aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZelin Tong <ztong@ludwig.cs.unc.edu>2020-03-08 00:47:17 -0500
committerZelin Tong <ztong@ludwig.cs.unc.edu>2020-03-08 00:47:17 -0500
commitc8a50bd6a68ba37ee433cbc8b245a089900f6638 (patch)
tree67d2d2830f2366588b1730e6bfaa47d05ffec228
parent3a5267527b8ebe81a2a7d1f09832876dd6ec24f2 (diff)
Updated logic in utilization tracking
-rw-r--r--litmus/sched_edfsc.c74
1 files changed, 36 insertions, 38 deletions
diff --git a/litmus/sched_edfsc.c b/litmus/sched_edfsc.c
index e90cfc7b3485..c3c6dddc9eb2 100644
--- a/litmus/sched_edfsc.c
+++ b/litmus/sched_edfsc.c
@@ -30,7 +30,7 @@ typedef struct cont_domain {
30 struct task_struct *scheduled; //fixed task 30 struct task_struct *scheduled; //fixed task
31 lt_t scheduled_last_exec_time; //exec_time of the scheduled task when it was last scheduled 31 lt_t scheduled_last_exec_time; //exec_time of the scheduled task when it was last scheduled
32 lt_t changed_budget; //change to scheduled task's exec time due to container budget constraints 32 lt_t changed_budget; //change to scheduled task's exec time due to container budget constraints
33 u64 f_util, future_f_util; 33 u64 f_util;
34 struct bheap_node *hn; 34 struct bheap_node *hn;
35 struct hrtimer idle_enforcement_timer; 35 struct hrtimer idle_enforcement_timer;
36 int timer_armed; 36 int timer_armed;
@@ -65,8 +65,8 @@ static cont_domain_t** container_list;
65static rt_domain_t gsched_domain; 65static rt_domain_t gsched_domain;
66#define g_lock (gsched_domain.ready_lock) 66#define g_lock (gsched_domain.ready_lock)
67 67
68u64 m_util, future_m_util; 68u64 m_util;
69u64 sys_util, future_sys_util; 69u64 sys_util;
70 70
71#define is_container(task) ((task) && tsk_rt(task)->edfsc_params.domain != NULL && tsk_rt(task)->domain == &gsched_domain) 71#define is_container(task) ((task) && tsk_rt(task)->edfsc_params.domain != NULL && tsk_rt(task)->domain == &gsched_domain)
72#define is_fixed(task) ((task) && tsk_rt(task)->edfsc_params.container_task != NULL) 72#define is_fixed(task) ((task) && tsk_rt(task)->edfsc_params.container_task != NULL)
@@ -84,15 +84,15 @@ struct bheap_node* bheap_node_alloc(int gfp_flags);
84void bheap_node_free(struct bheap_node* hn); 84void bheap_node_free(struct bheap_node* hn);
85 85
86 86
87/* Do a backwards comparison based on future_f_util so that heavier containers 87/* Do a backwards comparison based on f_util so that heavier containers
88 * will come first 88 * will come first
89 */ 89 */
90static int container_lower_prio(const void *_a, const void *_b) 90static int container_lower_prio(const void *_a, const void *_b)
91{ 91{
92 const cont_domain_t *a = (const cont_domain_t *)(_a); 92 const cont_domain_t *a = (const cont_domain_t *)(_a);
93 const cont_domain_t *b = (const cont_domain_t *)(_b); 93 const cont_domain_t *b = (const cont_domain_t *)(_b);
94 if (a->future_f_util < b->future_f_util) return 1; 94 if (a->f_util < b->f_util) return 1;
95 if (a->future_f_util > b->future_f_util) return -1; 95 if (a->f_util > b->f_util) return -1;
96 return 0; 96 return 0;
97} 97}
98 98
@@ -417,16 +417,7 @@ static void g_remove_task(struct task_struct *t)
417{ 417{
418 BUG_ON(is_container(t)); 418 BUG_ON(is_container(t));
419 m_util -= get_rt_utilization(t); 419 m_util -= get_rt_utilization(t);
420 future_m_util -= get_rt_utilization(t); 420 sys_util -= get_rt_utilization(t);
421 future_sys_util -= get_rt_utilization(t);
422 if (tsk_rt(t)->edfsc_params.move_to) {
423 prepare_for_next_period(t);
424 tsk_rt(t)->domain = (rt_domain_t*)tsk_rt(t)->edfsc_params.move_to;
425 tsk_rt(t)->edfsc_params.container_task = tsk_rt(t)->edfsc_params.move_to->container;
426 requeue(t);
427 tsk_rt(t)->edfsc_params.move_to->f_util += get_rt_utilization(t);
428 tsk_rt(t)->edfsc_params.move_to = NULL;
429 }
430} 421}
431 422
432static void c_remove_task(struct task_struct *t) 423static void c_remove_task(struct task_struct *t)
@@ -434,29 +425,28 @@ static void c_remove_task(struct task_struct *t)
434 struct task_struct* container_task = tsk_rt(t)->edfsc_params.container_task; 425 struct task_struct* container_task = tsk_rt(t)->edfsc_params.container_task;
435 tsk_rt(container_task)->edfsc_params.domain->f_util -= 426 tsk_rt(container_task)->edfsc_params.domain->f_util -=
436 get_rt_utilization(t); 427 get_rt_utilization(t);
437 tsk_rt(container_task)->edfsc_params.domain->future_f_util -= 428 sys_util -= get_rt_utilization(t);
438 get_rt_utilization(t);
439 future_sys_util -= get_rt_utilization(t);
440} 429}
441 430
442/** 431/**
443 * Remove a task from it's current domain and put it in a different domain. 432 * Remove a task from it's current domain and put it in a different domain.
444 * Must be called at the greater time of job completion and deadline to respect 433 * Must be called at the greater time of job completion and deadline to respect
445 * EDF-sc invariants. 434 * EDF-sc invariants. Can only go from migrating to fixed task.
446 */ 435 */
447static void migrate_task(struct task_struct *t) 436static void migrate_task(struct task_struct *t)
448{ 437{
449 BUG_ON(!t); 438 BUG_ON(!t);
450 BUG_ON(is_container(t)); 439 BUG_ON(is_container(t) || is_fixed(t));
451 BUG_ON(!tsk_rt(t)->edfsc_params.move_to); 440 BUG_ON(!tsk_rt(t)->edfsc_params.move_to);
452 441
453 if (is_queued(t)) 442 if (is_queued(t))
454 remove(tsk_rt(t)->domain, t); 443 remove(tsk_rt(t)->domain, t);
455 if (is_fixed(t)) { 444 // Remove the util of the "fake reservation task"(specified by the paper) from the system
456 c_remove_task(t); 445 sys_util -= get_rt_utilization(t);
457 } else { 446 prepare_for_next_period(t);
458 g_remove_task(t); 447 tsk_rt(t)->domain = (rt_domain_t*)tsk_rt(t)->edfsc_params.move_to;
459 } 448 tsk_rt(t)->edfsc_params.container_task = tsk_rt(t)->edfsc_params.move_to->container;
449 requeue(t);
460 tsk_rt(t)->edfsc_params.move_to = NULL; 450 tsk_rt(t)->edfsc_params.move_to = NULL;
461} 451}
462 452
@@ -918,7 +908,7 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
918 t = task_of_list_node(it); 908 t = task_of_list_node(it);
919 if (u_extra >= get_rt_utilization(t)) { 909 if (u_extra >= get_rt_utilization(t)) {
920 for (i = 0; i < num_cpus; i++) { 910 for (i = 0; i < num_cpus; i++) {
921 u64 leftover = to_fp(1) - container_domains[i].future_f_util 911 u64 leftover = to_fp(1) - container_domains[i].f_util
922 - get_rt_utilization(t); 912 - get_rt_utilization(t);
923 if (leftover >= 0) { 913 if (leftover >= 0) {
924 container = &(container_domains[i]); 914 container = &(container_domains[i]);
@@ -930,17 +920,14 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
930 tsk_rt(t)->domain = (rt_domain_t*)container; 920 tsk_rt(t)->domain = (rt_domain_t*)container;
931 tsk_rt(t)->edfsc_params.container_task = container->container; 921 tsk_rt(t)->edfsc_params.container_task = container->container;
932 container->f_util += get_rt_utilization(t); 922 container->f_util += get_rt_utilization(t);
933 container->future_f_util += get_rt_utilization(t);
934 } else { 923 } else {
935 tsk_rt(t)->domain = &gsched_domain; 924 tsk_rt(t)->domain = &gsched_domain;
936 tsk_rt(t)->edfsc_params.container_task = NULL; 925 tsk_rt(t)->edfsc_params.container_task = NULL;
937 m_util += get_rt_utilization(t); 926 m_util += get_rt_utilization(t);
938 future_m_util += get_rt_utilization(t);
939 //list_add(&tsk_rt(t)->edfsc_params.qnode, &migrating_tasks); 927 //list_add(&tsk_rt(t)->edfsc_params.qnode, &migrating_tasks);
940 list_add(&t->edfsc_qnode, &migrating_tasks); 928 list_add(&t->edfsc_qnode, &migrating_tasks);
941 } 929 }
942 sys_util += get_rt_utilization(t); 930 sys_util += get_rt_utilization(t);
943 future_sys_util += get_rt_utilization(t);
944 need_reweight = 1; 931 need_reweight = 1;
945 // Setup the release time for the first job to be now 932 // Setup the release time for the first job to be now
946 release_at(t, litmus_clock()); 933 release_at(t, litmus_clock());
@@ -965,25 +952,35 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
965 // migrating tasks and potentially all the containers every period for a 952 // migrating tasks and potentially all the containers every period for a
966 // best-case Omega(m) and worst-case O(m^2) work---only once the scheduler 953 // best-case Omega(m) and worst-case O(m^2) work---only once the scheduler
967 // is actually working 954 // is actually working
955 // According to the paper, when we migrate, we must reserve space in the container
956 // We do this by adding a fake task that ultimately doesn't release any jobs
957 // This is represented here by adding the utilization to sys_util
958 // which will be subtracted when the migrating task is actually changed to fixed
968 list_for_each(it, &migrating_tasks) { 959 list_for_each(it, &migrating_tasks) {
969 struct task_struct* t = task_of_list_node(it); 960 struct task_struct* t = task_of_list_node(it);
961 // Although technically selecting the migrating tasks to be moved into containers
962 // doesn't change m_util and the container's f_util until after the move,
963 // but since the move is guaranteed to happen before the next container_boundary
964 // where we check all the utilization stuff, it's fine to account for it now
970 if (!(tsk_rt(t)->edfsc_params.move_to) && !is_released(t, now) 965 if (!(tsk_rt(t)->edfsc_params.move_to) && !is_released(t, now)
971 && get_deadline(t) < get_deadline(&container_tasks[0]) + get_rt_period(&container_tasks[0])) { 966 && get_deadline(t) < get_deadline(&container_tasks[0]) + get_rt_period(&container_tasks[0])) {
972 tsk_rt(t)->edfsc_params.move_to = NULL; 967 tsk_rt(t)->edfsc_params.move_to = NULL;
973 968
974 container = NULL; 969 container = NULL;
975 for (i = 0; i < num_cpus; i++) { 970 for (i = 0; i < num_cpus; i++) {
976 u64 leftover = to_fp(1) - container_domains[i].future_f_util 971 u64 leftover = to_fp(1) - container_domains[i].f_util
977 - get_rt_utilization(t); 972 - get_rt_utilization(t);
978 if (leftover >= 0) { 973 u_extra = to_fp(num_cpus) - sys_util;
974 if (leftover >= to_fp(0) && u_extra >= get_rt_utilization(t)) {
979 container = &(container_domains[i]); 975 container = &(container_domains[i]);
980 break; 976 break;
981 } 977 }
982 } 978 }
983 979
984 if (container) { 980 if (container) {
985 container->future_f_util += get_rt_utilization(t); 981 container->f_util += get_rt_utilization(t);
986 future_sys_util += get_rt_utilization(t); 982 m_util -= get_rt_utilization(t);
983 sys_util += get_rt_utilization(t);
987 tsk_rt(t)->edfsc_params.move_to = container; 984 tsk_rt(t)->edfsc_params.move_to = container;
988 need_reweight = 1; 985 need_reweight = 1;
989 } 986 }
@@ -995,12 +992,12 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
995 int remaining; 992 int remaining;
996 // Sort containers by the utilization of their fixed tasks 993 // Sort containers by the utilization of their fixed tasks
997 sort(container_list, num_cpus, sizeof(cont_domain_t *), &container_lower_prio, NULL); 994 sort(container_list, num_cpus, sizeof(cont_domain_t *), &container_lower_prio, NULL);
998 u_extra = to_fp(num_cpus) - future_sys_util; 995 u_extra = to_fp(num_cpus) - sys_util;
999 // Fully provision all the container tasks we can 996 // Fully provision all the container tasks we can
1000 for (i = 0; i < num_cpus && u_extra >= to_fp(1) - container_list[i]->future_f_util; i++) { 997 for (i = 0; i < num_cpus && u_extra >= to_fp(1) - container_list[i]->f_util; i++) {
1001 struct task_struct* t = container_list[i]->container; 998 struct task_struct* t = container_list[i]->container;
1002 tsk_rt(t)->task_params.utilization = to_fp(1); 999 tsk_rt(t)->task_params.utilization = to_fp(1);
1003 u_extra -= to_fp(1) - container_list[i]->future_f_util; 1000 u_extra -= to_fp(1) - container_list[i]->f_util;
1004 } 1001 }
1005 // Split the extra capacity between the remaining container tasks 1002 // Split the extra capacity between the remaining container tasks
1006 // XXX this is actually dangerous as hell, right? Since overheads are 1003 // XXX this is actually dangerous as hell, right? Since overheads are
@@ -1016,7 +1013,7 @@ static enum hrtimer_restart container_boundary(struct hrtimer *timer)
1016 remaining = num_cpus - i; 1013 remaining = num_cpus - i;
1017 for (; i < num_cpus; i++) { 1014 for (; i < num_cpus; i++) {
1018 struct task_struct* t = container_list[i]->container; 1015 struct task_struct* t = container_list[i]->container;
1019 tsk_rt(t)->task_params.utilization = container_list[i]->future_f_util + u_extra / remaining; 1016 tsk_rt(t)->task_params.utilization = container_list[i]->f_util + u_extra / remaining;
1020 } 1017 }
1021 } 1018 }
1022 1019
@@ -1053,6 +1050,7 @@ static enum hrtimer_restart task_deadline_callback(struct hrtimer* timer) {
1053 struct task_struct *t = container_of(timer, struct task_struct, edfsc_deadline_timer); 1050 struct task_struct *t = container_of(timer, struct task_struct, edfsc_deadline_timer);
1054 1051
1055 BUG_ON(is_container(t)); 1052 BUG_ON(is_container(t));
1053 // This is true only if set to be migrating from container_boundary
1056 if (tsk_rt(t)->edfsc_params.move_to) { 1054 if (tsk_rt(t)->edfsc_params.move_to) {
1057 // Migrate here if the task is not late, otherwise migrate in job_complete 1055 // Migrate here if the task is not late, otherwise migrate in job_complete
1058 if (!is_released(t, litmus_clock()) || budget_exhausted(t)) 1056 if (!is_released(t, litmus_clock()) || budget_exhausted(t))