diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-09-10 13:30:24 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-09-10 13:30:24 -0400 |
commit | 893c8943ce5c5527f05ab7e9208d5a942d77d8b5 (patch) | |
tree | aa9e84b3503ff97c1d87bc9c2ce6682e51cfc971 /litmus/edf_common.c | |
parent | 901fdd9c22790039a76c1d3ee01828a2f124f6f3 (diff) | |
parent | d3c32e91e3fce2a57083a734efae6d9de06ec02f (diff) |
Merge branch 'prop/robust-tie-break' into wip-gpu-rtas12
Conflicts:
include/litmus/binheap.h
include/litmus/fdso.h
include/litmus/litmus.h
litmus/Makefile
litmus/binheap.c
litmus/edf_common.c
litmus/fdso.c
litmus/jobs.c
litmus/locking.c
Diffstat (limited to 'litmus/edf_common.c')
-rw-r--r-- | litmus/edf_common.c | 132 |
1 files changed, 94 insertions, 38 deletions
diff --git a/litmus/edf_common.c b/litmus/edf_common.c index b346bdd65b3b..a1cdc10ea6f1 100644 --- a/litmus/edf_common.c +++ b/litmus/edf_common.c | |||
@@ -18,6 +18,30 @@ | |||
18 | 18 | ||
19 | #include <litmus/edf_common.h> | 19 | #include <litmus/edf_common.h> |
20 | 20 | ||
21 | #ifdef CONFIG_EDF_TIE_BREAK_LATENESS_NORM | ||
22 | #include <litmus/fpmath.h> | ||
23 | #endif | ||
24 | |||
25 | #ifdef CONFIG_EDF_TIE_BREAK_HASH | ||
26 | #include <linux/hash.h> | ||
27 | static inline long edf_hash(struct task_struct *t) | ||
28 | { | ||
29 | /* pid is 32 bits, so normally we would shove that into the | ||
30 | * upper 32-bits and and put the job number in the bottom | ||
31 | * and hash the 64-bit number with hash_64(). Sadly, | ||
32 | * in testing, hash_64() doesn't distribute keys were the | ||
33 | * upper bits are close together (as would be the case with | ||
34 | * pids) and job numbers are equal (as would be the case with | ||
35 | * synchronous task sets with all relative deadlines equal). | ||
36 | * | ||
37 | * A 2006 Linux patch proposed the following solution | ||
38 | * (but for some reason it wasn't accepted...). | ||
39 | * | ||
40 | * At least this workaround works for 32-bit systems as well. | ||
41 | */ | ||
42 | return hash_32(hash_32((u32)tsk_rt(t)->job_params.job_no, 32) ^ t->pid, 32); | ||
43 | } | ||
44 | #endif | ||
21 | 45 | ||
22 | 46 | ||
23 | /* edf_higher_prio - returns true if first has a higher EDF priority | 47 | /* edf_higher_prio - returns true if first has a higher EDF priority |
@@ -88,58 +112,90 @@ int edf_higher_prio(struct task_struct* first, struct task_struct* second) | |||
88 | 112 | ||
89 | #endif | 113 | #endif |
90 | 114 | ||
91 | // // rate-monotonic for testing | ||
92 | // if (!is_realtime(second_task)) { | ||
93 | // return true; | ||
94 | // } | ||
95 | // | ||
96 | // if (shorter_period(first_task, second_task)) { | ||
97 | // return true; | ||
98 | // } | ||
99 | // | ||
100 | // if (get_period(first_task) == get_period(second_task)) { | ||
101 | // if (first_task->pid < second_task->pid) { | ||
102 | // return true; | ||
103 | // } | ||
104 | // else if (first_task->pid == second_task->pid) { | ||
105 | // return !second->rt_param.inh_task; | ||
106 | // } | ||
107 | // } | ||
108 | |||
109 | if (!is_realtime(second_task)) { | 115 | if (!is_realtime(second_task)) { |
110 | return true; | 116 | return 1; |
111 | } | 117 | } |
112 | 118 | else if (earlier_deadline(first_task, second_task)) { | |
113 | if (earlier_deadline(first_task, second_task)) { | 119 | return 1; |
114 | return true; | ||
115 | } | 120 | } |
116 | if (get_deadline(first_task) == get_deadline(second_task)) { | 121 | else if (get_deadline(first_task) == get_deadline(second_task)) { |
117 | 122 | /* Need to tie break. All methods must set pid_break to 0/1 if | |
118 | if (shorter_period(first_task, second_task)) { | 123 | * first_task does not have priority over second_task. |
119 | return true; | 124 | */ |
125 | int pid_break; | ||
126 | |||
127 | #if defined(CONFIG_EDF_TIE_BREAK_LATENESS) | ||
128 | /* Tie break by lateness. Jobs with greater lateness get | ||
129 | * priority. This should spread tardiness across all tasks, | ||
130 | * especially in task sets where all tasks have the same | ||
131 | * period and relative deadlines. | ||
132 | */ | ||
133 | if (get_lateness(first_task) > get_lateness(second_task)) { | ||
134 | return 1; | ||
135 | } | ||
136 | pid_break = (get_lateness(first_task) == get_lateness(second_task)); | ||
137 | |||
138 | |||
139 | #elif defined(CONFIG_EDF_TIE_BREAK_LATENESS_NORM) | ||
140 | /* Tie break by lateness, normalized by relative deadline. Jobs with | ||
141 | * greater normalized lateness get priority. | ||
142 | * | ||
143 | * Note: Considered using the algebraically equivalent | ||
144 | * lateness(first)*relative_deadline(second) > | ||
145 | lateness(second)*relative_deadline(first) | ||
146 | * to avoid fixed-point math, but values are prone to overflow if inputs | ||
147 | * are on the order of several seconds, even in 64-bit. | ||
148 | */ | ||
149 | fp_t fnorm = _frac(get_lateness(first_task), | ||
150 | get_rt_relative_deadline(first_task)); | ||
151 | fp_t snorm = _frac(get_lateness(second_task), | ||
152 | get_rt_relative_deadline(second_task)); | ||
153 | if (_gt(fnorm, snorm)) { | ||
154 | return 1; | ||
155 | } | ||
156 | pid_break = _eq(fnorm, snorm); | ||
157 | |||
158 | |||
159 | #elif defined(CONFIG_EDF_TIE_BREAK_HASH) | ||
160 | /* Tie break by comparing hashs of (pid, job#) tuple. There should be | ||
161 | * a 50% chance that first_task has a higher priority than second_task. | ||
162 | */ | ||
163 | long fhash = edf_hash(first_task); | ||
164 | long shash = edf_hash(second_task); | ||
165 | if (fhash < shash) { | ||
166 | return 1; | ||
120 | } | 167 | } |
121 | if (get_rt_period(first_task) == get_rt_period(second_task)) { | 168 | pid_break = (fhash == shash); |
169 | #else | ||
170 | |||
171 | |||
172 | /* CONFIG_EDF_PID_TIE_BREAK */ | ||
173 | pid_break = 1; // fall through to tie-break by pid; | ||
174 | #endif | ||
175 | |||
176 | /* Tie break by pid */ | ||
177 | if(pid_break) { | ||
122 | if (first_task->pid < second_task->pid) { | 178 | if (first_task->pid < second_task->pid) { |
123 | return true; | 179 | return 1; |
124 | } | 180 | } |
125 | if (first_task->pid == second_task->pid) { | 181 | else if (first_task->pid == second_task->pid) { |
126 | #ifdef CONFIG_LITMUS_SOFTIRQD | 182 | #ifdef CONFIG_LITMUS_SOFTIRQD |
127 | if (first_task->rt_param.is_proxy_thread < | 183 | if (first_task->rt_param.is_proxy_thread < |
128 | second_task->rt_param.is_proxy_thread) { | 184 | second_task->rt_param.is_proxy_thread) { |
129 | return true; | 185 | return 1; |
130 | } | ||
131 | if(first_task->rt_param.is_proxy_thread == second_task->rt_param.is_proxy_thread) { | ||
132 | return !second->rt_param.inh_task; | ||
133 | } | 186 | } |
134 | #else | ||
135 | return !second->rt_param.inh_task; | ||
136 | #endif | 187 | #endif |
188 | /* If the PIDs are the same then the task with the | ||
189 | * inherited priority wins. | ||
190 | */ | ||
191 | if (!second_task->rt_param.inh_task) { | ||
192 | return 1; | ||
193 | } | ||
137 | } | 194 | } |
138 | |||
139 | } | 195 | } |
140 | } | 196 | } |
141 | 197 | ||
142 | return false; | 198 | return 0; /* fall-through. prio(second_task) > prio(first_task) */ |
143 | } | 199 | } |
144 | 200 | ||
145 | 201 | ||