diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-17 17:23:36 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-17 17:23:36 -0400 |
commit | 469aaad39c956446b8a31d351ee36bedd87ac18a (patch) | |
tree | 3e2864a01df8a04ab7a406342627d3dc850760af /include | |
parent | 9374a7c30b6906d01c548833fb8a7b65ba4b5ccc (diff) |
Per-task budget high-resolution timers (hrtimers).
As a step towards implementing more complex budget tracking
method (ex. BWI, VXR, etc.), we need per-task budget trackers
because we may be required to drain budget from a task, even
while it is suspended or blocked.
This patch does:
1) Replaces the per-CPU hrtimers with per-task hrtimers.
2) Plugin architecture for different budget policies.
This patch creates three budget draining policies:
SIMPLE, SAWARE (suspension-aware), and SOBLIV (suspension-oblivious).
However, only SIMPLE is supported by this patch.
SIMPLE (default):
Budget drains while the task is scheduled. Budget is preserved
across self-suspensions (but not job completions, of course).
Only SIMPLE is supported in this patch. (Maintaining current Litmus
functionality.)
SAWARE:
Draining according to suspension-aware analysis. Budget should drain
whenever a task is among the top-m tasks in its cluster, where
m is the number of processors in said cluster. This draining should
happen whether or not the task is actually scheduled.
SOBLIV:
Draining according to suspension-oblivious analysis. Budget should
drain whenever the task is scheduled or suspended (but not due to
preemption). Exception: Draining should halt when we can prove that
the task is not among the top-m tasks blocked on the same lock (i.e.,
on the PQ in the OMLP-family locking protocols).
Diffstat (limited to 'include')
-rw-r--r-- | include/litmus/budget.h | 106 | ||||
-rw-r--r-- | include/litmus/fdso.h | 2 | ||||
-rw-r--r-- | include/litmus/gpu_affinity.h | 8 | ||||
-rw-r--r-- | include/litmus/litmus.h | 2 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 26 | ||||
-rw-r--r-- | include/litmus/sched_plugin.h | 1 |
6 files changed, 106 insertions, 39 deletions
diff --git a/include/litmus/budget.h b/include/litmus/budget.h index 763b31c0e9f6..2a3511245f7a 100644 --- a/include/litmus/budget.h +++ b/include/litmus/budget.h | |||
@@ -1,26 +1,14 @@ | |||
1 | #ifndef _LITMUS_BUDGET_H_ | 1 | #ifndef _LITMUS_BUDGET_H_ |
2 | #define _LITMUS_BUDGET_H_ | 2 | #define _LITMUS_BUDGET_H_ |
3 | 3 | ||
4 | /* Update the per-processor enforcement timer (arm/reproram/cancel) for | 4 | #include <linux/hrtimer.h> |
5 | * the next task. */ | 5 | #include <linux/semaphore.h> |
6 | void update_enforcement_timer(struct task_struct* t); | ||
7 | 6 | ||
8 | /* Send SIG_BUDGET to a real-time task. */ | 7 | #define budget_exhausted(t) \ |
9 | void send_sigbudget(struct task_struct* t); | 8 | (get_exec_time(t) >= get_exec_cost(t)) |
10 | 9 | ||
11 | inline static int budget_exhausted(struct task_struct* t) | 10 | #define budget_remaining(t) \ |
12 | { | 11 | ((!budget_exhausted(t)) ? (get_exec_cost(t) - get_exec_time(t)) : 0) |
13 | return get_exec_time(t) >= get_exec_cost(t); | ||
14 | } | ||
15 | |||
16 | inline static lt_t budget_remaining(struct task_struct* t) | ||
17 | { | ||
18 | if (!budget_exhausted(t)) | ||
19 | return get_exec_cost(t) - get_exec_time(t); | ||
20 | else | ||
21 | /* avoid overflow */ | ||
22 | return 0; | ||
23 | } | ||
24 | 12 | ||
25 | #define budget_enforced(t) (\ | 13 | #define budget_enforced(t) (\ |
26 | tsk_rt(t)->task_params.budget_policy != NO_ENFORCEMENT) | 14 | tsk_rt(t)->task_params.budget_policy != NO_ENFORCEMENT) |
@@ -29,21 +17,87 @@ inline static lt_t budget_remaining(struct task_struct* t) | |||
29 | tsk_rt(t)->task_params.budget_policy == PRECISE_ENFORCEMENT || \ | 17 | tsk_rt(t)->task_params.budget_policy == PRECISE_ENFORCEMENT || \ |
30 | tsk_rt(t)->task_params.budget_signal_policy == PRECISE_SIGNALS) | 18 | tsk_rt(t)->task_params.budget_signal_policy == PRECISE_SIGNALS) |
31 | 19 | ||
20 | #define budget_quantum_tracked(t) (\ | ||
21 | tsk_rt(t)->task_params.budget_policy == QUANTUM_ENFORCEMENT || \ | ||
22 | tsk_rt(t)->task_params.budget_signal_policy == QUANTUM_SIGNALS) | ||
23 | |||
32 | #define budget_signalled(t) (\ | 24 | #define budget_signalled(t) (\ |
33 | tsk_rt(t)->task_params.budget_signal_policy != NO_SIGNALS) | 25 | tsk_rt(t)->task_params.budget_signal_policy != NO_SIGNALS) |
34 | 26 | ||
35 | #define budget_precisely_signalled(t) (\ | 27 | #define budget_precisely_signalled(t) (\ |
36 | tsk_rt(t)->task_params.budget_policy == PRECISE_SIGNALS) | 28 | tsk_rt(t)->task_params.budget_policy == PRECISE_SIGNALS) |
37 | 29 | ||
38 | #define sigbudget_sent(t) (\ | 30 | #define bt_flag_is_set(t, flag_nr) (\ |
39 | test_bit(RT_JOB_SIG_BUDGET_SENT, &tsk_rt(t)->job_params.flags)) | 31 | test_bit(flag_nr, &tsk_rt(t)->budget.flags)) |
32 | |||
33 | #define bt_flag_test_and_set(t, flag_nr) (\ | ||
34 | test_and_set_bit(flag_nr, &tsk_rt(t)->budget.flags)) | ||
35 | |||
36 | #define bt_flag_set(t, flag_nr) (\ | ||
37 | set_bit(flag_nr, &tsk_rt(t)->budget.flags)) | ||
38 | |||
39 | #define bt_flag_clear(t, flag_nr) (\ | ||
40 | clear_bit(flag_nr, &tsk_rt(t)->budget.flags)) | ||
41 | |||
42 | #define bt_flags_reset(t) (\ | ||
43 | tsk_rt(t)->budget.flags = 0) | ||
44 | |||
45 | #define requeue_preempted_job(t) \ | ||
46 | (t && (!budget_exhausted(t) || !budget_enforced(t))) | ||
47 | |||
48 | struct enforcement_timer | ||
49 | { | ||
50 | raw_spinlock_t lock; | ||
51 | struct hrtimer timer; | ||
52 | int armed:1; | ||
53 | }; | ||
54 | |||
55 | typedef void (*scheduled_t)(struct task_struct* t); | ||
56 | typedef void (*blocked_t)(struct task_struct* t); | ||
57 | typedef void (*preempt_or_sleep_t)(struct task_struct* t); | ||
58 | typedef void (*exhausted_t)(struct task_struct* t); | ||
59 | typedef void (*exit_t)(struct task_struct* t); | ||
40 | 60 | ||
41 | static inline int requeue_preempted_job(struct task_struct* t) | 61 | struct budget_tracker_ops |
42 | { | 62 | { |
43 | /* Add task to ready queue only if not subject to budget enforcement or | 63 | scheduled_t on_scheduled; /* called from litmus_schedule(). */ |
44 | * if the job has budget remaining. t may be NULL. | 64 | blocked_t on_blocked; /* called from plugin::schedule() */ |
45 | */ | 65 | preempt_or_sleep_t on_preempt_or_sleep; /* called from plugin::schedule() */ |
46 | return t && (!budget_exhausted(t) || !budget_enforced(t)); | 66 | |
47 | } | 67 | exit_t on_exit; /* task exiting rt mode */ |
68 | |||
69 | exhausted_t on_exhausted; /* called by plugin::tick() or timer interrupt */ | ||
70 | }; | ||
71 | |||
72 | struct budget_tracker | ||
73 | { | ||
74 | struct enforcement_timer timer; | ||
75 | const struct budget_tracker_ops* ops; | ||
76 | unsigned long flags; | ||
77 | }; | ||
78 | |||
79 | /* budget tracker flags */ | ||
80 | enum BT_FLAGS | ||
81 | { | ||
82 | BTF_BUDGET_EXHAUSTED = 0, | ||
83 | BTF_SIG_BUDGET_SENT = 1, | ||
84 | }; | ||
85 | |||
86 | /* Functions for simple DRAIN_SIMPLE policy common | ||
87 | * to every scheduler. Scheduler must provided | ||
88 | * implementation for simple_on_exhausted(). | ||
89 | */ | ||
90 | void simple_on_scheduled(struct task_struct* t); | ||
91 | void simple_on_blocked(struct task_struct* t); | ||
92 | void simple_on_preempt_or_sleep(struct task_struct* t); | ||
93 | void simple_on_exit(struct task_struct* t); | ||
94 | |||
95 | |||
96 | void init_budget_tracker(struct budget_tracker* bt, | ||
97 | const struct budget_tracker_ops* ops); | ||
98 | |||
99 | |||
100 | /* Send SIG_BUDGET to a real-time task. */ | ||
101 | void send_sigbudget(struct task_struct* t); | ||
48 | 102 | ||
49 | #endif | 103 | #endif |
diff --git a/include/litmus/fdso.h b/include/litmus/fdso.h index f7887288d8f5..2d8e6c43d908 100644 --- a/include/litmus/fdso.h +++ b/include/litmus/fdso.h | |||
@@ -36,7 +36,7 @@ typedef enum { | |||
36 | KFMLP_GPU_AFF_OBS = 12, | 36 | KFMLP_GPU_AFF_OBS = 12, |
37 | 37 | ||
38 | PRIOQ_MUTEX = 13, | 38 | PRIOQ_MUTEX = 13, |
39 | 39 | ||
40 | MAX_OBJ_TYPE = 13 | 40 | MAX_OBJ_TYPE = 13 |
41 | } obj_type_t; | 41 | } obj_type_t; |
42 | 42 | ||
diff --git a/include/litmus/gpu_affinity.h b/include/litmus/gpu_affinity.h index 47da725717b0..f610f58b1f3b 100644 --- a/include/litmus/gpu_affinity.h +++ b/include/litmus/gpu_affinity.h | |||
@@ -11,6 +11,7 @@ gpu_migration_dist_t gpu_migration_distance(int a, int b); | |||
11 | static inline void reset_gpu_tracker(struct task_struct* t) | 11 | static inline void reset_gpu_tracker(struct task_struct* t) |
12 | { | 12 | { |
13 | t->rt_param.accum_gpu_time = 0; | 13 | t->rt_param.accum_gpu_time = 0; |
14 | t->rt_param.gpu_time_stamp = 0; | ||
14 | } | 15 | } |
15 | 16 | ||
16 | static inline void start_gpu_tracker(struct task_struct* t) | 17 | static inline void start_gpu_tracker(struct task_struct* t) |
@@ -22,11 +23,16 @@ static inline void stop_gpu_tracker(struct task_struct* t) | |||
22 | { | 23 | { |
23 | lt_t now = litmus_clock(); | 24 | lt_t now = litmus_clock(); |
24 | t->rt_param.accum_gpu_time += (now - t->rt_param.gpu_time_stamp); | 25 | t->rt_param.accum_gpu_time += (now - t->rt_param.gpu_time_stamp); |
26 | t->rt_param.gpu_time_stamp = 0; | ||
25 | } | 27 | } |
26 | 28 | ||
27 | static inline lt_t get_gpu_time(struct task_struct* t) | 29 | static inline lt_t get_gpu_time(struct task_struct* t) |
28 | { | 30 | { |
29 | return t->rt_param.accum_gpu_time; | 31 | lt_t accum = t->rt_param.accum_gpu_time; |
32 | if (t->rt_param.gpu_time_stamp != 0) { | ||
33 | accum += (litmus_clock() - t->rt_param.gpu_time_stamp); | ||
34 | } | ||
35 | return accum; | ||
30 | } | 36 | } |
31 | 37 | ||
32 | static inline lt_t get_gpu_estimate(struct task_struct* t, gpu_migration_dist_t dist) | 38 | static inline lt_t get_gpu_estimate(struct task_struct* t, gpu_migration_dist_t dist) |
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index 70b421d59d34..f6ea5f6e80ee 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -62,6 +62,7 @@ void litmus_exit_task(struct task_struct *tsk); | |||
62 | #define get_priority(t) (tsk_rt(t)->task_params.priority) | 62 | #define get_priority(t) (tsk_rt(t)->task_params.priority) |
63 | #define get_class(t) (tsk_rt(t)->task_params.cls) | 63 | #define get_class(t) (tsk_rt(t)->task_params.cls) |
64 | #define get_release_policy(t) (tsk_rt(t)->task_params.release_policy) | 64 | #define get_release_policy(t) (tsk_rt(t)->task_params.release_policy) |
65 | #define get_drain_policy(t) (tsk_rt(t)->task_params.drain_policy) | ||
65 | 66 | ||
66 | /* job_param macros */ | 67 | /* job_param macros */ |
67 | #define get_exec_time(t) (tsk_rt(t)->job_params.exec_time) | 68 | #define get_exec_time(t) (tsk_rt(t)->job_params.exec_time) |
@@ -69,6 +70,7 @@ void litmus_exit_task(struct task_struct *tsk); | |||
69 | #define get_period(t) (tsk_rt(t)->task_params.period) | 70 | #define get_period(t) (tsk_rt(t)->task_params.period) |
70 | #define get_release(t) (tsk_rt(t)->job_params.release) | 71 | #define get_release(t) (tsk_rt(t)->job_params.release) |
71 | #define get_lateness(t) (tsk_rt(t)->job_params.lateness) | 72 | #define get_lateness(t) (tsk_rt(t)->job_params.lateness) |
73 | #define get_budget_timer(t) (tsk_rt(t)->job_params.budget_timer) | ||
72 | 74 | ||
73 | #define effective_priority(t) ((!(tsk_rt(t)->inh_task)) ? t : tsk_rt(t)->inh_task) | 75 | #define effective_priority(t) ((!(tsk_rt(t)->inh_task)) ? t : tsk_rt(t)->inh_task) |
74 | #define base_priority(t) (t) | 76 | #define base_priority(t) (t) |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index bf0ee8dbae6e..887075b908ca 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -36,6 +36,14 @@ typedef enum { | |||
36 | } budget_policy_t; | 36 | } budget_policy_t; |
37 | 37 | ||
38 | typedef enum { | 38 | typedef enum { |
39 | /* all drain mechanisms are ignored if budget enforcement or signalling | ||
40 | is not in use. */ | ||
41 | DRAIN_SIMPLE, /* drains while task is linked */ | ||
42 | DRAIN_SAWARE, /* drains according to suspension-aware analysis */ | ||
43 | DRAIN_SOBLIV, /* drains according to suspension-obliv analysis */ | ||
44 | } budget_drain_policy_t; | ||
45 | |||
46 | typedef enum { | ||
39 | NO_SIGNALS, /* job receives no signals when it exhausts its budget */ | 47 | NO_SIGNALS, /* job receives no signals when it exhausts its budget */ |
40 | QUANTUM_SIGNALS, /* budget signals are only sent on quantum boundaries */ | 48 | QUANTUM_SIGNALS, /* budget signals are only sent on quantum boundaries */ |
41 | PRECISE_SIGNALS, /* budget signals are triggered with hrtimers */ | 49 | PRECISE_SIGNALS, /* budget signals are triggered with hrtimers */ |
@@ -132,6 +140,7 @@ struct rt_task { | |||
132 | unsigned int priority; | 140 | unsigned int priority; |
133 | task_class_t cls; | 141 | task_class_t cls; |
134 | budget_policy_t budget_policy; /* ignored by pfair */ | 142 | budget_policy_t budget_policy; /* ignored by pfair */ |
143 | budget_drain_policy_t drain_policy; | ||
135 | budget_signal_policy_t budget_signal_policy; /* currently ignored by pfair */ | 144 | budget_signal_policy_t budget_signal_policy; /* currently ignored by pfair */ |
136 | release_policy_t release_policy; | 145 | release_policy_t release_policy; |
137 | }; | 146 | }; |
@@ -213,8 +222,9 @@ struct control_page { | |||
213 | /* don't export internal data structures to user space (liblitmus) */ | 222 | /* don't export internal data structures to user space (liblitmus) */ |
214 | #ifdef __KERNEL__ | 223 | #ifdef __KERNEL__ |
215 | 224 | ||
216 | #include <litmus/binheap.h> | ||
217 | #include <linux/semaphore.h> | 225 | #include <linux/semaphore.h> |
226 | #include <litmus/budget.h> | ||
227 | #include <litmus/binheap.h> | ||
218 | 228 | ||
219 | #ifdef CONFIG_LITMUS_SOFTIRQD | 229 | #ifdef CONFIG_LITMUS_SOFTIRQD |
220 | #include <linux/interrupt.h> | 230 | #include <linux/interrupt.h> |
@@ -247,15 +257,8 @@ struct rt_job { | |||
247 | * Increase this sequence number when a job is released. | 257 | * Increase this sequence number when a job is released. |
248 | */ | 258 | */ |
249 | unsigned int job_no; | 259 | unsigned int job_no; |
250 | |||
251 | /* bits: | ||
252 | * 0th: Set if a budget exhaustion signal has already been sent for | ||
253 | * the current job. */ | ||
254 | unsigned long flags; | ||
255 | }; | 260 | }; |
256 | 261 | ||
257 | #define RT_JOB_SIG_BUDGET_SENT 0 | ||
258 | |||
259 | struct pfair_param; | 262 | struct pfair_param; |
260 | 263 | ||
261 | enum klmirqd_sem_status | 264 | enum klmirqd_sem_status |
@@ -278,12 +281,12 @@ typedef enum gpu_migration_dist | |||
278 | MIG_LAST = MIG_NONE | 281 | MIG_LAST = MIG_NONE |
279 | } gpu_migration_dist_t; | 282 | } gpu_migration_dist_t; |
280 | 283 | ||
281 | typedef struct feedback_est{ | 284 | typedef struct feedback_est |
285 | { | ||
282 | fp_t est; | 286 | fp_t est; |
283 | fp_t accum_err; | 287 | fp_t accum_err; |
284 | } feedback_est_t; | 288 | } feedback_est_t; |
285 | 289 | ||
286 | |||
287 | #define AVG_EST_WINDOW_SIZE 20 | 290 | #define AVG_EST_WINDOW_SIZE 20 |
288 | 291 | ||
289 | typedef int (*notify_rsrc_exit_t)(struct task_struct* tsk); | 292 | typedef int (*notify_rsrc_exit_t)(struct task_struct* tsk); |
@@ -417,7 +420,6 @@ struct rt_param { | |||
417 | struct binheap_node aux_task_owner_node; | 420 | struct binheap_node aux_task_owner_node; |
418 | #endif | 421 | #endif |
419 | 422 | ||
420 | |||
421 | #ifdef CONFIG_NP_SECTION | 423 | #ifdef CONFIG_NP_SECTION |
422 | /* For the FMLP under PSN-EDF, it is required to make the task | 424 | /* For the FMLP under PSN-EDF, it is required to make the task |
423 | * non-preemptive from kernel space. In order not to interfere with | 425 | * non-preemptive from kernel space. In order not to interfere with |
@@ -427,6 +429,8 @@ struct rt_param { | |||
427 | unsigned int kernel_np; | 429 | unsigned int kernel_np; |
428 | #endif | 430 | #endif |
429 | 431 | ||
432 | struct budget_tracker budget; | ||
433 | |||
430 | /* This field can be used by plugins to store where the task | 434 | /* This field can be used by plugins to store where the task |
431 | * is currently scheduled. It is the responsibility of the | 435 | * is currently scheduled. It is the responsibility of the |
432 | * plugin to avoid race conditions. | 436 | * plugin to avoid race conditions. |
diff --git a/include/litmus/sched_plugin.h b/include/litmus/sched_plugin.h index 78cec30866ac..6e7d6df2fb78 100644 --- a/include/litmus/sched_plugin.h +++ b/include/litmus/sched_plugin.h | |||
@@ -130,6 +130,7 @@ struct sched_plugin { | |||
130 | schedule_t schedule; | 130 | schedule_t schedule; |
131 | finish_switch_t finish_switch; | 131 | finish_switch_t finish_switch; |
132 | 132 | ||
133 | |||
133 | /* syscall backend */ | 134 | /* syscall backend */ |
134 | complete_job_t complete_job; | 135 | complete_job_t complete_job; |
135 | release_at_t release_at; | 136 | release_at_t release_at; |