diff options
Diffstat (limited to 'litmus/edf_common.c')
-rw-r--r-- | litmus/edf_common.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/litmus/edf_common.c b/litmus/edf_common.c new file mode 100644 index 000000000000..5aca2934a7b5 --- /dev/null +++ b/litmus/edf_common.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * kernel/edf_common.c | ||
3 | * | ||
4 | * Common functions for EDF based scheduler. | ||
5 | */ | ||
6 | |||
7 | #include <linux/percpu.h> | ||
8 | #include <linux/sched.h> | ||
9 | #include <linux/list.h> | ||
10 | |||
11 | #include <litmus/litmus.h> | ||
12 | #include <litmus/sched_plugin.h> | ||
13 | #include <litmus/sched_trace.h> | ||
14 | |||
15 | #include <litmus/edf_common.h> | ||
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 | |||
43 | /* edf_higher_prio - returns true if first has a higher EDF priority | ||
44 | * than second. Deadline ties are broken by PID. | ||
45 | * | ||
46 | * both first and second may be NULL | ||
47 | */ | ||
48 | int edf_higher_prio(struct task_struct* first, | ||
49 | struct task_struct* second) | ||
50 | { | ||
51 | struct task_struct *first_task = first; | ||
52 | struct task_struct *second_task = second; | ||
53 | |||
54 | /* There is no point in comparing a task to itself. */ | ||
55 | if (first && first == second) { | ||
56 | TRACE_TASK(first, | ||
57 | "WARNING: pointless edf priority comparison.\n"); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | |||
62 | /* check for NULL tasks */ | ||
63 | if (!first || !second) | ||
64 | return first && !second; | ||
65 | |||
66 | #ifdef CONFIG_LITMUS_LOCKING | ||
67 | |||
68 | /* Check for inherited priorities. Change task | ||
69 | * used for comparison in such a case. | ||
70 | */ | ||
71 | if (unlikely(first->rt_param.inh_task)) | ||
72 | first_task = first->rt_param.inh_task; | ||
73 | if (unlikely(second->rt_param.inh_task)) | ||
74 | second_task = second->rt_param.inh_task; | ||
75 | |||
76 | /* Check for priority boosting. Tie-break by start of boosting. | ||
77 | */ | ||
78 | if (unlikely(is_priority_boosted(first_task))) { | ||
79 | /* first_task is boosted, how about second_task? */ | ||
80 | if (!is_priority_boosted(second_task) || | ||
81 | lt_before(get_boost_start(first_task), | ||
82 | get_boost_start(second_task))) | ||
83 | return 1; | ||
84 | else | ||
85 | return 0; | ||
86 | } else if (unlikely(is_priority_boosted(second_task))) | ||
87 | /* second_task is boosted, first is not*/ | ||
88 | return 0; | ||
89 | |||
90 | #endif | ||
91 | |||
92 | if (earlier_deadline(first_task, second_task)) { | ||
93 | return 1; | ||
94 | } | ||
95 | else if (get_deadline(first_task) == get_deadline(second_task)) { | ||
96 | /* Need to tie break. All methods must set pid_break to 0/1 if | ||
97 | * first_task does not have priority over second_task. | ||
98 | */ | ||
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)) { | ||
109 | return 1; | ||
110 | } | ||
111 | pid_break = (get_lateness(first_task) == get_lateness(second_task)); | ||
112 | |||
113 | |||
114 | #elif defined(CONFIG_EDF_TIE_BREAK_LATENESS_NORM) | ||
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) { | ||
154 | return 1; | ||
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->rt_param.inh_task) { | ||
161 | return 1; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | return 0; /* fall-through. prio(second_task) > prio(first_task) */ | ||
167 | } | ||
168 | |||
169 | int edf_ready_order(struct bheap_node* a, struct bheap_node* b) | ||
170 | { | ||
171 | return edf_higher_prio(bheap2task(a), bheap2task(b)); | ||
172 | } | ||
173 | |||
174 | void edf_domain_init(rt_domain_t* rt, check_resched_needed_t resched, | ||
175 | release_jobs_t release) | ||
176 | { | ||
177 | rt_domain_init(rt, edf_ready_order, resched, release); | ||
178 | } | ||
179 | |||
180 | /* need_to_preempt - check whether the task t needs to be preempted | ||
181 | * call only with irqs disabled and with ready_lock acquired | ||
182 | * THIS DOES NOT TAKE NON-PREEMPTIVE SECTIONS INTO ACCOUNT! | ||
183 | */ | ||
184 | int edf_preemption_needed(rt_domain_t* rt, struct task_struct *t) | ||
185 | { | ||
186 | /* we need the read lock for edf_ready_queue */ | ||
187 | /* no need to preempt if there is nothing pending */ | ||
188 | if (!__jobs_pending(rt)) | ||
189 | return 0; | ||
190 | /* we need to reschedule if t doesn't exist */ | ||
191 | if (!t) | ||
192 | return 1; | ||
193 | |||
194 | /* NOTE: We cannot check for non-preemptibility since we | ||
195 | * don't know what address space we're currently in. | ||
196 | */ | ||
197 | |||
198 | /* make sure to get non-rt stuff out of the way */ | ||
199 | return !is_realtime(t) || edf_higher_prio(__next_ready(rt), t); | ||
200 | } | ||