diff options
| author | Zelin Tong <ztong@ludwig.cs.unc.edu> | 2020-06-01 13:26:51 -0400 |
|---|---|---|
| committer | Zelin Tong <ztong@ludwig.cs.unc.edu> | 2020-06-01 13:26:51 -0400 |
| commit | e4c5fa6df346a78dfb683d601fd5ad34e6de3375 (patch) | |
| tree | 90a7b4dcf891ec84c2f7ca4d32bb94d63cc12a2c | |
| parent | 1394cfe730e1e5030decc9990b37011a4957a7c0 (diff) | |
Final Fixes
Fixed jobs sometimes disappearing due to mysterious path in gschedule
where it is not requeued. This is done by first requeueing regardless,
and letting unlink dequeue as necessary.
Made container_boundary only try to stabilize when new tasks are
removed/added to the systed
| -rw-r--r-- | litmus/litmus_proc.c | 9 | ||||
| -rw-r--r-- | litmus/sched_edfsc.c | 129 |
2 files changed, 99 insertions, 39 deletions
diff --git a/litmus/litmus_proc.c b/litmus/litmus_proc.c index de5e3f37fe88..ebea92da0a3d 100644 --- a/litmus/litmus_proc.c +++ b/litmus/litmus_proc.c | |||
| @@ -31,13 +31,18 @@ static struct proc_dir_entry *litmus_dir = NULL, | |||
| 31 | /* in litmus/sync.c */ | 31 | /* in litmus/sync.c */ |
| 32 | int count_tasks_waiting_for_release(void); | 32 | int count_tasks_waiting_for_release(void); |
| 33 | 33 | ||
| 34 | /* in litmus/sched_edfsc.c */ | ||
| 35 | int count_migrating_tasks(void); | ||
| 36 | |||
| 34 | static int litmus_stats_proc_show(struct seq_file *m, void *v) | 37 | static int litmus_stats_proc_show(struct seq_file *m, void *v) |
| 35 | { | 38 | { |
| 36 | seq_printf(m, | 39 | seq_printf(m, |
| 37 | "real-time tasks = %d\n" | 40 | "real-time tasks = %d\n" |
| 38 | "ready for release = %d\n", | 41 | "ready for release = %d\n" |
| 42 | "migrating tasks = %d\n", | ||
| 39 | atomic_read(&rt_task_count), | 43 | atomic_read(&rt_task_count), |
| 40 | count_tasks_waiting_for_release()); | 44 | count_tasks_waiting_for_release(), |
| 45 | count_migrating_tasks()); | ||
| 41 | return 0; | 46 | return 0; |
| 42 | } | 47 | } |
| 43 | 48 | ||
diff --git a/litmus/sched_edfsc.c b/litmus/sched_edfsc.c index 8ae94f2dc1df..fae6feeac76f 100644 --- a/litmus/sched_edfsc.c +++ b/litmus/sched_edfsc.c | |||
| @@ -68,6 +68,9 @@ static rt_domain_t gsched_domain; | |||
| 68 | u64 m_util; | 68 | u64 m_util; |
| 69 | u64 sys_util; | 69 | u64 sys_util; |
| 70 | 70 | ||
| 71 | //only true when container_boundary needs to perform stabilization | ||
| 72 | int sys_changed; | ||
| 73 | |||
| 71 | #define is_container(task) ((task) && tsk_rt(task)->edfsc_params.domain != NULL && tsk_rt(task)->domain == &gsched_domain) | 74 | #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) | 75 | #define is_fixed(task) ((task) && tsk_rt(task)->edfsc_params.container_task != NULL) |
| 73 | #define is_migrating(task) ((task) && tsk_rt(task)->edfsc_params.domain == NULL && tsk_rt(task)->domain == &gsched_domain) | 76 | #define is_migrating(task) ((task) && tsk_rt(task)->edfsc_params.domain == NULL && tsk_rt(task)->domain == &gsched_domain) |
| @@ -83,6 +86,21 @@ void release_heap_free(struct release_heap* rh); | |||
| 83 | struct bheap_node* bheap_node_alloc(int gfp_flags); | 86 | struct bheap_node* bheap_node_alloc(int gfp_flags); |
| 84 | void bheap_node_free(struct bheap_node* hn); | 87 | void bheap_node_free(struct bheap_node* hn); |
| 85 | 88 | ||
| 89 | int count_migrating_tasks(void) | ||
| 90 | { | ||
| 91 | int task_count = 0; | ||
| 92 | struct list_head *pos; | ||
| 93 | unsigned long flags; | ||
| 94 | |||
| 95 | raw_spin_lock_irqsave(&g_lock, flags); | ||
| 96 | |||
| 97 | list_for_each(pos, &migrating_tasks) { | ||
| 98 | task_count++; | ||
| 99 | } | ||
| 100 | |||
| 101 | raw_spin_unlock_irqrestore(&g_lock, flags); | ||
| 102 | return task_count; | ||
| 103 | } | ||
| 86 | 104 | ||
| 87 | /* Do a backwards comparison based on f_util so that heavier containers | 105 | /* Do a backwards comparison based on f_util so that heavier containers |
| 88 | * will come first | 106 | * will come first |
| @@ -370,6 +388,7 @@ static void g_remove_task(struct task_struct *t) | |||
| 370 | BUG_ON(is_container(t)); | 388 | BUG_ON(is_container(t)); |
| 371 | m_util -= get_rt_utilization(t); | 389 | m_util -= get_rt_utilization(t); |
| 372 | sys_util -= get_rt_utilization(t); | 390 | sys_util -= get_rt_utilization(t); |
| 391 | sys_changed = 1; | ||
| 373 | } | 392 | } |
| 374 | 393 | ||
| 375 | static void c_remove_task(struct task_struct *t) | 394 | static void c_remove_task(struct task_struct *t) |
| @@ -378,6 +397,7 @@ static void c_remove_task(struct task_struct *t) | |||
| 378 | tsk_rt(container_task)->edfsc_params.domain->f_util -= | 397 | tsk_rt(container_task)->edfsc_params.domain->f_util -= |
| 379 | get_rt_utilization(t); | 398 | get_rt_utilization(t); |
| 380 | sys_util -= get_rt_utilization(t); | 399 | sys_util -= get_rt_utilization(t); |
| 400 | sys_changed = 1; | ||
| 381 | } | 401 | } |
| 382 | 402 | ||
| 383 | /** | 403 | /** |
| @@ -400,6 +420,7 @@ static void migrate_task(struct task_struct *t) | |||
| 400 | tsk_rt(t)->edfsc_params.container_task = tsk_rt(t)->edfsc_params.move_to->container; | 420 | tsk_rt(t)->edfsc_params.container_task = tsk_rt(t)->edfsc_params.move_to->container; |
| 401 | requeue(t); | 421 | requeue(t); |
| 402 | tsk_rt(t)->edfsc_params.move_to = NULL; | 422 | tsk_rt(t)->edfsc_params.move_to = NULL; |
| 423 | sys_changed = 1; | ||
| 403 | } | 424 | } |
| 404 | 425 | ||
| 405 | /** | 426 | /** |
| @@ -492,6 +513,7 @@ static noinline void g_job_completion(struct task_struct* t, int forced) | |||
| 492 | * tardy case, then just immediately call c_release() on the container. | 513 | * tardy case, then just immediately call c_release() on the container. |
| 493 | */ | 514 | */ |
| 494 | } else if (is_container(t)) { | 515 | } else if (is_container(t)) { |
| 516 | /* | ||
| 495 | struct task_struct** child = &tsk_rt(t)->edfsc_params.domain->scheduled; | 517 | struct task_struct** child = &tsk_rt(t)->edfsc_params.domain->scheduled; |
| 496 | // No need to handle fixed tasks, cschedule will do that when it runs next | 518 | // No need to handle fixed tasks, cschedule will do that when it runs next |
| 497 | if (*child && is_migrating(*child)) { | 519 | if (*child && is_migrating(*child)) { |
| @@ -509,6 +531,7 @@ static noinline void g_job_completion(struct task_struct* t, int forced) | |||
| 509 | // Regardless, we never "freeze" a migrating task in a container | 531 | // Regardless, we never "freeze" a migrating task in a container |
| 510 | *child = NULL; | 532 | *child = NULL; |
| 511 | } | 533 | } |
| 534 | */ | ||
| 512 | // When a container job finishes late, release it immediately | 535 | // When a container job finishes late, release it immediately |
| 513 | if (tsk_rt(t)->edfsc_params.can_release) { | 536 | if (tsk_rt(t)->edfsc_params.can_release) { |
| 514 | tsk_rt(t)->edfsc_params.can_release = 0; | 537 | tsk_rt(t)->edfsc_params.can_release = 0; |
| @@ -543,7 +566,8 @@ static void g_finish_switch(struct task_struct *prev) | |||
| 543 | // members of entry multiple times, we have to lock. Otherwise we | 566 | // members of entry multiple times, we have to lock. Otherwise we |
| 544 | // may make an if branch based off entry->linked, and then have it | 567 | // may make an if branch based off entry->linked, and then have it |
| 545 | // change before we can set entry->scheduled. | 568 | // change before we can set entry->scheduled. |
| 546 | raw_spin_lock_irqsave(&g_lock, flags); | 569 | //raw_spin_lock_irqsave(&g_lock, flags); |
| 570 | preempt_disable(); | ||
| 547 | entry->scheduled = is_realtime(current) ? current : NULL; | 571 | entry->scheduled = is_realtime(current) ? current : NULL; |
| 548 | // If we're scheduling a task in a container, set entry->scheduled to the container | 572 | // If we're scheduling a task in a container, set entry->scheduled to the container |
| 549 | if (entry->scheduled) { | 573 | if (entry->scheduled) { |
| @@ -557,13 +581,9 @@ static void g_finish_switch(struct task_struct *prev) | |||
| 557 | entry->scheduled = entry->linked; | 581 | entry->scheduled = entry->linked; |
| 558 | } | 582 | } |
| 559 | 583 | ||
| 560 | // This handles requeuing when a container is descheduled | 584 | BUG_ON(is_fixed(entry->scheduled)); |
| 561 | // TODO: Move this to edfsc_gschedule() | 585 | //raw_spin_unlock_irqrestore(&g_lock, flags); |
| 562 | if (!is_container(entry->scheduled) && tsk_rt(container)->edfsc_params.domain->scheduled) { | 586 | preempt_enable(); |
| 563 | requeue(tsk_rt(container)->edfsc_params.domain->scheduled); | ||
| 564 | tsk_rt(container)->edfsc_params.domain->scheduled = NULL; | ||
| 565 | } | ||
| 566 | raw_spin_unlock_irqrestore(&g_lock, flags); | ||
| 567 | #ifdef WANT_ALL_SCHED_EVENTS | 587 | #ifdef WANT_ALL_SCHED_EVENTS |
| 568 | TRACE_TASK(prev, "switched away from\n"); | 588 | TRACE_TASK(prev, "switched away from\n"); |
| 569 | #endif | 589 | #endif |
| @@ -595,7 +615,7 @@ static void edfsc_cschedule(cont_domain_t* cedf, struct task_struct * prev) | |||
| 595 | * differently from gedf, when a task exits (dead) | 615 | * differently from gedf, when a task exits (dead) |
| 596 | * cedf->schedule may be null and prev _is_ realtime | 616 | * cedf->schedule may be null and prev _is_ realtime |
| 597 | */ | 617 | */ |
| 598 | BUG_ON(cedf->scheduled && cedf->scheduled != prev && is_realtime(prev)); | 618 | //BUG_ON(cedf->scheduled && cedf->scheduled != prev && is_realtime(prev)); |
| 599 | BUG_ON(cedf->scheduled && !is_realtime(cedf->scheduled)); | 619 | BUG_ON(cedf->scheduled && !is_realtime(cedf->scheduled)); |
| 600 | 620 | ||
| 601 | /* (0) Determine state */ | 621 | /* (0) Determine state */ |
| @@ -605,7 +625,8 @@ static void edfsc_cschedule(cont_domain_t* cedf, struct task_struct * prev) | |||
| 605 | && budget_exhausted(cedf->scheduled); | 625 | && budget_exhausted(cedf->scheduled); |
| 606 | np = exists && is_np(cedf->scheduled); | 626 | np = exists && is_np(cedf->scheduled); |
| 607 | sleep = exists && is_completed(cedf->scheduled); | 627 | sleep = exists && is_completed(cedf->scheduled); |
| 608 | preempt = (is_migrating(prev) && __peek_ready(edf)) || edf_preemption_needed(edf, prev); | 628 | preempt = (is_migrating(cedf->scheduled) && __peek_ready(edf)) || |
| 629 | (exists && edf_preemption_needed(edf, cedf->scheduled)); | ||
| 609 | 630 | ||
| 610 | /* If we need to preempt do so. | 631 | /* If we need to preempt do so. |
| 611 | * The following checks set resched to 1 in case of special | 632 | * The following checks set resched to 1 in case of special |
| @@ -632,7 +653,7 @@ static void edfsc_cschedule(cont_domain_t* cedf, struct task_struct * prev) | |||
| 632 | } | 653 | } |
| 633 | 654 | ||
| 634 | // Deschedule any background jobs if a fixed task is ready | 655 | // Deschedule any background jobs if a fixed task is ready |
| 635 | if (is_migrating(cedf->scheduled) && preempt) { | 656 | if (is_migrating(cedf->scheduled) || preempt) { |
| 636 | if (!sleep && !out_of_time && !blocks && !is_queued(cedf->scheduled)) | 657 | if (!sleep && !out_of_time && !blocks && !is_queued(cedf->scheduled)) |
| 637 | requeue(cedf->scheduled); | 658 | requeue(cedf->scheduled); |
| 638 | resched = 1; | 659 | resched = 1; |
| @@ -644,6 +665,9 @@ static void edfsc_cschedule(cont_domain_t* cedf, struct task_struct * prev) | |||
| 644 | */ | 665 | */ |
| 645 | next = NULL; | 666 | next = NULL; |
| 646 | if (blocks || !exists || (!np && resched)) { | 667 | if (blocks || !exists || (!np && resched)) { |
| 668 | /*if (exists && !out_of_time && !sleep && !is_queued(cedf->scheduled)) { | ||
| 669 | requeue(cedf->scheduled); | ||
| 670 | }*/ | ||
| 647 | next = __take_ready(edf); | 671 | next = __take_ready(edf); |
| 648 | } else if (exists) { | 672 | } else if (exists) { |
| 649 | // This is safe when background scheduling, as we can only get here if | 673 | // This is safe when background scheduling, as we can only get here if |
| @@ -682,6 +706,7 @@ static struct task_struct *edfsc_gschedule(struct task_struct *prev) | |||
| 682 | int out_of_time, sleep, preempted, np, exists, blocks, is_cont; | 706 | int out_of_time, sleep, preempted, np, exists, blocks, is_cont; |
| 683 | unsigned long flags; | 707 | unsigned long flags; |
| 684 | struct task_struct* next = NULL; | 708 | struct task_struct* next = NULL; |
| 709 | struct task_struct* temp = NULL; | ||
| 685 | 710 | ||
