aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/sched_mc.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2011-09-27 14:47:26 -0400
committerJonathan Herman <hermanjl@cs.unc.edu>2011-09-27 14:47:26 -0400
commitf21e1d0ef90c2e88ae6a563afc31ea601ed968c7 (patch)
treed7a0cf75344c890c81fbd402f0da1764937eebc8 /litmus/sched_mc.c
parent2fe725ef2142dd6c1bbf72e8d1b0a6f7e885d7ed (diff)
Timer merging
Diffstat (limited to 'litmus/sched_mc.c')
-rw-r--r--litmus/sched_mc.c339
1 files changed, 214 insertions, 125 deletions
diff --git a/litmus/sched_mc.c b/litmus/sched_mc.c
index 577e7d36faf5..30898246ea38 100644
--- a/litmus/sched_mc.c
+++ b/litmus/sched_mc.c
@@ -22,6 +22,7 @@
22#include <litmus/sched_trace.h> 22#include <litmus/sched_trace.h>
23#include <litmus/domain.h> 23#include <litmus/domain.h>
24#include <litmus/bheap.h> 24#include <litmus/bheap.h>
25#include <litmus/event_group.h>
25 26
26#include <litmus/sched_mc.h> 27#include <litmus/sched_mc.h>
27 28
@@ -34,85 +35,84 @@
34 * @timer For ghost task budget enforcement 35 * @timer For ghost task budget enforcement
35 * @node Used to sort crit_entries by preemptability in global domains 36 * @node Used to sort crit_entries by preemptability in global domains
36 */ 37 */
37typedef struct { 38struct crit_entry {
38 enum crit_level level; 39 enum crit_level level;
39 struct task_struct* linked; 40 struct task_struct* linked;
40 domain_t* domain; 41 struct domain* domain;
41 int usable; 42 int usable;
43#ifdef CONFIG_MERGE_TIMERS
44 struct rt_event event;
45#else
42 struct hrtimer timer; 46 struct hrtimer timer;
47#endif
43 struct bheap_node* node; 48 struct bheap_node* node;
44 atomic_t dirty; 49};
45} crit_entry_t;
46 50
47/** 51/**
48 * cpu_entry_t - State of a CPU for the entire MC system 52 * struct cpu_entry - State of a CPU for the entire MC system
49 * @cpu CPU id 53 * @cpu CPU id
50 * @scheduled Task that is physically running 54 * @scheduled Task that is physically running
51 * @linked Task that should be running / is logically running 55 * @linked Task that should be running / is logically running
52 * @lock For serialization 56 * @lock For serialization
53 * @crit_entries Array of CPU state per criticality level 57 * @crit_entries Array of CPU state per criticality level
54 */ 58 */
55typedef struct { 59struct cpu_entry {
56 int cpu; 60 int cpu;
57 struct task_struct* scheduled; 61 struct task_struct* scheduled;
58 struct task_struct* linked; 62 struct task_struct* linked;
59 raw_spinlock_t lock; 63 raw_spinlock_t lock;
60 crit_entry_t crit_entries[NUM_CRIT_LEVELS]; 64 struct crit_entry crit_entries[NUM_CRIT_LEVELS];
61#ifdef CONFIG_PLUGIN_MC_REDIRECT 65#ifdef CONFIG_PLUGIN_MC_REDIRECT
62 struct list_head redir; 66 struct list_head redir;
63 raw_spinlock_t redir_lock; 67 raw_spinlock_t redir_lock;
64#endif 68#endif
65} cpu_entry_t; 69#ifdef CONFIG_MERGE_TIMERS
70 struct event_group* event_group;
71#endif
72};
66 73
67/** 74/**
68 * domain_data_t - Wrap domains with related CPU state 75 * struct domain_data - Wrap domains with related CPU state
69 * @domain A domain for a criticality level 76 * @domain A domain for a criticality level
70 * @heap The preemptable heap of crit entries (for global domains) 77 * @heap The preemptable heap of crit entries (for global domains)
71 * @crit_entry The crit entry for this domain (for partitioned domains) 78 * @crit_entry The crit entry for this domain (for partitioned domains)
72 */ 79 */
73typedef struct { 80struct domain_data {
74 domain_t domain; 81 struct domain domain;
75 struct bheap* heap; 82 struct bheap* heap;
76 crit_entry_t* crit_entry; 83 struct crit_entry* crit_entry;
77} domain_data_t; 84};
78 85
79static cpu_entry_t* cpus[NR_CPUS]; 86DEFINE_PER_CPU(struct cpu_entry, cpus);
80#ifdef CONFIG_RELEASE_MASTER 87#ifdef CONFIG_RELEASE_MASTER
81static int interrupt_cpu; 88static int interrupt_cpu;
82#endif 89#endif
90#ifdef CONFIG_MERGE_TIMERS
91static struct event_group* global_group;
92#endif
83 93
84#define domain_data(dom) (container_of(dom, domain_data_t, domain)) 94#define domain_data(dom) (container_of(dom, struct domain_data, domain))
85#define is_global(dom) (domain_data(dom)->heap) 95#define is_global(dom) (domain_data(dom)->heap)
86#define is_global_task(t) (is_global(get_task_domain(t))) 96#define is_global_task(t) (is_global(get_task_domain(t)))
87#define is_in_list(t) (tsk_rt(t)->list.next != tsk_rt(t)->list)
88#define can_requeue(t) \ 97#define can_requeue(t) \
89 (!is_global_task(t) || (t)->rt_param.scheduled_on == NO_CPU) 98 (!is_global_task(t) || (t)->rt_param.scheduled_on == NO_CPU)
90#define entry_level(e) \ 99#define entry_level(e) \
91 (((e)->linked) ? tsk_mc_crit((e)->linked) : NUM_CRIT_LEVELS - 1) 100 (((e)->linked) ? tsk_mc_crit((e)->linked) : NUM_CRIT_LEVELS - 1)
92#define crit_cpu(ce) \ 101#define crit_cpu(ce) \
93 (container_of((void*)((ce) - (ce)->level), cpu_entry_t, crit_entries)) 102 (container_of((void*)((ce) - (ce)->level), struct cpu_entry, crit_entries))
94/* Useful debug macros */
95#define TS "(%s/%d:%d:%s)"
96#define TA(t) (t) ? (is_ghost(t)) ? "ghost" : t->comm : "NULL", (t) ? t->pid : 1, \
97 (t) ? t->rt_param.job_params.job_no : 1, \
98 (t && get_task_domain(t)) ? get_task_domain(t)->name : ""
99#define TRACE_ENTRY(e, fmt, args...) \ 103#define TRACE_ENTRY(e, fmt, args...) \
100 TRACE("P%d, linked=" TS " " fmt "\n", \ 104 TRACE("P%d, linked=" TS " " fmt "\n", e->cpu, TA(e->linked), ##args)
101 e->cpu, TA(e->linked), ##args)
102#define TRACE_CRIT_ENTRY(ce, fmt, args...) \ 105#define TRACE_CRIT_ENTRY(ce, fmt, args...) \
103 TRACE("%s P%d, linked=" TS " " fmt "\n", \ 106 TRACE("%s P%d, linked=" TS " " fmt "\n", \
104 (ce)->domain->name, crit_cpu(ce)->cpu, TA((ce)->linked), ##args) 107 (ce)->domain->name, crit_cpu(ce)->cpu, TA((ce)->linked), ##args)
105#undef TRACE_TASK
106#define TRACE_TASK(t, fmt, args...) \
107 TRACE(TS " " fmt "\n", TA(t), ##args)
108 108
109/* 109/*
110 * Sort CPUs within a global domain by the domain's priority function. 110 * Sort CPUs within a global domain by the domain's priority function.
111 */ 111 */
112static int cpu_lower_prio(struct bheap_node *a, struct bheap_node *b) 112static int cpu_lower_prio(struct bheap_node *a, struct bheap_node *b)
113{ 113{
114 domain_t *domain; 114 struct domain *domain;
115 crit_entry_t *first, *second; 115 struct crit_entry *first, *second;
116 struct task_struct *first_link, *second_link; 116 struct task_struct *first_link, *second_link;
117 117
118 first = a->value; 118 first = a->value;
@@ -134,7 +134,7 @@ static int cpu_lower_prio(struct bheap_node *a, struct bheap_node *b)
134 * Return true if the domain has a higher priority ready task. The curr 134 * Return true if the domain has a higher priority ready task. The curr
135 * task must belong to the domain. 135 * task must belong to the domain.
136 */ 136 */
137static noinline int mc_preempt_needed(domain_t *dom, struct task_struct* curr) 137static int mc_preempt_needed(struct domain *dom, struct task_struct* curr)
138{ 138{
139 struct task_struct *next = dom->peek_ready(dom); 139 struct task_struct *next = dom->peek_ready(dom);
140 if (!next || !curr) { 140 if (!next || !curr) {
@@ -149,15 +149,45 @@ static noinline int mc_preempt_needed(domain_t *dom, struct task_struct* curr)
149 * Return next CPU which should preempted or NULL if the domain has no 149 * Return next CPU which should preempted or NULL if the domain has no
150 * preemptable CPUs. 150 * preemptable CPUs.
151 */ 151 */
152static inline crit_entry_t* lowest_prio_cpu(domain_t *dom) 152static inline struct crit_entry* lowest_prio_cpu(struct domain *dom)
153{ 153{
154 struct bheap *heap = domain_data(dom)->heap; 154 struct bheap *heap = domain_data(dom)->heap;
155 struct bheap_node* hn = bheap_peek(cpu_lower_prio, heap); 155 struct bheap_node* hn = bheap_peek(cpu_lower_prio, heap);
156 return (hn) ? hn->value : NULL; 156 return (hn) ? hn->value : NULL;
157} 157}
158 158
159/** 159/*
160 * update_ghost_time() - Time accounting for ghost tasks. 160 * Cancel ghost timer.
161 */
162static inline void cancel_ghost(struct crit_entry *ce)
163{
164#ifdef CONFIG_MERGE_TIMERS
165 cancel_event(&ce->event);
166#else
167 hrtimer_try_to_cancel(&ce->timer);
168#endif
169}
170
171/*
172 * Arm ghost timer. Will merge timers if the option is specified.
173 */
174static inline void arm_ghost(struct crit_entry *ce, lt_t fire)
175{
176#ifdef CONFIG_MERGE_TIMERS
177 struct event_group* group = (is_global(ce->domain)) ?
178 global_group : crit_cpu(ce)->event_group;
179 add_event(group, &ce->event, fire);
180#else
181 __hrtimer_start_range_ns(&ce->timer,
182 ns_to_ktime(when_to_fire),
183 0 /* delta */,
184 HRTIMER_MODE_ABS_PINNED,
185 0 /* no wakeup */);
186#endif
187}
188
189/*
190 * Time accounting for ghost tasks.
161 * Must be called before a decision is made involving the task's budget. 191 * Must be called before a decision is made involving the task's budget.
162 */ 192 */
163static void update_ghost_time(struct task_struct *p) 193static void update_ghost_time(struct task_struct *p)
@@ -167,14 +197,14 @@ static void update_ghost_time(struct task_struct *p)
167 BUG_ON(!is_ghost(p)); 197 BUG_ON(!is_ghost(p));
168 if (unlikely ((s64)delta < 0)) { 198 if (unlikely ((s64)delta < 0)) {
169 delta = 0; 199 delta = 0;
170 TRACE_TASK(p, "WARNING: negative time delta"); 200 TRACE_MC_TASK(p, "WARNING: negative time delta");
171 } 201 }
172 if (tsk_mc_data(p)->mc_job.ghost_budget <= delta) { 202 if (tsk_mc_data(p)->mc_job.ghost_budget <= delta) {
173 TRACE_TASK(p, "Ghost job could have ended"); 203 TRACE_MC_TASK(p, "Ghost job could have ended");
174 tsk_mc_data(p)->mc_job.ghost_budget = 0; 204 tsk_mc_data(p)->mc_job.ghost_budget = 0;
175 p->se.exec_start = clock; 205 p->se.exec_start = clock;
176 } else { 206 } else {
177 TRACE_TASK(p, "Ghost job updated, but didn't finish"); 207 TRACE_MC_TASK(p, "Ghost job updated, but didn't finish");
178 tsk_mc_data(p)->mc_job.ghost_budget -= delta; 208 tsk_mc_data(p)->mc_job.ghost_budget -= delta;
179 p->se.exec_start = clock; 209 p->se.exec_start = clock;
180 } 210 }
@@ -184,7 +214,7 @@ static void update_ghost_time(struct task_struct *p)
184 * link_task_to_crit() - Logically run a task at a criticality level. 214 * link_task_to_crit() - Logically run a task at a criticality level.
185 * Caller must hold @ce's domain's lock. 215 * Caller must hold @ce's domain's lock.
186 */ 216 */
187static void link_task_to_crit(crit_entry_t *ce, 217static void link_task_to_crit(struct crit_entry *ce,
188 struct task_struct *task) 218 struct task_struct *task)
189{ 219{
190 lt_t when_to_fire; 220 lt_t when_to_fire;
@@ -198,10 +228,10 @@ static void link_task_to_crit(crit_entry_t *ce,
198 228
199 /* Unlink last task */ 229 /* Unlink last task */
200 if (ce->linked) { 230 if (ce->linked) {
201 TRACE_TASK(ce->linked, "Unlinking"); 231 TRACE_MC_TASK(ce->linked, "Unlinking");
202 ce->linked->rt_param.linked_on = NO_CPU; 232 ce->linked->rt_param.linked_on = NO_CPU;
203 if (is_ghost(ce->linked)) { 233 if (is_ghost(ce->linked)) {
204 hrtimer_try_to_cancel(&ce->timer); 234 cancel_ghost(ce);
205 if (tsk_mc_data(ce->linked)->mc_job.ghost_budget > 0) { 235 if (tsk_mc_data(ce->linked)->mc_job.ghost_budget > 0) {
206 /* Job isn't finished, so do accounting */ 236 /* Job isn't finished, so do accounting */
207 update_ghost_time(ce->linked); 237 update_ghost_time(ce->linked);
@@ -218,11 +248,7 @@ static void link_task_to_crit(crit_entry_t *ce,
218 task->se.exec_start = litmus_clock(); 248 task->se.exec_start = litmus_clock();
219 when_to_fire = litmus_clock() + 249 when_to_fire = litmus_clock() +
220 tsk_mc_data(task)->mc_job.ghost_budget; 250 tsk_mc_data(task)->mc_job.ghost_budget;
221 __hrtimer_start_range_ns(&ce->timer, 251 arm_ghost(ce, when_to_fire);
222 ns_to_ktime(when_to_fire),
223 0 /* delta */,
224 HRTIMER_MODE_ABS_PINNED,
225 0 /* no wakeup */);
226 } 252 }
227 } 253 }
228 254
@@ -234,17 +260,18 @@ static void link_task_to_crit(crit_entry_t *ce,
234 } 260 }
235} 261}
236 262
237static void check_for_preempt(domain_t*); 263static void check_for_preempt(struct domain*);
238/** 264/**
239 * job_arrival() - Called when a task re-enters the system. 265 * job_arrival() - Called when a task re-enters the system.
240 * Caller must hold no locks. 266 * Caller must hold no locks.
241 */ 267 */
242static void job_arrival(struct task_struct *task) 268static void job_arrival(struct task_struct *task)
243{ 269{
244 domain_t *dom = get_task_domain(task); 270 struct domain *dom = get_task_domain(task);
245 271
246 TRACE_TASK(task, "Job arriving"); 272 TRACE_MC_TASK(task, "Job arriving");
247 BUG_ON(!task); 273 BUG_ON(!task);
274
248 if (can_requeue(task)) { 275 if (can_requeue(task)) {
249 raw_spin_lock(dom->lock); 276 raw_spin_lock(dom->lock);
250 dom->requeue(dom, task); 277 dom->requeue(dom, task);
@@ -257,7 +284,7 @@ static void job_arrival(struct task_struct *task)
257 * causing the system to crash when the task is scheduled 284 * causing the system to crash when the task is scheduled
258 * in two places simultaneously. 285 * in two places simultaneously.
259 */ 286 */
260 TRACE_TASK(task, "Delayed arrival of scheduled task"); 287 TRACE_MC_TASK(task, "Delayed arrival of scheduled task");
261 } 288 }
262} 289}
263 290
@@ -267,7 +294,7 @@ static void job_arrival(struct task_struct *task)
267 */ 294 */
268static void low_prio_arrival(struct task_struct *task) 295static void low_prio_arrival(struct task_struct *task)
269{ 296{
270 cpu_entry_t *entry; 297 struct cpu_entry *entry;
271 298
272 /* Race conditions! */ 299 /* Race conditions! */
273 if (!can_requeue(task)) return; 300 if (!can_requeue(task)) return;
@@ -278,9 +305,9 @@ static void low_prio_arrival(struct task_struct *task)
278 goto arrive; 305 goto arrive;
279#endif 306#endif
280 if (smp_processor_id() != interrupt_cpu) { 307 if (smp_processor_id() != interrupt_cpu) {
281 entry = cpus[smp_processor_id()]; 308 entry = &__get_cpu_var(cpus);
282 raw_spin_lock(&entry->redir_lock); 309 raw_spin_lock(&entry->redir_lock);
283 TRACE_TASK(task, "Adding to redirect queue"); 310 TRACE_MC_TASK(task, "Adding to redirect queue");
284 list_add(&tsk_rt(task)->list, &entry->redir); 311 list_add(&tsk_rt(task)->list, &entry->redir);
285 raw_spin_unlock(&entry->redir_lock); 312 raw_spin_unlock(&entry->redir_lock);
286 litmus_reschedule(interrupt_cpu); 313 litmus_reschedule(interrupt_cpu);
@@ -299,18 +326,18 @@ static void low_prio_arrival(struct task_struct *task)
299static void fix_global_levels(void) 326static void fix_global_levels(void)
300{ 327{
301 int c; 328 int c;
302 cpu_entry_t *e; 329 struct cpu_entry *e;
303 struct list_head *pos, *safe; 330 struct list_head *pos, *safe;
304 struct task_struct *t; 331 struct task_struct *t;
305 332
306 TRACE("Fixing global levels\n"); 333 TRACE("Fixing global levels\n");
307 for_each_online_cpu(c) { 334 for_each_online_cpu(c) {
308 e = cpus[c]; 335 e = &per_cpu(cpus, c);
309 raw_spin_lock(&e->redir_lock); 336 raw_spin_lock(&e->redir_lock);
310 list_for_each_safe(pos, safe, &e->redir) { 337 list_for_each_safe(pos, safe, &e->redir) {
311 t = list_entry(pos, struct task_struct, rt_param.list); 338 t = list_entry(pos, struct task_struct, rt_param.list);
312 TRACE_TASK(t, "Dequeued redirected job"); 339 BUG_ON(!t);
313 BUG_ON(is_queued(t)); 340 TRACE_MC_TASK(t, "Dequeued redirected job");
314 list_del_init(pos); 341 list_del_init(pos);
315 job_arrival(t); 342 job_arrival(t);
316 } 343 }
@@ -324,10 +351,10 @@ static void fix_global_levels(void)
324 * The task must first have been linked to one of the CPU's crit_entries. 351 * The task must first have been linked to one of the CPU's crit_entries.
325 * Caller must hold the entry lock. 352 * Caller must hold the entry lock.
326 */ 353 */
327static void link_task_to_cpu(cpu_entry_t *entry, struct task_struct *task) 354static void link_task_to_cpu(struct cpu_entry *entry, struct task_struct *task)
328{ 355{
329 int i = entry_level(entry); 356 int i = entry_level(entry);
330 TRACE_TASK(task, "Linking to P%d", entry->cpu); 357 TRACE_MC_TASK(task, "Linking to P%d", entry->cpu);
331 BUG_ON(task && tsk_rt(task)->linked_on != entry->cpu); 358 BUG_ON(task && tsk_rt(task)->linked_on != entry->cpu);
332 BUG_ON(task && is_ghost(task)); 359 BUG_ON(task && is_ghost(task));
333 360
@@ -348,10 +375,10 @@ static void link_task_to_cpu(cpu_entry_t *entry, struct task_struct *task)
348 * 375 *
349 * Caller must hold the lock for @dom and @ce's CPU lock. 376 * Caller must hold the lock for @dom and @ce's CPU lock.
350 */ 377 */
351static void preempt(domain_t *dom, crit_entry_t *ce) 378static void preempt(struct domain *dom, struct crit_entry *ce)
352{ 379{
353 struct task_struct *task = dom->take_ready(dom); 380 struct task_struct *task = dom->take_ready(dom);
354 cpu_entry_t *entry = crit_cpu(ce); 381 struct cpu_entry *entry = crit_cpu(ce);
355 382
356 BUG_ON(!task); 383 BUG_ON(!task);
357 TRACE_CRIT_ENTRY(ce, "Preempted by " TS, TA(task)); 384 TRACE_CRIT_ENTRY(ce, "Preempted by " TS, TA(task));
@@ -373,17 +400,25 @@ static void preempt(domain_t *dom, crit_entry_t *ce)
373 * This should be called after a new task has been linked to @entry. 400 * This should be called after a new task has been linked to @entry.
374 * The caller must hold the @entry->lock, but this method will release it. 401 * The caller must hold the @entry->lock, but this method will release it.
375 */ 402 */
376static void update_crit_levels(cpu_entry_t *entry) 403static void update_crit_levels(struct cpu_entry *entry)
377{ 404{
378 int i; 405 int i, global_preempted;
379 crit_entry_t *ce; 406 struct crit_entry *ce;
380 struct task_struct *tasks[NUM_CRIT_LEVELS]; 407 struct task_struct *readmit[NUM_CRIT_LEVELS];
381 enum crit_level level = entry_level(entry); 408 enum crit_level level = entry_level(entry);
382 409
383 /* Remove lower priority tasks from the entry */ 410 /* Remove lower priority tasks from the entry */
384 for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { 411 for (i = level + 1; i < NUM_CRIT_LEVELS; i++) {
385 ce = &entry->crit_entries[i]; 412 ce = &entry->crit_entries[i];
386 tasks[i] = ce->linked; 413
414 global_preempted = entry->scheduled == ce->linked &&
415 ce->linked && entry->linked &&
416 !is_ghost(ce->linked) && is_global(ce->domain);
417 /* Do not readmit global tasks which are preempted! These can't
418 * ever be re-admitted until they are descheduled for reasons
419 * explained in job_arrival.
420 */
421 readmit[i] = (!global_preempted) ? ce->linked : NULL;
387 ce->usable = 0; 422 ce->usable = 0;
388 if (ce->linked) 423 if (ce->linked)
389 link_task_to_crit(ce, NULL); 424 link_task_to_crit(ce, NULL);
@@ -394,8 +429,8 @@ static void update_crit_levels(cpu_entry_t *entry)
394 /* Re-admit tasks to the system */ 429 /* Re-admit tasks to the system */
395 for (i = level + 1; i < NUM_CRIT_LEVELS; i++) { 430 for (i = level + 1; i < NUM_CRIT_LEVELS; i++) {
396 ce = &entry->crit_entries[i]; 431 ce = &entry->crit_entries[i];
397 if (tasks[i]) 432 if (readmit[i])
398 low_prio_arrival(tasks[i]); 433 low_prio_arrival(readmit[i]);
399 } 434 }
400} 435}
401 436
@@ -405,11 +440,11 @@ static void update_crit_levels(cpu_entry_t *entry)
405 * Makes gigantic nasty assumption that there is 1 global criticality level, 440 * Makes gigantic nasty assumption that there is 1 global criticality level,
406 * and it is the last one in each list, so it doesn't call update_crit.. 441 * and it is the last one in each list, so it doesn't call update_crit..
407 */ 442 */
408static void check_for_preempt(domain_t *dom) 443static void check_for_preempt(struct domain *dom)
409{ 444{
410 int preempted = 1; 445 int preempted = 1;
411 cpu_entry_t *entry; 446 struct cpu_entry *entry;
412 crit_entry_t *ce; 447 struct crit_entry *ce;
413 448
414 if (is_global(dom)) { 449 if (is_global(dom)) {
415 /* Loop until we find a non-preemptable CPU */ 450 /* Loop until we find a non-preemptable CPU */
@@ -443,17 +478,17 @@ static void check_for_preempt(domain_t *dom)
443static void remove_from_all(struct task_struct* task) 478static void remove_from_all(struct task_struct* task)
444{ 479{
445 int update = 0; 480 int update = 0;
446 cpu_entry_t *entry; 481 struct cpu_entry *entry;
447 crit_entry_t *ce; 482 struct crit_entry *ce;
448 domain_t *dom = get_task_domain(task); 483 struct domain *dom = get_task_domain(task);
449 484
450 TRACE_TASK(task, "Removing from everything"); 485 TRACE_MC_TASK(task, "Removing from everything");
451 BUG_ON(!task); 486 BUG_ON(!task);
452 487
453 raw_spin_lock(dom->lock); 488 raw_spin_lock(dom->lock);
454 489
455 if (task->rt_param.linked_on != NO_CPU) { 490 if (task->rt_param.linked_on != NO_CPU) {
456 entry = cpus[task->rt_param.linked_on]; 491 entry = &per_cpu(cpus, task->rt_param.linked_on);
457 raw_spin_lock(&entry->lock); 492 raw_spin_lock(&entry->lock);
458 493
459 /* Unlink only if task is still linked post lock */ 494 /* Unlink only if task is still linked post lock */
@@ -492,7 +527,7 @@ static void remove_from_all(struct task_struct* task)
492 */ 527 */
493static void job_completion(struct task_struct *task, int forced) 528static void job_completion(struct task_struct *task, int forced)
494{ 529{
495 TRACE_TASK(task, "Completed"); 530 TRACE_MC_TASK(task, "Completed");
496 sched_trace_task_completion(task, forced); 531 sched_trace_task_completion(task, forced);
497 BUG_ON(!task); 532 BUG_ON(!task);
498 533
@@ -525,11 +560,19 @@ static void job_completion(struct task_struct *task, int forced)
525/** 560/**
526 * mc_ghost_exhausted() - Complete logically running ghost task. 561 * mc_ghost_exhausted() - Complete logically running ghost task.
527 */ 562 */
563#ifdef CONFIG_MERGE_TIMERS
564static void mc_ghost_exhausted(struct rt_event *e)
565{
566 struct crit_entry *ce = container_of(e, struct crit_entry, event);
567#else
528static enum hrtimer_restart mc_ghost_exhausted(struct hrtimer *timer) 568static enum hrtimer_restart mc_ghost_exhausted(struct hrtimer *timer)
529{ 569{
570 struct crit_entry *ce = container_of(timer, struct crit_entry, timer);
571#endif
572
530 unsigned long flags; 573 unsigned long flags;
531 struct task_struct *tmp = NULL; 574 struct task_struct *tmp = NULL;
532 crit_entry_t *ce = container_of(timer, crit_entry_t, timer);; 575
533 576
534 local_irq_save(flags); 577 local_irq_save(flags);
535 TRACE_CRIT_ENTRY(ce, "Ghost exhausted firing"); 578 TRACE_CRIT_ENTRY(ce, "Ghost exhausted firing");
@@ -553,7 +596,9 @@ static enum hrtimer_restart mc_ghost_exhausted(struct hrtimer *timer)
553 job_completion(tmp, 0); 596 job_completion(tmp, 0);
554 597
555 local_irq_restore(flags); 598 local_irq_restore(flags);
599#ifndef CONFIG_MERGE_TIMERS
556 return HRTIMER_NORESTART; 600 return HRTIMER_NORESTART;
601#endif
557} 602}
558 603
559/** 604/**
@@ -563,10 +608,10 @@ static void mc_release_jobs(rt_domain_t* rt, struct bheap* tasks)
563{ 608{
564 unsigned long flags; 609 unsigned long flags;
565 struct task_struct *first = bheap_peek(rt->order, tasks)->value; 610 struct task_struct *first = bheap_peek(rt->order, tasks)->value;
566 domain_t *dom = get_task_domain(first); 611 struct domain *dom = get_task_domain(first);
567 612
568 raw_spin_lock_irqsave(dom->lock, flags); 613 raw_spin_lock_irqsave(dom->lock, flags);
569 TRACE_TASK(first, "Jobs released"); 614 TRACE_MC_TASK(first, "Jobs released");
570 __merge_ready(rt, tasks); 615 __merge_ready(rt, tasks);
571 check_for_preempt(dom); 616 check_for_preempt(dom);
572 raw_spin_unlock_irqrestore(dom->lock, flags); 617 raw_spin_unlock_irqrestore(dom->lock, flags);
@@ -579,7 +624,7 @@ static void mc_release_jobs(rt_domain_t* rt, struct bheap* tasks)
579static void mc_task_new(struct task_struct *t, int on_rq, int running) 624static void mc_task_new(struct task_struct *t, int on_rq, int running)
580{ 625{
581 unsigned long flags; 626 unsigned long flags;
582 cpu_entry_t* entry; 627 struct cpu_entry* entry;
583 enum crit_level level = tsk_mc_crit(t); 628 enum crit_level level = tsk_mc_crit(t);
584 629
585 local_irq_save(flags); 630 local_irq_save(flags);
@@ -587,9 +632,9 @@ static void mc_task_new(struct task_struct *t, int on_rq, int running)
587 632
588 /* Assign domain */ 633 /* Assign domain */
589 if (level < CRIT_LEVEL_C) 634 if (level < CRIT_LEVEL_C)
590 entry = cpus[get_partition(t)]; 635 entry = &per_cpu(cpus, get_partition(t));
591 else 636 else
592 entry = cpus[task_cpu(t)]; 637 entry = &per_cpu(cpus, task_cpu(t));
593 t->rt_param._domain = entry->crit_entries[level].domain; 638 t->rt_param._domain = entry->crit_entries[level].domain;
594 639
595 /* Setup job params */ 640 /* Setup job params */
@@ -619,7 +664,7 @@ static void mc_task_wake_up(struct task_struct *task)
619 lt_t now = litmus_clock(); 664 lt_t now = litmus_clock();
620 local_irq_save(flags); 665 local_irq_save(flags);
621 666
622 TRACE_TASK(task, "Wakes up"); 667 TRACE_MC_TASK(task, "Wakes up");
623 if (is_tardy(task, now)) { 668 if (is_tardy(task, now)) {
624 /* Task missed its last release */ 669 /* Task missed its last release */
625 release_at(task, now); 670 release_at(task, now);
@@ -638,7 +683,7 @@ static void mc_task_block(struct task_struct *task)
638{ 683{
639 unsigned long flags; 684 unsigned long flags;
640 local_irq_save(flags); 685 local_irq_save(flags);
641 TRACE_TASK(task, "Block at %llu", litmus_clock()); 686 TRACE_MC_TASK(task, "Block at %llu", litmus_clock());
642 remove_from_all(task); 687 remove_from_all(task);
643 local_irq_restore(flags); 688 local_irq_restore(flags);
644} 689}
@@ -651,11 +696,11 @@ static void mc_task_exit(struct task_struct *task)
651 unsigned long flags; 696 unsigned long flags;
652 local_irq_save(flags); 697 local_irq_save(flags);
653 BUG_ON(!is_realtime(task)); 698 BUG_ON(!is_realtime(task));
654 TRACE_TASK(task, "RIP"); 699 TRACE_MC_TASK(task, "RIP");
655 700
656 remove_from_all(task); 701 remove_from_all(task);
657 if (tsk_rt(task)->scheduled_on != NO_CPU) { 702 if (tsk_rt(task)->scheduled_on != NO_CPU) {
658 cpus[tsk_rt(task)->scheduled_on]->scheduled = NULL; 703 per_cpu(cpus, tsk_rt(task)->scheduled_on).scheduled = NULL;
659 tsk_rt(task)->scheduled_on = NO_CPU; 704 tsk_rt(task)->scheduled_on = NO_CPU;
660 } 705 }
661 706
@@ -689,9 +734,9 @@ static long mc_admit_task(struct task_struct* task)
689static struct task_struct* mc_schedule(struct task_struct * prev) 734static struct task_struct* mc_schedule(struct task_struct * prev)
690{ 735{
691 unsigned long flags; 736 unsigned long flags;
692 domain_t *dom; 737 struct domain *dom;
693 crit_entry_t *ce; 738 struct crit_entry *ce;
694 cpu_entry_t* entry = cpus[smp_processor_id()]; 739 struct cpu_entry* entry = &__get_cpu_var(cpus);
695 int i, out_of_time, sleep, preempt, exists, blocks, global, lower; 740 int i, out_of_time, sleep, preempt, exists, blocks, global, lower;
696 struct task_struct *dtask = NULL, *ready_task = NULL, *next = NULL; 741 struct task_struct *dtask = NULL, *ready_task = NULL, *next = NULL;
697 742
@@ -703,6 +748,7 @@ static struct task_struct* mc_schedule(struct task_struct * prev)
703 BUG_ON(is_realtime(prev) && !entry->scheduled); 748 BUG_ON(is_realtime(prev) && !entry->scheduled);
704 749
705 /* Determine state */ 750 /* Determine state */
751 raw_spin_lock(&entry->lock);
706 exists = entry->scheduled != NULL; 752 exists = entry->scheduled != NULL;
707 blocks = exists && !is_running(entry->scheduled); 753 blocks = exists && !is_running(entry->scheduled);
708 out_of_time = exists && budget_enforced(entry->scheduled) && 754 out_of_time = exists && budget_enforced(entry->scheduled) &&
@@ -715,17 +761,20 @@ static struct task_struct* mc_schedule(struct task_struct * prev)
715 761
716 if (exists) { 762 if (exists) {
717 entry->scheduled->rt_param.scheduled_on = NO_CPU; 763 entry->scheduled->rt_param.scheduled_on = NO_CPU;
718 TRACE_TASK(prev, 764 TRACE_MC_TASK(prev,
719 "blocks:%d out_of_time:%d sleep:%d preempt:%d " 765 "blocks:%d out_of_time:%d sleep:%d preempt:%d "
720 "state:%d sig:%d global:%d", 766 "state:%d sig:%d global:%d",
721 blocks, out_of_time, sleep, preempt, 767 blocks, out_of_time, sleep, preempt,
722 prev->state, signal_pending(prev), global); 768 prev->state, signal_pending(prev), global);
723 } 769 }
770 raw_spin_unlock(&entry->lock);
771
724 772
725#ifdef CONFIG_PLUGIN_MC_REDIRECT 773#ifdef CONFIG_PLUGIN_MC_REDIRECT
726 if (smp_processor_id() == interrupt_cpu) 774 if (smp_processor_id() == interrupt_cpu)
727 fix_global_levels(); 775 fix_global_levels();
728#endif 776#endif
777
729 /* If a task blocks we have no choice but to reschedule */ 778 /* If a task blocks we have no choice but to reschedule */
730 if (blocks) 779 if (blocks)
731 remove_from_all(entry->scheduled); 780 remove_from_all(entry->scheduled);
@@ -769,6 +818,7 @@ static struct task_struct* mc_schedule(struct task_struct * prev)
769 raw_spin_unlock(dom->lock); 818 raw_spin_unlock(dom->lock);
770 update_crit_levels(entry); 819 update_crit_levels(entry);
771 raw_spin_lock(&entry->lock); 820 raw_spin_lock(&entry->lock);
821 continue;
772 } 822 }
773 } 823 }
774 raw_spin_unlock(dom->lock); 824 raw_spin_unlock(dom->lock);
@@ -784,22 +834,12 @@ static struct task_struct* mc_schedule(struct task_struct * prev)
784 raw_spin_unlock(&entry->lock); 834 raw_spin_unlock(&entry->lock);
785 local_irq_restore(flags); 835 local_irq_restore(flags);
786 if (next) 836 if (next)
787 TRACE_TASK(next, "Scheduled at %llu", litmus_clock()); 837 TRACE_MC_TASK(next, "Scheduled at %llu", litmus_clock());
788 else if (exists && !next) 838 else if (exists && !next)
789 TRACE("Becomes idle at %llu\n", litmus_clock()); 839 TRACE("Becomes idle at %llu\n", litmus_clock());
790 return next; 840 return next;
791} 841}
792 842
793static long mc_activate_plugin(void)
794{
795#ifdef CONFIG_RELEASE_MASTER
796 interrupt_cpu = atomic_read(&release_master_cpu);
797 if (interrupt_cpu == NO_CPU)
798 interrupt_cpu = 0;
799#endif
800 return 0;
801}
802
803/* ************************************************************************** 843/* **************************************************************************
804 * Initialization 844 * Initialization
805 * ************************************************************************** */ 845 * ************************************************************************** */
@@ -807,23 +847,36 @@ static long mc_activate_plugin(void)
807/* Initialize values here so that they are allocated with the module 847/* Initialize values here so that they are allocated with the module
808 * and destroyed when the module is unloaded. 848 * and destroyed when the module is unloaded.
809 */ 849 */
810DEFINE_PER_CPU(cpu_entry_t, _mc_cpus); 850
811/* LVL-A */ 851/* LVL-A */
812DEFINE_PER_CPU(domain_data_t, _mc_crit_a); 852DEFINE_PER_CPU(struct domain_data, _mc_crit_a);
813DEFINE_PER_CPU(rt_domain_t, _mc_crit_a_rt); 853DEFINE_PER_CPU(rt_domain_t, _mc_crit_a_rt);
814/* LVL-B */ 854/* LVL-B */
815DEFINE_PER_CPU(domain_data_t, _mc_crit_b); 855DEFINE_PER_CPU(struct domain_data, _mc_crit_b);
816DEFINE_PER_CPU(rt_domain_t, _mc_crit_b_rt); 856DEFINE_PER_CPU(rt_domain_t, _mc_crit_b_rt);
817/* LVL-C */ 857/* LVL-C */
818static domain_data_t _mc_crit_c; 858static struct domain_data _mc_crit_c;
819static rt_domain_t _mc_crit_c_rt; 859static rt_domain_t _mc_crit_c_rt;
820struct bheap _mc_heap_c; 860struct bheap _mc_heap_c;
821struct bheap_node _mc_nodes_c[NR_CPUS]; 861struct bheap_node _mc_nodes_c[NR_CPUS];
822 862
823/* 863#ifdef CONFIG_MERGE_TIMERS
824 * XXX commented out because I think this was an obvious typo 864#ifdef CONFIG_PLUGIN_MC_RELEASE_MASTER
825 */ 865struct event_group _mc_group;
826/* release_at)_ */ 866#else
867DEFINE_PER_CPU(struct event_group, _mc_groups);
868#endif
869#endif
870
871static long mc_activate_plugin(void)
872{
873#ifdef CONFIG_RELEASE_MASTER
874 interrupt_cpu = atomic_read(&release_master_cpu);
875 if (interrupt_cpu == NO_CPU)
876 interrupt_cpu = 0;
877#endif
878 return 0;
879}
827 880
828static struct sched_plugin mc_plugin __cacheline_aligned_in_smp = { 881static struct sched_plugin mc_plugin __cacheline_aligned_in_smp = {
829 .plugin_name = "MC", 882 .plugin_name = "MC",
@@ -837,8 +890,8 @@ static struct sched_plugin mc_plugin __cacheline_aligned_in_smp = {
837 .activate_plugin = mc_activate_plugin, 890 .activate_plugin = mc_activate_plugin,
838}; 891};
839 892
840static void init_crit_entry(crit_entry_t *ce, enum crit_level level, 893static void init_crit_entry(struct crit_entry *ce, enum crit_level level,
841 domain_data_t *dom_data, 894 struct domain_data *dom_data,
842 struct bheap_node *node) 895 struct bheap_node *node)
843{ 896{
844 ce->level = level; 897 ce->level = level;
@@ -846,12 +899,17 @@ static void init_crit_entry(crit_entry_t *ce, enum crit_level level,
846 ce->node = node; 899 ce->node = node;
847 ce->domain = &dom_data->domain; 900 ce->domain = &dom_data->domain;
848 ce->usable = 1; 901 ce->usable = 1;
849 atomic_set(&ce->dirty, 1); 902#ifdef CONFIG_MERGE_TIMERS
903 init_event(&ce->event, level, mc_ghost_exhausted,
904 event_list_alloc(GFP_ATOMIC));
905#else
850 hrtimer_init(&ce->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 906 hrtimer_init(&ce->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
851 ce->timer.function = mc_ghost_exhausted; 907 ce->timer.function = mc_ghost_exhausted;
908#endif
909
852} 910}
853 911
854static void init_local_domain(cpu_entry_t *entry, domain_data_t *dom_data, 912static void init_local_domain(struct cpu_entry *entry, struct domain_data *dom_data,
855 enum crit_level level) 913 enum crit_level level)
856{ 914{
857 dom_data->heap = NULL; 915 dom_data->heap = NULL;
@@ -859,12 +917,12 @@ static void init_local_domain(cpu_entry_t *entry, domain_data_t *dom_data,
859 init_crit_entry(dom_data->crit_entry, level, dom_data, NULL); 917 init_crit_entry(dom_data->crit_entry, level, dom_data, NULL);
860} 918}
861 919
862static void init_global_domain(domain_data_t *dom_data, enum crit_level level, 920static void init_global_domain(struct domain_data *dom_data, enum crit_level level,
863 struct bheap *heap, struct bheap_node *nodes) 921 struct bheap *heap, struct bheap_node *nodes)
864{ 922{
865 int cpu; 923 int cpu;
866 cpu_entry_t *entry; 924 struct cpu_entry *entry;
867 crit_entry_t *ce; 925 struct crit_entry *ce;
868 struct bheap_node *node; 926 struct bheap_node *node;
869 927
870 dom_data->crit_entry = NULL; 928 dom_data->crit_entry = NULL;
@@ -872,7 +930,7 @@ static void init_global_domain(domain_data_t *dom_data, enum crit_level level,
872 bheap_init(heap); 930 bheap_init(heap);
873 931
874 for_each_online_cpu(cpu) { 932 for_each_online_cpu(cpu) {
875 entry = cpus[cpu]; 933 entry = &per_cpu(cpus, cpu);
876 node = &nodes[cpu]; 934 node = &nodes[cpu];
877 ce = &entry->crit_entries[level]; 935 ce = &entry->crit_entries[level];
878 init_crit_entry(ce, level, dom_data, node); 936 init_crit_entry(ce, level, dom_data, node);
@@ -881,40 +939,62 @@ static void init_global_domain(domain_data_t *dom_data, enum crit_level level,
881 } 939 }
882} 940}
883 941
884static inline void init_edf_domain(domain_t *dom, rt_domain_t *rt) 942static inline void init_edf_domain(struct domain *dom, rt_domain_t *rt,
943 int timer_cpu, int prio)
885{ 944{
886 pd_domain_init(dom, rt, edf_ready_order, NULL, 945 pd_domain_init(dom, rt, edf_ready_order, NULL,
887 mc_release_jobs, mc_preempt_needed, 946 mc_release_jobs, mc_preempt_needed,
888 edf_higher_prio); 947 edf_higher_prio);
948#ifdef CONFIG_PLUGIN_MC_RELEASE_MASTER
949#ifdef CONFIG_MERGE_TIMERS
950 rt->event_group = &_mc_group;
951 rt->prio = prio;
952#else
953 rt->release_master = interrupt_cpu;
954#endif
955#elif CONFIG_MERGE_TIMERS
956 rt->event_group = &_mc_groups[timer_cpu];
957 rt->prio = prio;
958#endif
889} 959}
890 960
891static int __init init_mc(void) 961static int __init init_mc(void)
892{ 962{
893 int cpu; 963 int cpu;
894 cpu_entry_t *entry; 964 struct cpu_entry *entry;
965 struct domain_data *dom_data;
895 rt_domain_t *rt; 966 rt_domain_t *rt;
896 domain_data_t *dom_data;
897 raw_spinlock_t *a_dom, *b_dom, *c_dom; /* For lock debugger */ 967 raw_spinlock_t *a_dom, *b_dom, *c_dom; /* For lock debugger */
898 968
899 for_each_online_cpu(cpu) { 969 for_each_online_cpu(cpu) {
900 entry = &per_cpu(_mc_cpus, cpu); 970 entry = &per_cpu(cpus, cpu);
901 cpus[cpu] = entry;
902 971
903 /* CPU */ 972 /* CPU */
904 entry->cpu = cpu; 973 entry->cpu = cpu;
905 entry->scheduled = NULL; 974 entry->scheduled = NULL;
906 entry->linked = NULL; 975 entry->linked = NULL;
907 raw_spin_lock_init(&entry->lock); 976 raw_spin_lock_init(&entry->lock);
977
908#ifdef CONFIG_PLUGIN_MC_REDIRECT 978#ifdef CONFIG_PLUGIN_MC_REDIRECT
909 raw_spin_lock_init(&entry->redir_lock); 979 raw_spin_lock_init(&entry->redir_lock);
910 INIT_LIST_HEAD(&entry->redir); 980 INIT_LIST_HEAD(&entry->redir);
911#endif 981#endif
912 982
983#ifdef CONFIG_MERGE_TIMERS
984#ifdef CONFIG_PLUGIN_MC_RELEASE_MASTER
985 entry->event_group = &_mc_group;
986#else
987 init_event_group(&_mc_groups[cpu],
988 CONFIG_MERGE_TIMERS_WINDOW, cpu);
989 entry->event_group = &_mc_groups[cpu];
990#endif
991#endif
992
913 /* CRIT_LEVEL_A */ 993 /* CRIT_LEVEL_A */
914 dom_data = &per_cpu(_mc_crit_a, cpu); 994 dom_data = &per_cpu(_mc_crit_a, cpu);
915 rt = &per_cpu(_mc_crit_a_rt, cpu); 995 rt = &per_cpu(_mc_crit_a_rt, cpu);
916 init_local_domain(entry, dom_data, CRIT_LEVEL_A); 996 init_local_domain(entry, dom_data, CRIT_LEVEL_A);
917 init_edf_domain(&dom_data->domain, rt); 997 init_edf_domain(&dom_data->domain, rt, cpu, CRIT_LEVEL_A);
918 a_dom = dom_data->domain.lock; 998 a_dom = dom_data->domain.lock;
919 raw_spin_lock_init(a_dom); 999 raw_spin_lock_init(a_dom);
920 dom_data->domain.name = "LVL-A"; 1000 dom_data->domain.name = "LVL-A";
@@ -923,16 +1003,25 @@ static int __init init_mc(void)
923 dom_data = &per_cpu(_mc_crit_b, cpu); 1003 dom_data = &per_cpu(_mc_crit_b, cpu);
924 rt = &per_cpu(_mc_crit_b_rt, cpu); 1004 rt = &per_cpu(_mc_crit_b_rt, cpu);
925 init_local_domain(entry, dom_data, CRIT_LEVEL_B); 1005 init_local_domain(entry, dom_data, CRIT_LEVEL_B);
926 init_edf_domain(&dom_data->domain, rt); 1006 init_edf_domain(&dom_data->domain, rt, cpu, CRIT_LEVEL_B);
927 b_dom = dom_data->domain.lock; 1007 b_dom = dom_data->domain.lock;
928 raw_spin_lock_init(b_dom); 1008 raw_spin_lock_init(b_dom);
929 dom_data->domain.name = "LVL-B"; 1009 dom_data->domain.name = "LVL-B";
930 } 1010 }
931 1011
1012#ifdef CONFIG_MERGE_TIMERS
1013#ifdef CONFIG_PLUGIN_MC_RELEASE_MASTER
1014 init_event_group(&_mc_group, CONFIG_MERGE_TIMERS_WINDOW, interrupt_cpu);
1015 global_group = &_mc_group;
1016#else
1017 global_group = &_mc_groups[0];
1018#endif
1019#endif
1020
932 /* CRIT_LEVEL_C */ 1021 /* CRIT_LEVEL_C */
933 init_global_domain(&_mc_crit_c, CRIT_LEVEL_C, 1022 init_global_domain(&_mc_crit_c, CRIT_LEVEL_C,
934 &_mc_heap_c, _mc_nodes_c); 1023 &_mc_heap_c, _mc_nodes_c);
935 init_edf_domain(&_mc_crit_c.domain, &_mc_crit_c_rt); 1024 init_edf_domain(&_mc_crit_c.domain, &_mc_crit_c_rt, 0, CRIT_LEVEL_C);
936 c_dom = _mc_crit_c.domain.lock; 1025 c_dom = _mc_crit_c.domain.lock;
937 raw_spin_lock_init(c_dom); 1026 raw_spin_lock_init(c_dom);
938 _mc_crit_c.domain.name = "LVL-C"; 1027 _mc_crit_c.domain.name = "LVL-C";