diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-08-20 17:28:55 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-08-27 15:07:17 -0400 |
commit | 077aaecac31331b65442275843932314049a2ceb (patch) | |
tree | 6b24a59521a0f5e3853b7667669b54211b03b272 /litmus/edf_common.c | |
parent | 9a19f35c9c287cb8abd5bcf276ae8d1a3e876907 (diff) |
EDF priority tie-breaks.wip-robust-tie-break
Instead of tie-breaking by PID (which is a static
priority tie-break), we can tie-break by other
job-level-unique parameters. This is desirable
because tasks are equaly affected by tardiness
since static priority tie-breaks cause tasks
with greater PID values to experience the most
tardiness.
There are four tie-break methods:
1) Lateness. If two jobs, J_{1,i} and J_{2,j} of
tasks T_1 and T_2, respectively, have equal
deadlines, we favor the job of the task that
had the worst lateness for jobs J_{1,i-1} and
J_{2,j-1}.
Note: Unlike tardiness, lateness may be less than
zero. This occurs when a job finishes before its
deadline.
2) Normalized Lateness. The same as #1, except
lateness is first normalized by each task's
relative deadline. This prevents tasks with short
relative deadlines and small execution requirements
from always losing tie-breaks.
3) Hash. The job tuple (PID, Job#) is used to
generate a hash. Hash values are then compared.
A job has ~50% chance of winning a tie-break
with respect to another job.
Note: Emperical testing shows that some jobs
can have +/- ~1.5% advantage in tie-breaks.
Linux's built-in hash function is not totally
a uniform hash.
4) PIDs. PID-based tie-break used in prior
versions of Litmus.
Conflicts:
litmus/edf_common.c
Diffstat (limited to 'litmus/edf_common.c')
-rw-r--r-- | litmus/edf_common.c | 110 |
1 files changed, 91 insertions, 19 deletions
diff --git a/litmus/edf_common.c b/litmus/edf_common.c index 668737f0fbf9..52205df3ea8b 100644 --- a/litmus/edf_common.c +++ b/litmus/edf_common.c | |||
@@ -14,6 +14,32 @@ | |||
14 | 14 | ||
15 | #include <litmus/edf_common.h> | 15 | #include <litmus/edf_common.h> |
16 | 16 | ||
17 | #ifdef CONFIG_EDF_TIE_BREAK_LATENESS_NORM | ||
18 | #include <litmus/fpmath.h> | ||
19 | #endif | ||
20 | |||
21 | #ifdef CONFIG_EDF_TIE_BREAK_HASH | ||
22 | #include <linux/hash.h> | ||
23 | static inline long edf_hash(struct task_struct *t) | ||
24 | { | ||
25 | /* pid is 32 bits, so normally we would shove that into the | ||
26 | * upper 32-bits and and put the job number in the bottom | ||
27 | * and hash the 64-bit number with hash_64(). Sadly, | ||
28 | * in testing, hash_64() doesn't distribute keys were the | ||
29 | * upper bits are close together (as would be the case with | ||
30 | * pids) and job numbers are equal (as would be the case with | ||
31 | * synchronous task sets with all relative deadlines equal). | ||
32 | * | ||
33 | * A 2006 Linux patch proposed the following solution | ||
34 | * (but for some reason it wasn't accepted...). | ||
35 | * | ||
36 | * At least this workaround works for 32-bit systems as well. | ||
37 | */ | ||
38 | return hash_32(hash_32((u32)tsk_rt(t)->job_params.job_no, 32) ^ t->pid, 32); | ||
39 | } | ||
40 | #endif | ||
41 | |||
42 | |||
17 | /* edf_higher_prio - returns true if first has a higher EDF priority | 43 | /* edf_higher_prio - returns true if first has a higher EDF priority |
18 | * than second. Deadline ties are broken by PID. | 44 | * than second. Deadline ties are broken by PID. |
19 | * | 45 | * |
@@ -63,32 +89,78 @@ int edf_higher_prio(struct task_struct* first, | |||
63 | 89 | ||
64 | #endif | 90 | #endif |
65 | 91 | ||
66 | /* Determine the task with earliest deadline, with | 92 | if (earlier_deadline(first_task, second_task)) { |
67 | * tie-break logic. | ||
68 | */ | ||
69 | if (unlikely(!is_realtime(second_task))) { | ||
70 | return 1; | ||
71 | } | ||
72 | else if (earlier_deadline(first_task, second_task)) { | ||
73 | /* Is the deadline of the first task earlier? | ||
74 | * Then it has higher priority. | ||
75 | */ | ||
76 | return 1; | 93 | return 1; |
77 | } | 94 | } |
78 | else if (get_deadline(first_task) == get_deadline(second_task)) { | 95 | else if (get_deadline(first_task) == get_deadline(second_task)) { |
79 | /* Need to tie break */ | 96 | /* Need to tie break. All methods must set pid_break to 0/1 if |
80 | 97 | * first_task does not have priority over second_task. | |
81 | /* Tie break by pid */ | 98 | */ |
82 | if (first_task->pid < second_task->pid) { | 99 | int pid_break; |
100 | |||
101 | |||
102 | #if defined(CONFIG_EDF_TIE_BREAK_LATENESS) | ||
103 | /* Tie break by lateness. Jobs with greater lateness get | ||
104 | * priority. This should spread tardiness across all tasks, | ||
105 | * especially in task sets where all tasks have the same | ||
106 | * period and relative deadlines. | ||
107 | */ | ||
108 | if (get_lateness(first_task) > get_lateness(second_task)) { | ||
83 | return 1; | 109 | return 1; |
84 | } | 110 | } |
85 | else if (first_task->pid == second_task->pid) { | 111 | pid_break = (get_lateness(first_task) == get_lateness(second_task)); |
86 | /* If the PIDs are the same then the task with the | 112 | |
87 | * inherited priority wins. | 113 | |
88 | */ | 114 | #elif defined(CONFIG_EDF_TIE_BREAK_LATENESS_NORM) |
89 | if (!second_task->rt_param.inh_task) { | 115 | /* Tie break by lateness, normalized by relative deadline. Jobs with |
116 | * greater normalized lateness get priority. | ||
117 | * | ||
118 | * Note: Considered using the algebraically equivalent | ||
119 | * lateness(first)*relative_deadline(second) > | ||
120 | lateness(second)*relative_deadline(first) | ||
121 | * to avoid fixed-point math, but values are prone to overflow if inputs | ||
122 | * are on the order of several seconds, even in 64-bit. | ||
123 | */ | ||
124 | fp_t fnorm = _frac(get_lateness(first_task), | ||
125 | get_rt_relative_deadline(first_task)); | ||
126 | fp_t snorm = _frac(get_lateness(second_task), | ||
127 | get_rt_relative_deadline(second_task)); | ||
128 | if (_gt(fnorm, snorm)) { | ||
129 | return 1; | ||
130 | } | ||
131 | pid_break = _eq(fnorm, snorm); | ||
132 | |||
133 | |||
134 | #elif defined(CONFIG_EDF_TIE_BREAK_HASH) | ||
135 | /* Tie break by comparing hashs of (pid, job#) tuple. There should be | ||
136 | * a 50% chance that first_task has a higher priority than second_task. | ||
137 | */ | ||
138 | long fhash = edf_hash(first_task); | ||
139 | long shash = edf_hash(second_task); | ||
140 | if (fhash < shash) { | ||
141 | return 1; | ||
142 | } | ||
143 | pid_break = (fhash == shash); | ||
144 | #else | ||
145 | |||
146 | |||
147 | /* CONFIG_EDF_PID_TIE_BREAK */ | ||
148 | pid_break = 1; // fall through to tie-break by pid; | ||
149 | #endif | ||
150 | |||
151 | /* Tie break by pid */ | ||
152 | if(pid_break) { | ||
153 | if (first_task->pid < second_task->pid) { | ||
90 | return 1; | 154 | return 1; |
91 | } | 155 | } |
156 | else if (first_task->pid == second_task->pid) { | ||
157 | /* If the PIDs are the same then the task with the | ||
158 | * inherited priority wins. | ||
159 | */ | ||
160 | if (!second_task->rt_param.inh_task) { | ||
161 | return 1; | ||
162 | } | ||
163 | } | ||
92 | } | 164 | } |
93 | } | 165 | } |
94 | return 0; /* fall-through. prio(second_task) > prio(first_task) */ | 166 | return 0; /* fall-through. prio(second_task) > prio(first_task) */ |