aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZelin Tong <ztong@ludwig.cs.unc.edu>2020-02-27 18:02:33 -0500
committerZelin Tong <ztong@ludwig.cs.unc.edu>2020-02-27 18:02:33 -0500
commitfab953c864033c002675c79eab121291c324bee6 (patch)
treeba20846334f008b26591ac0a9fddfe79a092aa4b
parent25fb933628b3f3953fb8b6d206a0c53855a8bae9 (diff)
Fixed accounting for empty container budget
-rw-r--r--litmus/sched_edfsc.c57
1 files changed, 30 insertions, 27 deletions
diff --git a/litmus/sched_edfsc.c b/litmus/sched_edfsc.c
index 449d6b3431a2..644c88c6c428 100644
--- a/litmus/sched_edfsc.c
+++ b/litmus/sched_edfsc.c
@@ -240,6 +240,7 @@ static noinline void unlink(struct task_struct* t)
240 entry = &per_cpu(edfsc_cpu_entries, t->rt_param.linked_on); 240 entry = &per_cpu(edfsc_cpu_entries, t->rt_param.linked_on);
241 t->rt_param.linked_on = NO_CPU; 241 t->rt_param.linked_on = NO_CPU;
242 link_task_to_cpu(NULL, entry); 242 link_task_to_cpu(NULL, entry);
243 BUG_ON(entry->linked || t->rt_param.linked_on != NO_CPU);
243 } else if (is_queued(t)) { 244 } else if (is_queued(t)) {
244 /* This is an interesting situation: t is scheduled, 245 /* This is an interesting situation: t is scheduled,
245 * but was just recently unlinked. It cannot be 246 * but was just recently unlinked. It cannot be
@@ -444,9 +445,13 @@ static void g_finish_switch(struct task_struct *prev)
444 cpu_entry_t* entry = this_cpu_ptr(&edfsc_cpu_entries); 445 cpu_entry_t* entry = this_cpu_ptr(&edfsc_cpu_entries);
445 BUG_ON(is_realtime(current) && tsk_rt(current)->domain == NULL); 446 BUG_ON(is_realtime(current) && tsk_rt(current)->domain == NULL);
446 447
447 entry->scheduled = is_realtime(current) ? current : NULL; 448 if (!is_container(entry->linked)) {
448 if (entry->scheduled) 449 entry->scheduled = is_realtime(current) ? current : NULL;
449 entry->scheduled = (is_fixed(current)) ? tsk_rt(current)->edfsc_params.container_task : current; 450 if (entry->scheduled)
451 entry->scheduled = (is_fixed(current)) ? tsk_rt(current)->edfsc_params.container_task : current;
452 }
453 else
454 entry->scheduled = entry->linked;
450#ifdef WANT_ALL_SCHED_EVENTS 455#ifdef WANT_ALL_SCHED_EVENTS
451 TRACE_TASK(prev, "switched away from\n"); 456 TRACE_TASK(prev, "switched away from\n");
452#endif 457#endif
@@ -587,17 +592,17 @@ void manage_idle_enforcement_timer(struct task_struct* t)
587 lt_t now; 592 lt_t now;
588 593
589 cont_domain_t* domain = tsk_rt(t)->edfsc_params.domain; 594 cont_domain_t* domain = tsk_rt(t)->edfsc_params.domain;
590 if (t && budget_precisely_enforced(t)) { 595 now = litmus_clock();
596 domain->scheduled_last_exec_time = now;
597 if (budget_precisely_enforced(t)) {
591 BUG_ON(budget_exhausted(t) && !is_np(t)); 598 BUG_ON(budget_exhausted(t) && !is_np(t));
592 if (likely(!is_np(t))) { 599 if (likely(!is_np(t))) {
593 now = litmus_clock();
594 //hrtimer_start cancels the timer so don't have to check 600 //hrtimer_start cancels the timer so don't have to check
595 //if it is already armed 601 //if it is already armed
596 hrtimer_start(&(domain->idle_enforcement_timer), 602 hrtimer_start(&(domain->idle_enforcement_timer),
597 ns_to_ktime(now + budget_remaining(t)), 603 ns_to_ktime(now + budget_remaining(t)),
598 HRTIMER_MODE_ABS_PINNED); 604 HRTIMER_MODE_ABS_PINNED);
599 domain->timer_armed = 1; 605 domain->timer_armed = 1;
600 domain->scheduled_last_exec_time = now;
601 } 606 }
602 } 607 }
603 else if (domain->timer_armed) { 608 else if (domain->timer_armed) {
@@ -620,21 +625,22 @@ static struct task_struct *edfsc_gschedule(struct task_struct *prev)
620 625
621 /* sanity checking */ 626 /* sanity checking */
622 BUG_ON(entry->scheduled && entry->scheduled != prev && !is_container(entry->scheduled)); 627 BUG_ON(entry->scheduled && entry->scheduled != prev && !is_container(entry->scheduled));
623 BUG_ON(entry->scheduled && entry->scheduled != prev && 628 BUG_ON(entry->scheduled && entry->scheduled != prev && is_realtime(prev) &&
624 tsk_rt(prev)->domain != tsk_rt(entry->scheduled)->edfsc_params.domain); 629 tsk_rt(prev)->domain != tsk_rt(entry->scheduled)->edfsc_params.domain);
625 BUG_ON(entry->scheduled && entry->scheduled != prev && 630 BUG_ON(entry->scheduled && entry->scheduled != prev && is_realtime(prev) &&
626 prev != tsk_rt(entry->scheduled)->edfsc_params.domain->scheduled); 631 prev != tsk_rt(entry->scheduled)->edfsc_params.domain->scheduled);
627 // It's okay for the previously scheduled task to not be rt if we think a 632 // It's okay for the previously scheduled task to not be rt if we think a
628 // container task is scheduled and the container doesn't have any pending 633 // container task is scheduled and the container doesn't have any pending
629 // jobs of fixed tasks. 634 // jobs of fixed tasks.
630 BUG_ON(entry->scheduled && !is_realtime(prev)); 635 BUG_ON(entry->scheduled && !is_container(entry->scheduled) && !is_realtime(prev));
631 BUG_ON(is_realtime(prev) && !entry->scheduled); 636 BUG_ON(is_realtime(prev) && !entry->scheduled);
632 637
633 //TODO 638 //TODO
634 // condition when a container is "scheduled" but there are no realtime tasks 639 // condition when a container is "scheduled" but there are no realtime tasks
635 if (is_container(entry->scheduled) && (!prev || !is_realtime(prev))) 640 if (is_container(entry->scheduled) && (!prev || !is_realtime(prev))) {
636 tsk_rt(entry->scheduled)->job_params.exec_time += litmus_clock() 641 tsk_rt(entry->scheduled)->job_params.exec_time += litmus_clock()
637 - tsk_rt(entry->scheduled)->edfsc_params.domain->scheduled_last_exec_time; 642 - tsk_rt(entry->scheduled)->edfsc_params.domain->scheduled_last_exec_time;
643 }
638 644
639 // update container budget if prev was a fixed or background scheduled task 645 // update container budget if prev was a fixed or background scheduled task
640 if (entry->scheduled && prev && is_realtime(prev) && prev != entry->scheduled) { 646 if (entry->scheduled && prev && is_realtime(prev) && prev != entry->scheduled) {
@@ -653,7 +659,7 @@ static struct task_struct *edfsc_gschedule(struct task_struct *prev)
653 /* (0) Determine state */ 659 /* (0) Determine state */
654 exists = entry->scheduled != NULL; 660 exists = entry->scheduled != NULL;
655 is_cont = is_container(entry->scheduled); 661 is_cont = is_container(entry->scheduled);
656 blocks = exists && !is_current_running(); 662 blocks = exists && !is_container(entry->scheduled) && !is_current_running();
657 out_of_time = exists && budget_enforced(entry->scheduled) 663 out_of_time = exists && budget_enforced(entry->scheduled)
658 && budget_exhausted(entry->scheduled); 664 && budget_exhausted(entry->scheduled);
659 np = exists && is_np(entry->scheduled); 665 np = exists && is_np(entry->scheduled);
@@ -677,7 +683,7 @@ static struct task_struct *edfsc_gschedule(struct task_struct *prev)
677 683
678 684
679 /* If a task blocks we have no choice but to reschedule. 685 /* If a task blocks we have no choice but to reschedule.
680 * Note: containers never block since their task struct has state = IS_RUNNING 686 * Note: containers never block
681 */ 687 */
682 if (blocks) 688 if (blocks)
683 unlink(entry->scheduled); 689 unlink(entry->scheduled);
@@ -687,6 +693,7 @@ static struct task_struct *edfsc_gschedule(struct task_struct *prev)
687 * that we are still linked. Multiple calls to request_exit_np() don't 693 * that we are still linked. Multiple calls to request_exit_np() don't
688 * hurt. 694 * hurt.
689 */ 695 */
696 printk("unlink? %d\n", np && (out_of_time || preempt || sleep));
690 if (np && (out_of_time || preempt || sleep)) { 697 if (np && (out_of_time || preempt || sleep)) {
691 unlink(entry->scheduled); 698 unlink(entry->scheduled);
692 request_exit_np(entry->scheduled); 699 request_exit_np(entry->scheduled);
@@ -697,6 +704,7 @@ static struct task_struct *edfsc_gschedule(struct task_struct *prev)
697 * this. Don't do a job completion if we block (can't have timers running 704 * this. Don't do a job completion if we block (can't have timers running
698 * for blocked jobs). 705 * for blocked jobs).
699 */ 706 */
707 printk("completion? %d\n", !np && (out_of_time || sleep));
700 if (!np && (out_of_time || sleep)) 708 if (!np && (out_of_time || sleep))
701 g_job_completion(entry->scheduled, !sleep); 709 g_job_completion(entry->scheduled, !sleep);
702 710
@@ -707,10 +715,9 @@ static struct task_struct *edfsc_gschedule(struct task_struct *prev)
707 printk("ready task in global domain %d\n", __peek_ready(&gsched_domain)); 715 printk("ready task in global domain %d\n", __peek_ready(&gsched_domain));
708 if (__peek_ready(&gsched_domain)) 716 if (__peek_ready(&gsched_domain))
709 printk("container id %d\n", tsk_rt(__peek_ready(&gsched_domain))->edfsc_params.id); 717 printk("container id %d\n", tsk_rt(__peek_ready(&gsched_domain))->edfsc_params.id);
710 printk("%p\n", entry->linked);
711 if (!entry->linked) 718 if (!entry->linked)
712 link_task_to_cpu(__take_ready(&gsched_domain), entry); 719 link_task_to_cpu(__take_ready(&gsched_domain), entry);
713 printk("%p\n", entry->linked); 720 printk("newly linked task: %p\n", entry->linked);
714 721
715 /* The final scheduling decision. Do we need to switch for some reason? 722 /* The final scheduling decision. Do we need to switch for some reason?
716 * If linked is different from scheduled, then select linked as next. 723 * If linked is different from scheduled, then select linked as next.
@@ -734,16 +741,14 @@ static struct task_struct *edfsc_gschedule(struct task_struct *prev)
734 if (exists) 741 if (exists)
735 next = prev; 742 next = prev;
736 743
737 printk("%p\n", next); 744 printk("next candidate: %p\n", next);
738 printk("%p\n", tsk_rt(next)->domain);
739 printk("%p\n", &gsched_domain);
740 if (is_container(next)) { 745 if (is_container(next)) {
741 next = edfsc_cschedule(tsk_rt(next)->edfsc_params.domain, prev); 746 next = edfsc_cschedule(tsk_rt(next)->edfsc_params.domain, prev);
742 } 747 }
743 748
744 sched_state_task_picked(); 749 sched_state_task_picked();
745 750
746 printk("/edfsc_gschedule\n"); 751 printk("/edfsc_gschedule\n\n");
747 752
748 raw_spin_unlock_irqrestore(&g_lock, flags); 753 raw_spin_unlock_irqrestore(&g_lock, flags);
749 754
@@ -757,9 +762,7 @@ static struct task_struct *edfsc_gschedule(struct task_struct *prev)
757#endif 762#endif
758 763
759 if (is_container(next)) { 764 if (is_container(next)) {
760 if (budget_precisely_enforced(next)) { 765 manage_idle_enforcement_timer(next);
761 manage_idle_enforcement_timer(next);
762 }
763 return NULL; 766 return NULL;
764 } 767 }
765 else 768 else
@@ -785,7 +788,7 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
785 788
786 raw_spin_lock_irqsave(&g_lock, flags); 789 raw_spin_lock_irqsave(&g_lock, flags);
787 790
788 printk("container_boundary\n"); 791 printk("\ncontainer_boundary\n");
789 792
790 now = litmus_clock(); 793 now = litmus_clock();
791 794
@@ -906,12 +909,12 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
906 if (budget_exhausted(t)) { 909 if (budget_exhausted(t)) {
907 prepare_for_next_period(t); 910 prepare_for_next_period(t);
908 if (is_early_releasing(t) || is_released(t, now)) { 911 if (is_early_releasing(t) || is_released(t, now)) {
912 //TODO actually release
909 sched_trace_task_release(t); 913 sched_trace_task_release(t);
910 } 914 }
911 /* requeue 915 /* requeue
912 * But don't requeue a blocking task. */ 916 * But don't requeue a blocking task. */
913 if (is_current_running()) { //since we don't support blocking, this should always be true 917 if (is_current_running()) { //since we don't support blocking, this should always be true
914 printk("current: %d\n", current);
915 if (tsk_rt(t)->edfsc_params.domain->scheduled) { 918 if (tsk_rt(t)->edfsc_params.domain->scheduled) {
916 requeue(tsk_rt(t)->edfsc_params.domain->scheduled); 919 requeue(tsk_rt(t)->edfsc_params.domain->scheduled);
917 } 920 }
@@ -923,8 +926,8 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
923 tsk_rt(&container_tasks[i])->edfsc_params.can_release = 1; 926 tsk_rt(&container_tasks[i])->edfsc_params.can_release = 1;
924 } 927 }
925 } 928 }
926 BUG(); 929
927 printk("/container_boundary\n"); 930 printk("/container_boundary\n\n");
928 raw_spin_unlock_irqrestore(&g_lock, flags); 931 raw_spin_unlock_irqrestore(&g_lock, flags);
929 932
930 hrtimer_add_expires_ns(timer, LITMUS_QUANTUM_LENGTH_NS); 933 hrtimer_add_expires_ns(timer, LITMUS_QUANTUM_LENGTH_NS);
@@ -1201,12 +1204,12 @@ static int __init init_edfsc(void)
1201 1204
1202 container_tasks[i].policy = SCHED_LITMUS; 1205 container_tasks[i].policy = SCHED_LITMUS;
1203 tsk_rt(&container_tasks[i])->scheduled_on = NO_CPU; 1206 tsk_rt(&container_tasks[i])->scheduled_on = NO_CPU;
1204 tsk_rt(&container_tasks[i])->task_params.exec_cost = 0; 1207 tsk_rt(&container_tasks[i])->task_params.exec_cost = LITMUS_QUANTUM_LENGTH_NS / 2;
1205 tsk_rt(&container_tasks[i])->task_params.period = 1208 tsk_rt(&container_tasks[i])->task_params.period =
1206 LITMUS_QUANTUM_LENGTH_NS; 1209 LITMUS_QUANTUM_LENGTH_NS;
1207 tsk_rt(&container_tasks[i])->task_params.relative_deadline = 1210 tsk_rt(&container_tasks[i])->task_params.relative_deadline =
1208 LITMUS_QUANTUM_LENGTH_NS; 1211 LITMUS_QUANTUM_LENGTH_NS;
1209 tsk_rt(&container_tasks[i])->task_params.budget_policy == PRECISE_ENFORCEMENT; 1212 tsk_rt(&container_tasks[i])->task_params.budget_policy = PRECISE_ENFORCEMENT;
1210 tsk_rt(&container_tasks[i])->edfsc_params.container_task = NULL; 1213 tsk_rt(&container_tasks[i])->edfsc_params.container_task = NULL;
1211 tsk_rt(&container_tasks[i])->domain = &gsched_domain; 1214 tsk_rt(&container_tasks[i])->domain = &gsched_domain;
1212 tsk_rt(&container_tasks[i])->edfsc_params.domain = &container_domains[i]; 1215 tsk_rt(&container_tasks[i])->edfsc_params.domain = &container_domains[i];