diff options
| author | Zelin Tong <ztong@ludwig.cs.unc.edu> | 2020-03-08 00:47:17 -0500 |
|---|---|---|
| committer | Zelin Tong <ztong@ludwig.cs.unc.edu> | 2020-03-08 00:47:17 -0500 |
| commit | c8a50bd6a68ba37ee433cbc8b245a089900f6638 (patch) | |
| tree | 67d2d2830f2366588b1730e6bfaa47d05ffec228 | |
| parent | 3a5267527b8ebe81a2a7d1f09832876dd6ec24f2 (diff) | |
Updated logic in utilization tracking
| -rw-r--r-- | litmus/sched_edfsc.c | 74 |
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; | |||
| 65 | static rt_domain_t gsched_domain; | 65 | static rt_domain_t gsched_domain; |
| 66 | #define g_lock (gsched_domain.ready_lock) | 66 | #define g_lock (gsched_domain.ready_lock) |
| 67 | 67 | ||
| 68 | u64 m_util, future_m_util; | 68 | u64 m_util; |
| 69 | u64 sys_util, future_sys_util; | 69 | u64 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); | |||
| 84 | void bheap_node_free(struct bheap_node* hn); | 84 | void 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 | */ |
| 90 | static int container_lower_prio(const void *_a, const void *_b) | 90 | static 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 | ||
| 432 | static void c_remove_task(struct task_struct *t) | 423 | static 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 | */ |
| 447 | static void migrate_task(struct task_struct *t) | 436 | static 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)) |
