diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-05 20:03:04 -0500 |
---|---|---|
committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2013-03-12 10:29:24 -0400 |
commit | 181b6bb0f5f122741262edc7ac0eca86d3f6dd73 (patch) | |
tree | 1b6e7ab6293bb67b6d01bb939217286ac8cd105c | |
parent | 033356ad3a0a719d52104e63c491d3c33f650ec3 (diff) |
EDF schedulers: Support early job releasing.
This patch allows a task to request early releasing
via rt_task parameters to sys_set_task_rt_param().
Note that early releasing can easily peg your CPUs
since early-releasing tasks never suspend to wait for
their next job. As such, early releasing is really
only useful in the context of implementing bandwidth
servers, interrupt handling threads (or any thread that
spends most of its time waiting for an event), or
short-lived computations. If early releasing pegs your
CPUs, then you probably shouldn't be using it.
-rw-r--r-- | include/litmus/litmus.h | 6 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 19 | ||||
-rw-r--r-- | litmus/Kconfig | 21 | ||||
-rw-r--r-- | litmus/sched_cedf.c | 4 | ||||
-rw-r--r-- | litmus/sched_gsn_edf.c | 4 | ||||
-rw-r--r-- | litmus/sched_psn_edf.c | 2 |
6 files changed, 50 insertions, 6 deletions
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index 875783e6a67b..81f6a499570b 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -63,6 +63,12 @@ void litmus_exit_task(struct task_struct *tsk); | |||
63 | #define get_release(t) (tsk_rt(t)->job_params.release) | 63 | #define get_release(t) (tsk_rt(t)->job_params.release) |
64 | #define get_lateness(t) (tsk_rt(t)->job_params.lateness) | 64 | #define get_lateness(t) (tsk_rt(t)->job_params.lateness) |
65 | 65 | ||
66 | #ifdef CONFIG_ALLOW_EARLY_RELEASE | ||
67 | #define wants_early_release(t) (tsk_rt(t)->task_params.release_policy == EARLY) | ||
68 | #else | ||
69 | #define wants_early_release(t) (0) | ||
70 | #endif | ||
71 | |||
66 | #define is_hrt(t) \ | 72 | #define is_hrt(t) \ |
67 | (tsk_rt(t)->task_params.cls == RT_CLASS_HARD) | 73 | (tsk_rt(t)->task_params.cls == RT_CLASS_HARD) |
68 | #define is_srt(t) \ | 74 | #define is_srt(t) \ |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index 5487bdb11380..4167508d9862 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -33,6 +33,22 @@ typedef enum { | |||
33 | PRECISE_ENFORCEMENT /* budgets are enforced with hrtimers */ | 33 | PRECISE_ENFORCEMENT /* budgets are enforced with hrtimers */ |
34 | } budget_policy_t; | 34 | } budget_policy_t; |
35 | 35 | ||
36 | typedef enum { | ||
37 | /* Jobs are released periodically (provided job precedence | ||
38 | constraints are met). */ | ||
39 | PERIODIC, | ||
40 | |||
41 | /* Jobs are released sporadically (provided job precedence | ||
42 | constraints are met). NOTE: Litmus currently does not | ||
43 | distinguish between periodic and sporadic tasks. */ | ||
44 | SPORADIC = PERIODIC, | ||
45 | |||
46 | /* Jobs are released immediatly after meeting precedence | ||
47 | constraints. Beware this can peg your CPUs if used in | ||
48 | the wrong applications. */ | ||
49 | EARLY | ||
50 | } release_policy_t; | ||
51 | |||
36 | /* We use the common priority interpretation "lower index == higher priority", | 52 | /* We use the common priority interpretation "lower index == higher priority", |
37 | * which is commonly used in fixed-priority schedulability analysis papers. | 53 | * which is commonly used in fixed-priority schedulability analysis papers. |
38 | * So, a numerically lower priority value implies higher scheduling priority, | 54 | * So, a numerically lower priority value implies higher scheduling priority, |
@@ -61,7 +77,8 @@ struct rt_task { | |||
61 | unsigned int cpu; | 77 | unsigned int cpu; |
62 | unsigned int priority; | 78 | unsigned int priority; |
63 | task_class_t cls; | 79 | task_class_t cls; |
64 | budget_policy_t budget_policy; /* ignored by pfair */ | 80 | budget_policy_t budget_policy; /* ignored by pfair */ |
81 | release_policy_t release_policy; /* ignored by non-edf */ | ||
65 | }; | 82 | }; |
66 | 83 | ||
67 | union np_flag { | 84 | union np_flag { |
diff --git a/litmus/Kconfig b/litmus/Kconfig index bd6635c8de08..795fbe1a769e 100644 --- a/litmus/Kconfig +++ b/litmus/Kconfig | |||
@@ -79,6 +79,27 @@ config SCHED_CPU_AFFINITY | |||
79 | 79 | ||
80 | Say Yes if unsure. | 80 | Say Yes if unsure. |
81 | 81 | ||
82 | config ALLOW_EARLY_RELEASE | ||
83 | bool "Allow Early Releasing" | ||
84 | default y | ||
85 | help | ||
86 | Allow tasks to release jobs early (while still maintaining job | ||
87 | precedence constraints). Only supported by EDF schedulers. Early | ||
88 | releasing must be explicitly requested by real-time tasks via | ||
89 | the task_params passed to sys_set_task_rt_param(). | ||
90 | |||
91 | Early releasing can improve job response times while maintaining | ||
92 | real-time correctness. However, it can easily peg your CPUs | ||
93 | since tasks never suspend to wait for their next job. As such, early | ||
94 | releasing is really only useful in the context of implementing | ||
95 | bandwidth servers, interrupt handling threads, or short-lived | ||
96 | computations. | ||
97 | |||
98 | Beware that early releasing may affect real-time analysis | ||
99 | if using locking protocols or I/O. | ||
100 | |||
101 | Say Yes if unsure. | ||
102 | |||
82 | choice | 103 | choice |
83 | prompt "EDF Tie-Break Behavior" | 104 | prompt "EDF Tie-Break Behavior" |
84 | default EDF_TIE_BREAK_LATENESS_NORM | 105 | default EDF_TIE_BREAK_LATENESS_NORM |
diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c index 4c2b150fa22d..ba3ed4525421 100644 --- a/litmus/sched_cedf.c +++ b/litmus/sched_cedf.c | |||
@@ -254,7 +254,7 @@ static noinline void requeue(struct task_struct* task) | |||
254 | /* sanity check before insertion */ | 254 | /* sanity check before insertion */ |
255 | BUG_ON(is_queued(task)); | 255 | BUG_ON(is_queued(task)); |
256 | 256 | ||
257 | if (is_released(task, litmus_clock())) | 257 | if (wants_early_release(task) || is_released(task, litmus_clock())) |
258 | __add_ready(&cluster->domain, task); | 258 | __add_ready(&cluster->domain, task); |
259 | else { | 259 | else { |
260 | /* it has got to wait */ | 260 | /* it has got to wait */ |
@@ -353,7 +353,7 @@ static noinline void job_completion(struct task_struct *t, int forced) | |||
353 | tsk_rt(t)->completed = 1; | 353 | tsk_rt(t)->completed = 1; |
354 | /* prepare for next period */ | 354 | /* prepare for next period */ |
355 | prepare_for_next_period(t); | 355 | prepare_for_next_period(t); |
356 | if (is_released(t, litmus_clock())) | 356 | if (wants_early_release(t) || is_released(t, litmus_clock())) |
357 | sched_trace_task_release(t); | 357 | sched_trace_task_release(t); |
358 | /* unlink */ | 358 | /* unlink */ |
359 | unlink(t); | 359 | unlink(t); |
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index 8fdc8f68fcfb..ac5c4d836018 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -251,7 +251,7 @@ static noinline void requeue(struct task_struct* task) | |||
251 | /* sanity check before insertion */ | 251 | /* sanity check before insertion */ |
252 | BUG_ON(is_queued(task)); | 252 | BUG_ON(is_queued(task)); |
253 | 253 | ||
254 | if (is_released(task, litmus_clock())) | 254 | if (wants_early_release(task) || is_released(task, litmus_clock())) |
255 | __add_ready(&gsnedf, task); | 255 | __add_ready(&gsnedf, task); |
256 | else { | 256 | else { |
257 | /* it has got to wait */ | 257 | /* it has got to wait */ |
@@ -344,7 +344,7 @@ static noinline void job_completion(struct task_struct *t, int forced) | |||
344 | tsk_rt(t)->completed = 1; | 344 | tsk_rt(t)->completed = 1; |
345 | /* prepare for next period */ | 345 | /* prepare for next period */ |
346 | prepare_for_next_period(t); | 346 | prepare_for_next_period(t); |
347 | if (is_released(t, litmus_clock())) | 347 | if (wants_early_release(t) || is_released(t, litmus_clock())) |
348 | sched_trace_task_release(t); | 348 | sched_trace_task_release(t); |
349 | /* unlink */ | 349 | /* unlink */ |
350 | unlink(t); | 350 | unlink(t); |
diff --git a/litmus/sched_psn_edf.c b/litmus/sched_psn_edf.c index c158f3532ba6..316333460dd9 100644 --- a/litmus/sched_psn_edf.c +++ b/litmus/sched_psn_edf.c | |||
@@ -61,7 +61,7 @@ static void requeue(struct task_struct* t, rt_domain_t *edf) | |||
61 | TRACE_TASK(t, "requeue: !TASK_RUNNING\n"); | 61 | TRACE_TASK(t, "requeue: !TASK_RUNNING\n"); |
62 | 62 | ||
63 | tsk_rt(t)->completed = 0; | 63 | tsk_rt(t)->completed = 0; |
64 | if (is_released(t, litmus_clock())) | 64 | if (wants_early_release(t) || is_released(t, litmus_clock())) |
65 | __add_ready(edf, t); | 65 | __add_ready(edf, t); |
66 | else | 66 | else |
67 | add_release(edf, t); /* it has got to wait */ | 67 | add_release(edf, t); /* it has got to wait */ |