diff options
author | Jeremy Erickson <jerickso@cs.unc.edu> | 2011-01-22 11:14:07 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2011-08-25 14:41:21 -0400 |
commit | d7f8fc563ffd17b5584acc5afedd16b385ad517b (patch) | |
tree | 5236d65f51dd53536ce5cd32dc8291ee5cf5aa4d /litmus/sched_mc.c | |
parent | 77282ed493834665c45c8ff86c9980e90840b01e (diff) |
Use watchdog timers (compiles, but not tested yet.)
Diffstat (limited to 'litmus/sched_mc.c')
-rw-r--r-- | litmus/sched_mc.c | 97 |
1 files changed, 91 insertions, 6 deletions
diff --git a/litmus/sched_mc.c b/litmus/sched_mc.c index 0f5da078c597..63dd157925ab 100644 --- a/litmus/sched_mc.c +++ b/litmus/sched_mc.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
14 | #include <linux/percpu.h> | 14 | #include <linux/percpu.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/hrtimer.h> | ||
16 | 17 | ||
17 | #include <litmus/litmus.h> | 18 | #include <litmus/litmus.h> |
18 | #include <litmus/jobs.h> | 19 | #include <litmus/jobs.h> |
@@ -99,6 +100,16 @@ typedef struct { | |||
99 | struct task_struct* ghost_tasks[CRIT_LEVEL_D+1]; | 100 | struct task_struct* ghost_tasks[CRIT_LEVEL_D+1]; |
100 | } cpu_entry_t; | 101 | } cpu_entry_t; |
101 | 102 | ||
103 | /*This code is heavily based on Bjoern's budget enforcement code. */ | ||
104 | struct watchdog_timer { | ||
105 | /* The watchdog timers determine when ghost jobs finish. */ | ||
106 | struct hrtimer timer; | ||
107 | struct task_struct* task; | ||
108 | }; | ||
109 | |||
110 | DEFINE_PER_CPU(struct watchdog_timer[CRIT_LEVEL_D+1], ghost_timers); | ||
111 | #define ghost_timer(cpu, crit) (&(per_cpu(ghost_timers, cpu)[crit])) | ||
112 | |||
102 | DEFINE_PER_CPU(cpu_entry_t, mc_cpu_entries); | 113 | DEFINE_PER_CPU(cpu_entry_t, mc_cpu_entries); |
103 | 114 | ||
104 | cpu_entry_t* mc_cpus[NR_CPUS]; | 115 | cpu_entry_t* mc_cpus[NR_CPUS]; |
@@ -328,7 +339,7 @@ static void update_ghost_time(struct task_struct *p) | |||
328 | u64 clock; | 339 | u64 clock; |
329 | 340 | ||
330 | BUG_ON(!is_ghost(p)); | 341 | BUG_ON(!is_ghost(p)); |
331 | clock = cpu_clock(p->rt_param.linked_on); | 342 | clock = litmus_clock(); |
332 | delta = clock - p->se.exec_start; | 343 | delta = clock - p->se.exec_start; |
333 | if (unlikely ((s64)delta < 0)) { | 344 | if (unlikely ((s64)delta < 0)) { |
334 | delta = 0; | 345 | delta = 0; |
@@ -344,6 +355,25 @@ static void update_ghost_time(struct task_struct *p) | |||
344 | } | 355 | } |
345 | 356 | ||
346 | 357 | ||
358 | /* | ||
359 | * | ||
360 | */ | ||
361 | static void cancel_watchdog_timer(struct watchdog_timer* wt) | ||
362 | { | ||
363 | int ret; | ||
364 | |||
365 | if (wt->task) { | ||
366 | TRACE_TASK(wt->task, "Cancelling watchdog timer.\n"); | ||
367 | ret = hrtimer_try_to_cancel(&wt->timer); | ||
368 | /*Should never be inactive.*/ | ||
369 | BUG_ON(ret == 0); | ||
370 | /*Should never be running concurrently. */ | ||
371 | BUG_ON(ret == -1); | ||
372 | |||
373 | wt->task = NULL; | ||
374 | } | ||
375 | } | ||
376 | |||
347 | /* link_task_to_cpu - Update the link of a CPU. | 377 | /* link_task_to_cpu - Update the link of a CPU. |
348 | * Handles the case where the to-be-linked task is already | 378 | * Handles the case where the to-be-linked task is already |
349 | * scheduled on a different CPU. | 379 | * scheduled on a different CPU. |
@@ -358,6 +388,8 @@ static noinline void link_task_to_cpu(struct task_struct* linked, | |||
358 | struct task_struct* tmp; | 388 | struct task_struct* tmp; |
359 | int on_cpu; | 389 | int on_cpu; |
360 | int i; | 390 | int i; |
391 | struct watchdog_timer* timer; | ||
392 | lt_t when_to_fire; | ||
361 | 393 | ||
362 | BUG_ON(linked && !is_realtime(linked)); | 394 | BUG_ON(linked && !is_realtime(linked)); |
363 | BUG_ON(linked && is_realtime(linked) && | 395 | BUG_ON(linked && is_realtime(linked) && |
@@ -378,8 +410,22 @@ static noinline void link_task_to_cpu(struct task_struct* linked, | |||
378 | */ | 410 | */ |
379 | BUG_ON(linked->rt_param.linked_on != NO_CPU); | 411 | BUG_ON(linked->rt_param.linked_on != NO_CPU); |
380 | linked->rt_param.linked_on = entry->cpu; | 412 | linked->rt_param.linked_on = entry->cpu; |
381 | linked->se.exec_start = cpu_clock(entry->cpu); | 413 | linked->se.exec_start = litmus_clock(); |
382 | entry->ghost_tasks[linked->rt_param.task_params.crit] = linked; | 414 | entry->ghost_tasks[linked->rt_param.task_params.crit] = linked; |
415 | /* Set up the watchdog timer. */ | ||
416 | timer = ghost_timer(entry->cpu, | ||
417 | linked->rt_param.task_params.crit); | ||
418 | if (timer->task){ | ||
419 | cancel_watchdog_timer(timer); | ||
420 | } | ||
421 | when_to_fire = litmus_clock() + | ||
422 | linked->rt_param.job_params.ghost_budget; | ||
423 | timer->task = linked; | ||
424 | __hrtimer_start_range_ns(&timer->timer, | ||
425 | ns_to_ktime(when_to_fire), | ||
426 | 0 /* delta */, | ||
427 | HRTIMER_MODE_ABS_PINNED, | ||
428 | 0 /* no wakeup */); | ||
383 | } | 429 | } |
384 | else{ | 430 | else{ |
385 | /* Currently linked task is set to be unlinked. */ | 431 | /* Currently linked task is set to be unlinked. */ |
@@ -465,6 +511,7 @@ static noinline void unlink(struct task_struct* t) | |||
465 | { | 511 | { |
466 | int cpu; | 512 | int cpu; |
467 | cpu_entry_t *entry; | 513 | cpu_entry_t *entry; |
514 | struct watchdog_timer *timer; | ||
468 | 515 | ||
469 | if (unlikely(!t)) { | 516 | if (unlikely(!t)) { |
470 | TRACE_BUG_ON(!t); | 517 | TRACE_BUG_ON(!t); |
@@ -477,6 +524,12 @@ static noinline void unlink(struct task_struct* t) | |||
477 | entry = remote_cpu_entry(cpu); | 524 | entry = remote_cpu_entry(cpu); |
478 | t->rt_param.linked_on = NO_CPU; | 525 | t->rt_param.linked_on = NO_CPU; |
479 | if (is_ghost(t)) { | 526 | if (is_ghost(t)) { |
527 | /* Clear the timer.*/ | ||
528 | timer = ghost_timer(cpu, | ||
529 | t->rt_param.task_params.crit); | ||
530 | /* Should already be watching task.*/ | ||
531 | BUG_ON(timer->task != t); | ||
532 | cancel_watchdog_timer(timer); | ||
480 | if (t->rt_param.job_params.ghost_budget > 0){ | 533 | if (t->rt_param.job_params.ghost_budget > 0){ |
481 | /* Job isn't finished, so do accounting. */ | 534 | /* Job isn't finished, so do accounting. */ |
482 | update_ghost_time(t); | 535 | update_ghost_time(t); |
@@ -686,7 +739,9 @@ static noinline void job_completion(struct task_struct *t, int forced) | |||
686 | 739 | ||
687 | /* set flags */ | 740 | /* set flags */ |
688 | set_rt_flags(t, RT_F_SLEEP); | 741 | set_rt_flags(t, RT_F_SLEEP); |
689 | /*If it's not a ghost job, do ghost job conversion and return.*/ | 742 | /* If it's not a ghost job, do ghost job conversion and return if |
743 | * needed. | ||
744 | */ | ||
690 | if (!is_ghost(t)) { | 745 | if (!is_ghost(t)) { |
691 | cpu = remote_cpu_entry(t->rt_param.scheduled_on); | 746 | cpu = remote_cpu_entry(t->rt_param.scheduled_on); |
692 | /*Unlink first while it's not a ghost job.*/ | 747 | /*Unlink first while it's not a ghost job.*/ |
@@ -697,6 +752,12 @@ static noinline void job_completion(struct task_struct *t, int forced) | |||
697 | /* If we did just convert the job to ghost, we can safely | 752 | /* If we did just convert the job to ghost, we can safely |
698 | * reschedule it and then let schedule() determine a new | 753 | * reschedule it and then let schedule() determine a new |
699 | * job to run in the slack. | 754 | * job to run in the slack. |
755 | * | ||
756 | * If it actually needs to run as a ghost job, we'll do so | ||
757 | * here. | ||
758 | * | ||
759 | * If it doesn't need to, it will fall through and be handled | ||
760 | * properly as well. | ||
700 | */ | 761 | */ |
701 | if (t->rt_param.job_params.ghost_budget > 0){ | 762 | if (t->rt_param.job_params.ghost_budget > 0){ |
702 | link_task_to_cpu(t, cpu); | 763 | link_task_to_cpu(t, cpu); |
@@ -705,9 +766,6 @@ static noinline void job_completion(struct task_struct *t, int forced) | |||
705 | } | 766 | } |
706 | } | 767 | } |
707 | /* prepare for next period */ | 768 | /* prepare for next period */ |
708 | /* TODO: check what happens if we actually finish with exactly our | ||
709 | * budget and never convert to ghost | ||
710 | */ | ||
711 | if (is_ghost(t)) { | 769 | if (is_ghost(t)) { |
712 | t->rt_param.job_params.ghost_budget = 0; | 770 | t->rt_param.job_params.ghost_budget = 0; |
713 | prepare_for_next_period(t); | 771 | prepare_for_next_period(t); |
@@ -726,6 +784,26 @@ static noinline void job_completion(struct task_struct *t, int forced) | |||
726 | mc_job_arrival(t); | 784 | mc_job_arrival(t); |
727 | } | 785 | } |
728 | 786 | ||
787 | /* watchdog_timeout - this function is called when a watchdog timer expires. | ||
788 | * | ||
789 | * Acquires global lock | ||
790 | */ | ||
791 | |||
792 | static enum hrtimer_restart watchdog_timeout(struct hrtimer *timer) | ||
793 | { | ||
794 | struct watchdog_timer* wt = container_of(timer, | ||
795 | struct watchdog_timer, | ||
796 | timer); | ||
797 | unsigned long flags; | ||
798 | raw_spin_lock_irqsave(&global_lock, flags); | ||
799 | /*If we have triggered, we know the budget must have expired.*/ | ||
800 | wt->task->rt_param.job_params.ghost_budget = 0; | ||
801 | job_completion(wt->task, 0); | ||
802 | raw_spin_unlock_irqrestore(&global_lock, flags); | ||
803 | return HRTIMER_NORESTART; | ||
804 | } | ||
805 | |||
806 | |||
729 | /* mc_tick - this function is called for every local timer | 807 | /* mc_tick - this function is called for every local timer |
730 | * interrupt. | 808 | * interrupt. |
731 | * | 809 | * |
@@ -1144,6 +1222,7 @@ static int __init init_mc(void) | |||
1144 | int cpu; | 1222 | int cpu; |
1145 | int i; | 1223 | int i; |
1146 | cpu_entry_t *entry; | 1224 | cpu_entry_t *entry; |
1225 | struct watchdog_timer *timer; | ||
1147 | 1226 | ||
1148 | bheap_init(&mc_cpu_heap_c); | 1227 | bheap_init(&mc_cpu_heap_c); |
1149 | bheap_init(&mc_cpu_heap_d); | 1228 | bheap_init(&mc_cpu_heap_d); |
@@ -1157,6 +1236,12 @@ static int __init init_mc(void) | |||
1157 | entry->hn_d = &mc_heap_node_d[cpu]; | 1236 | entry->hn_d = &mc_heap_node_d[cpu]; |
1158 | bheap_node_init(&entry->hn_c, entry); | 1237 | bheap_node_init(&entry->hn_c, entry); |
1159 | bheap_node_init(&entry->hn_d, entry); | 1238 | bheap_node_init(&entry->hn_d, entry); |
1239 | for (i = CRIT_LEVEL_A; i <= CRIT_LEVEL_D; i++){ | ||
1240 | timer = ghost_timer(cpu, i); | ||
1241 | hrtimer_init(&timer->timer, CLOCK_MONOTONIC, | ||
1242 | HRTIMER_MODE_ABS); | ||
1243 | timer->timer.function = watchdog_timeout; | ||
1244 | } | ||
1160 | } | 1245 | } |
1161 | mc_edf_domain_init(&crit_c, NULL, mc_release_jobs); | 1246 | mc_edf_domain_init(&crit_c, NULL, mc_release_jobs); |
1162 | mc_edf_domain_init(&crit_d, NULL, mc_release_jobs); | 1247 | mc_edf_domain_init(&crit_d, NULL, mc_release_jobs); |