diff options
author | Zelin Tong <ztong@ludwig.cs.unc.edu> | 2020-02-27 18:02:33 -0500 |
---|---|---|
committer | Zelin Tong <ztong@ludwig.cs.unc.edu> | 2020-02-27 18:02:33 -0500 |
commit | fab953c864033c002675c79eab121291c324bee6 (patch) | |
tree | ba20846334f008b26591ac0a9fddfe79a092aa4b | |
parent | 25fb933628b3f3953fb8b6d206a0c53855a8bae9 (diff) |
Fixed accounting for empty container budget
-rw-r--r-- | litmus/sched_edfsc.c | 57 |
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]; |