aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/edf_common.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-08-20 17:28:55 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2012-08-27 15:07:17 -0400
commit077aaecac31331b65442275843932314049a2ceb (patch)
tree6b24a59521a0f5e3853b7667669b54211b03b272 /litmus/edf_common.c
parent9a19f35c9c287cb8abd5bcf276ae8d1a3e876907 (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.c110
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>
23static 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) */