SCHED_DEADLINE server infrastructure
Subsystems (5)
v7 cover SCHED_DEADLINE server infrastructure
This is v7 of Peter's SCHED_DEADLINE server infrastructure implementation [1].
SCHED_DEADLINE servers can help fixing starvation issues of low priority tasks (e.g., SCHED_OTHER) when higher priority tasks monopolize CPU cycles. Today we have RT Throttling; DEADLINE servers should be able to replace and improve that.
In the v1 there was discussion raised about the consequence of using deadline based servers on the fixed-priority workloads. For a demonstration here is the baseline of timerlat scheduling latency as-is, with kernel build background workload:
# rtla timerlat top -u -d 10m
--------------------- %< ------------------------
Timer Latency
0 01:42:24 | IRQ Timer Latency (us) | Thread Timer Latency (us) | Ret user Timer Latency (us) CPU COUNT | cur min avg max | cur min avg max | cur min avg max 0 #6143559 | 0 0 0 92 | 2 1 3 98 | 4 1 5 100 1 #6143559 | 1 0 0 97 | 7 1 5 101 | 9 1 7 103 2 #6143559 | 0 0 0 88 | 3 1 5 95 | 5 1 7 99 3 #6143559 | 0 0 0 90 | 6 1 5 103 | 10 1 7 126 4 #6143558 | 1 0 0 81 | 7 1 4 86 | 9 1 7 90 5 #6143558 | 0 0 0 74 | 3 1 5 79 | 4 1 7 83 6 #6143558 | 0 0 0 83 | 2 1 5 89 | 3 0 7 108 7 #6143558 | 0 0 0 85 | 3 1 4 126 | 5 1 6 137
--------------------- >% ------------------------
And this is the same tests with DL server activating without any delay:
--------------------- %< ------------------------
0 00:10:01 | IRQ Timer Latency (us) | Thread Timer Latency (us) | Ret user Timer Latency (us) CPU COUNT | cur min avg max | cur min avg max | cur min avg max 0 #579147 | 0 0 0 54 | 2 1 52 61095 | 2 2 56 61102 1 #578766 | 0 0 0 83 | 2 1 49 55824 | 3 2 53 55831 2 #578559 | 0 0 1 59 | 2 1 50 55760 | 3 2 54 55770 3 #578318 | 0 0 0 76 | 2 1 49 55751 | 3 2 54 55760 4 #578611 | 0 0 0 64 | 2 1 49 55811 | 3 2 53 55820 5 #578347 | 0 0 1 40 | 2 1 50 56121 | 3 2 55 56133 6 #578938 | 0 0 1 75 | 2 1 49 55755 | 3 2 53 55764 7 #578631 | 0 0 1 36 | 3 1 51 55528 | 4 2 55 55541
--------------------- >% ------------------------
The problem with DL server only implementation is that FIFO tasks might suffer preemption from NORMAL even when spare CPU cycles are available. In fact, fair deadline server is enqueued right away when NORMAL tasks wake up and they are first scheduled by the server, thus potentially preempting a well behaving FIFO task. This is of course not ideal.
We had discussions about it, and one of the possibilities would be using a different scheduling algorithm for this. But IMHO that is an overkill.
Juri and I discussed this and though about delaying the server activation for the (period - runtime), thus enabling the server only if the fair scheduler is about to starve. We called it the defer server.
The defer the server start to the (absolute deadline - runtime) point in time. This is achieved by starting the dl server throttled, with a next replenishing time set to activate the server at (absolute deadline - runtime).
The server is enqueued with the runtime replenished. As the fair scheduler runs without boost, its runtime is consumed. If the fair server has its runtime before the runtime - deadline time, the a new period is set, and the timer armed for the new deadline.
The interface is per CPU and has two knobs:
fair_server_runtime (950 ms)
fair_server_period (1s)
With defer enabled on CPUs [0:3], the results get better, having a behavior similar to the one we have with the rt throttling.
--------------------- %< ------------------------
Timer Latency
0 00:10:01 | IRQ Timer Latency (us) | Thread Timer Latency (us) | Ret user Timer Latency (us) CPU COUNT | cur min avg max | cur min avg max | cur min avg max 0 #599979 | 0 0 0 64 | 4 1 4 67 | 6 1 5 69 1 #599979 | 0 0 1 17 | 6 1 5 50 | 10 2 7 71 2 #599984 | 1 0 1 22 | 4 1 5 78 | 5 2 7 107 3 #599986 | 0 0 1 72 | 7 1 5 79 | 10 2 7 82 4 #581580 | 1 0 1 37 | 6 1 38 52797 | 10 2 41 52805 5 #583270 | 1 0 1 41 | 9 1 36 52617 | 12 2 38 52623 6 #581240 | 0 0 1 25 | 7 1 39 52870 | 11 2 41 52876 7 #581208 | 0 0 1 69 | 6 1 39 52917 | 9 2 41 52923
--------------------- >% ------------------------
Here are some osnoise measurement, with osnoise threads running as FIFO:1 with different setups (defer enabled):
- CPU 2 isolated
- CPU 3 isolated shared with a CFS busy loop task
- CPU 8 non-isolated
- CPU 9 non-isolated shared with a CFS busy loop task
--------------------- %< ------------------------
~# pgrep ktimer | while read pid; do chrt -p -f 2 $pid; done # for RT kernel ~# tuna isolate -c 2
~# tuna isolate -c 3
~# taskset -c 3 ./f &
~# taskset -c 9 ./f &
~# osnoise -P f:1 -c 2,3,8,9 -T 1 -d 10m -H 1
Operating System Noise
duration: 0 00:10:00 | time is in us
CPU Period Runtime Noise % CPU Aval Max Noise Max Single HW NMI IRQ Softirq Thread
2 #599 599000000 178 99.99997 18 2 0 0 270 0 0 3 #598 598054434 31351553 94.75774 104442 104442 0 0 2837523 0 1794 8 #599 599000001 567456 99.90526 3260 2375 2 89 620490 0 13539 9 #598 598021196 31742537 94.69207 71707 53357 0 90 3411023 0 1762
--------------------- >% ------------------------
the system runs fine!
- no crashes (famous last words)
- FIFO property is kept
- per cpu interface because it is more flexible - and to detach this from the throttling concept.
In addition:
- This version is on my korg repo for three weeks without any 0 robot compaining.
- no regressions found on basic cfs tests, like kernel compilation.
- also tested with PREEMPT_RT 6.9-rt.
Global breaks only if the fair server activates (which is fair as RT tasks are not behaving anyways).
The selftest mentioned in the sched/core patches is here:
https://lore.kernel.org/all/[email protected]/
Thanks people at google for testing/suggesting:
- Suleiman Souhlal <[email protected]>
- Youssef Esmat <[email protected]>
- Joel Fernandes (Google) <[email protected]>
- Vineeth Pillai <[email protected]>
Changes from v6:
- Rebased on top of v6.10-rc1
- Improved comments (Daniel)
- Fix division by 0 on adding bw to the rq (Daniel)
- Use guard and scoped_guard (Peter)
- Remove the defer knob (Peter)
- Adjusted comments and code styling (Peter)
- Be aware of cfs throttling (Vineeth)
- Split the fixes and the feature from the basic fair server (Peter)
Changes from V5:
- Fixes DL server for core scheduling (patches 3 and 4) (Joel/Vineeth/Suleiman)
- Add a function to attach the fair server bandwidth to the
new root domain when the rq changes root domain (Daniel)
- Postpone the replenishment timer of the server if the defer reservation could consume runtime while waiting to boost (patch 2) (Daniel)
- Add the running state to defer mode avoid forcing the defer mechanism if the server continues to be activated due to starvation (patch 2) (Daniel)
- Consider idle time as time for the defer server to avoid penalty on RT tasks (patch 2) (Daniel)
- Mark DL server as unthrottled before enqueue (patch 2)(Joel)
- Make start_dl_timer callers more robust (patch 2) (Joel)
- Do not restart the DL server on replenish from timer (patch 2)(Joel)
- Fix Reverse args to dl_time_before in replenish (patch 2) (Suleiman Souhlal)
- Removed the negative runtime optimization (patch 2)
- Start the dl server as disabled in patch 1, enabling it only after removing the RT throttling, to avoid having two mechanism together by default (patch 1) (Daniel).
- Added a check need resched after dl_server_start (patch 1) (Daniel)
- reset dl_server pointer at put_prev_task_balance (patch 1) (Joel)
- Do not include the already merged patches
- Rebased to 6.9-rc2
Changes from V4:
- Enable the server when nr fair tasks is > 0 (peter)
- Consume runtime if the zerolax server is not boosted (peterz)
- Adjust interface to deal with admission control (peterz)
- Rebased to 6.6
Changes from V3:
- Add the defer server (Daniel)
- Add an per rq interface (Daniel with peter's feedback)
- Add an option not defer the server
- Typos and 1-liner fixes (Valentin, Luca, Peter)
- Fair scheduler running on dl server do not account as RT task (Daniel)
- Changed the condition to enable the server (RT & fair tasks) (Daniel)
Changes from v2:
- Refactor/rephrase/typos changes
- Defferable server using throttling
- The server starts when RT && Fair tasks are enqueued
- Interface with runtime/period/defer option
Changes from v1:
- rebased on 6.4-rc1 tip/sched/core
Daniel Bristot de Oliveira (3):
sched/deadline: Comment sched_dl_entity::dl_server variable sched/deadline: Deferrable dl server
sched/fair: Fair server interface
Joel Fernandes (Google) (3):
sched/core: Add clearing of ->dl_server in put_prev_task_balance() sched/core: Fix priority checking for DL server picks sched/core: Fix picking of tasks for core scheduling with DL server
Peter Zijlstra (2):
sched/fair: Add trivial fair server
sched/rt: Remove default bandwidth control
Youssef Esmat (1):
sched/core: Clear prev->dl_server in CFS pick fast path
include/linux/sched.h | 17 +- kernel/sched/core.c | 56 +++-- kernel/sched/deadline.c | 449 ++++++++++++++++++++++++++++++++++------ kernel/sched/debug.c | 162 +++++++++++++++ kernel/sched/fair.c | 75 ++++++- kernel/sched/idle.c | 2 + kernel/sched/rt.c | 242 ++++++++++------------ kernel/sched/sched.h | 17 +- kernel/sched/topology.c | 8 + 9 files changed, 813 insertions(+), 215 deletions(-)
Signature · 1 line
2.45.1
PATCH v7 1/9 sched/deadline: Comment sched_dl_entity::dl_server variable
Add an explanation for the newly added variable.
--- include/linux/sched.h | 2 ++ 1 file changed, 2 insertions(+)
include/linux/sched.h +2 -0
@@ -637,6 +637,8 @@ struct sched_dl_entity {* * @dl_overrun tells if the task asked to be informed about runtime * overruns. +* +* @dl_server tells if this is a server entity. */ unsigned int dl_throttled : 1; unsigned int dl_yielded : 1;
Signature · 1 line
2.45.1
[tip: sched/core] sched/deadline: Comment sched_dl_entity::dl_server variable
The following commit has been merged into the sched/core branch of tip:
The following commit has been merged into the sched/core branch of tip:
Commit-ID: f23c042ce34ba265cf3129d530702b5d218e3f4b Gitweb: https://git.kernel.org/tip/f23c042ce34ba265cf3129d530702b5d218e3f4b Author: Daniel Bristot de Oliveira <[email protected]> AuthorDate: Mon, 27 May 2024 14:06:47 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 29 Jul 2024 12:22:35 +02:00
sched/deadline: Comment sched_dl_entity::dl_server variable
Add an explanation for the newly added variable.
--- include/linux/sched.h | 2 ++ 1 file changed, 2 insertions(+)
include/linux/sched.h +2 -0
@@ -639,6 +639,8 @@ struct sched_dl_entity {* * @dl_overrun tells if the task asked to be informed about runtime * overruns. +* +* @dl_server tells if this is a server entity. */ unsigned int dl_throttled : 1; unsigned int dl_yielded : 1;
PATCH v7 2/9 sched/core: Add clearing of ->dl_server in put_prev_task_balance()
In reply to Daniel Bristot de OliveiraFrom: "Joel Fernandes (Google)" <[email protected]>
Paths using put_prev_task_balance() need to do a pick shortly after. Make sure they also clear the ->dl_server on prev as a part of that.
--- kernel/sched/core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
kernel/sched/core.c +8 -8
@@ -6006,6 +6006,14 @@ static void put_prev_task_balance(struct rq *rq, struct task_struct *prev,#endif put_prev_task (rq, prev); + +/* +* We've updated @prev and no longer need the server link, clear it. +* Must be done before ->pick_next_task() because that can (re)set +* ->dl_server. +*/ +if (prev->dl_server) + prev->dl_server =NULL ; }/*
@@ -6049,14 +6057,6 @@ __pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) restart:put_prev_task_balance (rq, prev, rf); -/* -* We've updated @prev and no longer need the server link, clear it. -* Must be done before ->pick_next_task() because that can (re)set -* ->dl_server. -*/ -if (prev->dl_server) - prev->dl_server =NULL ; -for_each_class (class) { p = class->pick_next_task (rq);if (p)
Signature · 1 line
2.45.1
[tip: sched/core] sched/core: Add clearing of ->dl_server in put_prev_task_balance()
The following commit has been merged into the sched/core branch of tip:
The following commit has been merged into the sched/core branch of tip:
Commit-ID: c245910049d04fbfa85bb2f5acd591c24e9907c7 Gitweb: https://git.kernel.org/tip/c245910049d04fbfa85bb2f5acd591c24e9907c7 Author: Joel Fernandes (Google) <[email protected]> AuthorDate: Mon, 27 May 2024 14:06:48 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 29 Jul 2024 12:22:35 +02:00
sched/core: Add clearing of ->dl_server in put_prev_task_balance()
Paths using put_prev_task_balance() need to do a pick shortly after. Make sure they also clear the ->dl_server on prev as a part of that.
--- kernel/sched/core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
kernel/sched/core.c +8 -8
@@ -5801,6 +5801,14 @@ static void put_prev_task_balance(struct rq *rq, struct task_struct *prev,#endif put_prev_task (rq, prev); + +/* +* We've updated @prev and no longer need the server link, clear it. +* Must be done before ->pick_next_task() because that can (re)set +* ->dl_server. +*/ +if (prev->dl_server) + prev->dl_server =NULL ; }/*
@@ -5844,14 +5852,6 @@ __pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) restart:put_prev_task_balance (rq, prev, rf); -/* -* We've updated @prev and no longer need the server link, clear it. -* Must be done before ->pick_next_task() because that can (re)set -* ->dl_server. -*/ -if (prev->dl_server) - prev->dl_server =NULL ; -for_each_class (class) { p = class->pick_next_task (rq);if (p)
PATCH v7 3/9 sched/core: Clear prev->dl_server in CFS pick fast path
In reply to Daniel Bristot de OliveiraFrom: Youssef Esmat <[email protected]>
In case the previous pick was a DL server pick, ->dl_server might be set. Clear it in the fast path as well.
--- kernel/sched/core.c | 7 +++++++ 1 file changed, 7 insertions(+)
kernel/sched/core.c +7 -0
@@ -6044,6 +6044,13 @@ __pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) p =pick_next_task_idle (rq); } +/* +* This is a normal CFS pick, but the previous could be a DL pick. +* Clear it as previous is no longer picked. +*/ +if (prev->dl_server) + prev->dl_server =NULL ; +/* * This is the fast path; it cannot be a DL server pick; * therefore even if @p == @prev, ->dl_server must be NULL.
Signature · 1 line
2.45.1
[tip: sched/core] sched/core: Clear prev->dl_server in CFS pick fast path
The following commit has been merged into the sched/core branch of tip:
The following commit has been merged into the sched/core branch of tip:
Commit-ID: a741b82423f41501e301eb6f9820b45ca202e877 Gitweb: https://git.kernel.org/tip/a741b82423f41501e301eb6f9820b45ca202e877 Author: Youssef Esmat <[email protected]> AuthorDate: Mon, 27 May 2024 14:06:49 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 29 Jul 2024 12:22:35 +02:00
sched/core: Clear prev->dl_server in CFS pick fast path
In case the previous pick was a DL server pick, ->dl_server might be set. Clear it in the fast path as well.
--- kernel/sched/core.c | 7 +++++++ 1 file changed, 7 insertions(+)
kernel/sched/core.c +7 -0
@@ -5840,6 +5840,13 @@ __pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) }/* +* This is a normal CFS pick, but the previous could be a DL pick. +* Clear it as previous is no longer picked. +*/ +if (prev->dl_server) + prev->dl_server =NULL ; + +/* * This is the fast path; it cannot be a DL server pick; * therefore even if @p == @prev, ->dl_server must be NULL. */
PATCH v7 4/9 sched/fair: Add trivial fair server
In reply to Daniel Bristot de OliveiraFrom: Peter Zijlstra <[email protected]>
Use deadline servers to service fair tasks.
This patch adds a fair_server deadline entity which acts as a container for fair entities and can be used to fix starvation when higher priority (wrt fair) tasks are monopolizing CPU(s).
--- kernel/sched/core.c | 1 + kernel/sched/deadline.c | 23 +++++++++++++++++++++++ kernel/sched/fair.c | 34 ++++++++++++++++++++++++++++++++++ kernel/sched/sched.h | 4 ++++ 4 files changed, 62 insertions(+)
kernel/sched/core.c +1 -0
@@ -10057,6 +10057,7 @@ void __init sched_init(void)#endif /* CONFIG_SMP */ hrtick_rq_init (rq);atomic_set (&rq->nr_iowait,0 ); +fair_server_init (rq);#ifdef CONFIG_SCHED_CORE rq->core = rq;
kernel/sched/deadline.c +23 -0
@@ -1381,6 +1381,13 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64resched_curr (rq); } +/* +* The fair server (sole dl_server) does not account for real-time +* workload because it is running fair work. +*/ +if (dl_se == &rq->fair_server) +return ; +/* * Because -- for now -- we share the rt bandwidth, we need to * account our runtime there too, otherwise actual rt tasks
@@ -1414,15 +1421,31 @@ void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec)void dl_server_start (struct sched_dl_entity *dl_se) { +struct rq *rq = dl_se->rq; +if (!dl_server (dl_se)) { +/* Disabled */ + dl_se->dl_runtime =0 ; + dl_se->dl_deadline =1000 *NSEC_PER_MSEC ; + dl_se->dl_period =1000 *NSEC_PER_MSEC ; + dl_se->dl_server =1 ;setup_new_dl_entity (dl_se); } + +if (!dl_se->dl_runtime) +return ; +enqueue_dl_entity (dl_se,ENQUEUE_WAKEUP ); +if (!dl_task (dl_se->rq->curr) ||dl_entity_preempt (dl_se, &rq->curr->dl)) +resched_curr (dl_se->rq); }void dl_server_stop (struct sched_dl_entity *dl_se) { +if (!dl_se->dl_runtime) +return ; +dequeue_dl_entity (dl_se,DEQUEUE_SLEEP ); }
kernel/sched/fair.c +34 -0
@@ -5766,6 +5766,7 @@ static bool throttle_cfs_rq(struct cfs_rq *cfs_rq)struct cfs_bandwidth *cfs_b =tg_cfs_bandwidth (cfs_rq->tg);struct sched_entity *se;long task_delta, idle_task_delta, dequeue =1 ; +long rq_h_nr_running = rq->cfs.h_nr_running;raw_spin_lock (&cfs_b->lock);/* This will start the period timer if necessary */
@@ -5838,6 +5839,9 @@ static bool throttle_cfs_rq(struct cfs_rq *cfs_rq)sub_nr_running (rq, task_delta); done: +/* Stop the fair server if throttling resulted in no runnable tasks */ +if (rq_h_nr_running && !rq->cfs.h_nr_running) +dl_server_stop (&rq->fair_server);/* * Note: distribution will already see us throttled via the * throttled-list. rq->lock protects completion.
@@ -5855,6 +5859,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)struct cfs_bandwidth *cfs_b =tg_cfs_bandwidth (cfs_rq->tg);struct sched_entity *se;long task_delta, idle_task_delta; +long rq_h_nr_running = rq->cfs.h_nr_running; se = cfs_rq->tg->se[cpu_of (rq)];
@@ -5930,6 +5935,10 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq) unthrottle_throttle:assert_list_leaf_cfs_rq (rq); +/* Start the fair server if un-throttling resulted in new runnable tasks */ +if (!rq_h_nr_running && rq->cfs.h_nr_running) +dl_server_start (&rq->fair_server); +/* Determine whether we need to wake up potentially idle CPU: */ if (rq->curr == rq->idle && rq->cfs.nr_running)resched_curr (rq);
@@ -6760,6 +6769,9 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)*/ util_est_enqueue (&rq->cfs, p); +if (!throttled_hierarchy (task_cfs_rq (p)) && !rq->cfs.h_nr_running) +dl_server_start (&rq->fair_server); +/* * If in_iowait is set, the code below may not trigger any cpufreq * utilization updates, so do it here explicitly with the IOWAIT flag
@@ -6904,6 +6916,9 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) rq->next_balance = jiffies; dequeue_throttle: +if (!throttled_hierarchy (task_cfs_rq (p)) && !rq->cfs.h_nr_running) +dl_server_stop (&rq->fair_server); +util_est_update (&rq->cfs, p, task_sleep);hrtick_update (rq); }
@@ -8607,6 +8622,25 @@ static struct task_struct *__pick_next_task_fair(struct rq *rq)return pick_next_task_fair (rq,NULL ,NULL ); } +static bool fair_server_has_tasks (struct sched_dl_entity *dl_se) +{ +return !!dl_se->rq->cfs.nr_running; +} + +static struct task_struct *fair_server_pick (struct sched_dl_entity *dl_se) +{ +return pick_next_task_fair (dl_se->rq,NULL ,NULL ); +} + +void fair_server_init (struct rq *rq) +{ +struct sched_dl_entity *dl_se = &rq->fair_server; + +init_dl_entity (dl_se); + +dl_server_init (dl_se, rq, fair_server_has_tasks, fair_server_pick); +} +/* * Account for a descheduled task: */
kernel/sched/sched.h +4 -0
@@ -356,6 +356,8 @@ extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,dl_server_has_tasks_f has_tasks, dl_server_pick_f pick); +extern void fair_server_init (struct rq *rq); +#ifdef CONFIG_CGROUP_SCHED struct cfs_rq ;
@@ -1037,6 +1039,8 @@ struct rq {struct rt_rq rt;struct dl_rq dl; +struct sched_dl_entity fair_server; +#ifdef CONFIG_FAIR_GROUP_SCHED /* list of leaf cfs_rq on this CPU: */ struct list_head leaf_cfs_rq_list;
Signature · 1 line
2.45.1
[tip: sched/core] sched/fair: Add trivial fair server
The following commit has been merged into the sched/core branch of tip:
The following commit has been merged into the sched/core branch of tip:
Commit-ID: 557a6bfc662c4d560f909b78adb1270c9862efa8 Gitweb: https://git.kernel.org/tip/557a6bfc662c4d560f909b78adb1270c9862efa8 Author: Peter Zijlstra <[email protected]> AuthorDate: Mon, 27 May 2024 14:06:50 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 29 Jul 2024 12:22:36 +02:00
sched/fair: Add trivial fair server
Use deadline servers to service fair tasks.
This patch adds a fair_server deadline entity which acts as a container for fair entities and can be used to fix starvation when higher priority (wrt fair) tasks are monopolizing CPU(s).
--- kernel/sched/core.c | 1 + kernel/sched/deadline.c | 23 +++++++++++++++++++++++ kernel/sched/fair.c | 34 ++++++++++++++++++++++++++++++++++ kernel/sched/sched.h | 4 ++++ 4 files changed, 62 insertions(+)
kernel/sched/core.c +1 -0
@@ -8336,6 +8336,7 @@ void __init sched_init(void)#endif /* CONFIG_SMP */ hrtick_rq_init (rq);atomic_set (&rq->nr_iowait,0 ); +fair_server_init (rq);#ifdef CONFIG_SCHED_CORE rq->core = rq;
kernel/sched/deadline.c +23 -0
@@ -1382,6 +1382,13 @@ throttle: }/* +* The fair server (sole dl_server) does not account for real-time +* workload because it is running fair work. +*/ +if (dl_se == &rq->fair_server) +return ; + +/* * Because -- for now -- we share the rt bandwidth, we need to * account our runtime there too, otherwise actual rt tasks * would be able to exceed the shared quota.
@@ -1414,15 +1421,31 @@ void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec)void dl_server_start (struct sched_dl_entity *dl_se) { +struct rq *rq = dl_se->rq; +if (!dl_server (dl_se)) { +/* Disabled */ + dl_se->dl_runtime =0 ; + dl_se->dl_deadline =1000 *NSEC_PER_MSEC ; + dl_se->dl_period =1000 *NSEC_PER_MSEC ; + dl_se->dl_server =1 ;setup_new_dl_entity (dl_se); } + +if (!dl_se->dl_runtime) +return ; +enqueue_dl_entity (dl_se,ENQUEUE_WAKEUP ); +if (!dl_task (dl_se->rq->curr) ||dl_entity_preempt (dl_se, &rq->curr->dl)) +resched_curr (dl_se->rq); }void dl_server_stop (struct sched_dl_entity *dl_se) { +if (!dl_se->dl_runtime) +return ; +dequeue_dl_entity (dl_se,DEQUEUE_SLEEP ); }
kernel/sched/fair.c +34 -0
@@ -5765,6 +5765,7 @@ static bool throttle_cfs_rq(struct cfs_rq *cfs_rq)struct cfs_bandwidth *cfs_b =tg_cfs_bandwidth (cfs_rq->tg);struct sched_entity *se;long task_delta, idle_task_delta, dequeue =1 ; +long rq_h_nr_running = rq->cfs.h_nr_running;raw_spin_lock (&cfs_b->lock);/* This will start the period timer if necessary */
@@ -5837,6 +5838,9 @@ static bool throttle_cfs_rq(struct cfs_rq *cfs_rq)sub_nr_running (rq, task_delta); done: +/* Stop the fair server if throttling resulted in no runnable tasks */ +if (rq_h_nr_running && !rq->cfs.h_nr_running) +dl_server_stop (&rq->fair_server);/* * Note: distribution will already see us throttled via the * throttled-list. rq->lock protects completion.
@@ -5854,6 +5858,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)struct cfs_bandwidth *cfs_b =tg_cfs_bandwidth (cfs_rq->tg);struct sched_entity *se;long task_delta, idle_task_delta; +long rq_h_nr_running = rq->cfs.h_nr_running; se = cfs_rq->tg->se[cpu_of (rq)];
@@ -5929,6 +5934,10 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq) unthrottle_throttle:assert_list_leaf_cfs_rq (rq); +/* Start the fair server if un-throttling resulted in new runnable tasks */ +if (!rq_h_nr_running && rq->cfs.h_nr_running) +dl_server_start (&rq->fair_server); +/* Determine whether we need to wake up potentially idle CPU: */ if (rq->curr == rq->idle && rq->cfs.nr_running)resched_curr (rq);
@@ -6759,6 +6768,9 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)*/ util_est_enqueue (&rq->cfs, p); +if (!throttled_hierarchy (task_cfs_rq (p)) && !rq->cfs.h_nr_running) +dl_server_start (&rq->fair_server); +/* * If in_iowait is set, the code below may not trigger any cpufreq * utilization updates, so do it here explicitly with the IOWAIT flag
@@ -6903,6 +6915,9 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) rq->next_balance = jiffies; dequeue_throttle: +if (!throttled_hierarchy (task_cfs_rq (p)) && !rq->cfs.h_nr_running) +dl_server_stop (&rq->fair_server); +util_est_update (&rq->cfs, p, task_sleep);hrtick_update (rq); }
@@ -8602,6 +8617,25 @@ static struct task_struct *__pick_next_task_fair(struct rq *rq)return pick_next_task_fair (rq,NULL ,NULL ); } +static bool fair_server_has_tasks (struct sched_dl_entity *dl_se) +{ +return !!dl_se->rq->cfs.nr_running; +} + +static struct task_struct *fair_server_pick (struct sched_dl_entity *dl_se) +{ +return pick_next_task_fair (dl_se->rq,NULL ,NULL ); +} + +void fair_server_init (struct rq *rq) +{ +struct sched_dl_entity *dl_se = &rq->fair_server; + +init_dl_entity (dl_se); + +dl_server_init (dl_se, rq, fair_server_has_tasks, fair_server_pick); +} +/* * Account for a descheduled task: */
kernel/sched/sched.h +4 -0
@@ -363,6 +363,8 @@ extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,dl_server_has_tasks_f has_tasks, dl_server_pick_f pick); +extern void fair_server_init (struct rq *rq); +#ifdef CONFIG_CGROUP_SCHED extern struct list_head task_groups;
@@ -1039,6 +1041,8 @@ struct rq {struct rt_rq rt;struct dl_rq dl; +struct sched_dl_entity fair_server; +#ifdef CONFIG_FAIR_GROUP_SCHED /* list of leaf cfs_rq on this CPU: */ struct list_head leaf_cfs_rq_list;
PATCH v7 5/9 sched/deadline: Deferrable dl server
In reply to Daniel Bristot de OliveiraAmong the motivations for the DL servers is the real-time throttling mechanism. This mechanism works by throttling the rt_rq after running for a long period without leaving space for fair tasks.
The base dl server avoids this problem by boosting fair tasks instead of throttling the rt_rq. The point is that it boosts without waiting for potential starvation, causing some non-intuitive cases.
For example, an IRQ dispatches two tasks on an idle system, a fair and an RT. The DL server will be activated, running the fair task before the RT one. This problem can be avoided by deferring the dl server activation.
By setting the defer option, the dl_server will dispatch an SCHED_DEADLINE reservation with replenished runtime, but throttled.
The dl_timer will be set for the defer time at (period - runtime) ns from start time. Thus boosting the fair rq at defer time.
If the fair scheduler has the opportunity to run while waiting for defer time, the dl server runtime will be consumed. If the runtime is completely consumed before the defer time, the server will be replenished while still in a throttled state. Then, the dl_timer will be reset to the new defer time
If the fair server reaches the defer time without consuming its runtime, the server will start running, following CBS rules (thus without breaking SCHED_DEADLINE). Then the server will continue the running state (without deferring) until it fair tasks are able to execute as regular fair scheduler (end of the starvation).
--- include/linux/sched.h | 12 ++ kernel/sched/deadline.c | 301 ++++++++++++++++++++++++++++++++++------ kernel/sched/fair.c | 24 +++- kernel/sched/idle.c | 2 + kernel/sched/sched.h | 4 +- 5 files changed, 298 insertions(+), 45 deletions(-)
include/linux/sched.h +12 -0
@@ -639,12 +639,24 @@ struct sched_dl_entity {* overruns. * * @dl_server tells if this is a server entity. +* +* @dl_defer tells if this is a deferred or regular server. For +* now only defer server exists. +* +* @dl_defer_armed tells if the deferrable server is waiting +* for the replenishment timer to activate it. +* +* @dl_defer_running tells if the deferrable server is actually +* running, skipping the defer phase. */ unsigned int dl_throttled : 1; unsigned int dl_yielded : 1; unsigned int dl_non_contending : 1; unsigned int dl_overrun : 1; unsigned int dl_server : 1; + unsigned int dl_defer : 1; + unsigned int dl_defer_armed : 1; + unsigned int dl_defer_running : 1;/* * Bandwidth enforcement timer. Each -deadline task has its
kernel/sched/deadline.c +261 -40
400 lines not on this page · raw message
kernel/sched/fair.c +20 -4
@@ -1156,12 +1156,13 @@ s64 update_curr_common(struct rq *rq)static void update_curr (struct cfs_rq *cfs_rq) {struct sched_entity *curr = cfs_rq->curr; +struct rq *rq =rq_of (cfs_rq);s64 delta_exec;if (unlikely (!curr))return ; - delta_exec =update_curr_se (rq_of (cfs_rq), curr); + delta_exec =update_curr_se (rq, curr);if (unlikely (delta_exec <=0 ))return ;
@@ -1169,8 +1170,19 @@ static void update_curr(struct cfs_rq *cfs_rq)update_deadline (cfs_rq, curr);update_min_vruntime (cfs_rq); -if (entity_is_task (curr)) -update_curr_task (task_of (curr), delta_exec); +if (entity_is_task (curr)) { +struct task_struct *p =task_of (curr); + +update_curr_task (p, delta_exec); + +/* +* Any fair task that runs outside of fair_server should +* account against fair_server such that it can account for +* this time and possibly avoid running this period. +*/ +if (p->dl_server != &rq->fair_server) +dl_server_update (&rq->fair_server, delta_exec); + }account_cfs_rq_runtime (cfs_rq, delta_exec); }
@@ -6769,8 +6781,12 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)*/ util_est_enqueue (&rq->cfs, p); -if (!throttled_hierarchy (task_cfs_rq (p)) && !rq->cfs.h_nr_running) +if (!throttled_hierarchy (task_cfs_rq (p)) && !rq->cfs.h_nr_running) { +/* Account for idle runtime */ +if (!rq->nr_running) +dl_server_update_idle_time (rq, rq->curr);dl_server_start (&rq->fair_server); + }/* * If in_iowait is set, the code below may not trigger any cpufreq
kernel/sched/idle.c +2 -0
@@ -458,12 +458,14 @@ static void wakeup_preempt_idle(struct rq *rq, struct task_struct *p, int flags)static void put_prev_task_idle (struct rq *rq,struct task_struct *prev) { +dl_server_update_idle_time (rq, prev); }static void set_next_task_idle (struct rq *rq,struct task_struct *next,bool first) {update_idle_core (rq);schedstat_inc (rq->sched_goidle); + next->se.exec_start =rq_clock_task (rq); }#ifdef CONFIG_SMP
kernel/sched/sched.h +3 -1
@@ -328,7 +328,7 @@ extern bool __checkparam_dl(const struct sched_attr *attr);extern bool dl_param_changed (struct task_struct *p,const struct sched_attr *attr);extern int dl_cpuset_cpumask_can_shrink (const struct cpumask *cur,const struct cpumask *trial);extern int dl_bw_check_overflow (int cpu); - +extern s64 dl_scaled_delta_exec (struct rq *rq,struct sched_dl_entity *dl_se,s64 delta_exec);/* * SCHED_DEADLINE supports servers (nested scheduling) with the following * interface:
@@ -356,6 +356,8 @@ extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,dl_server_has_tasks_f has_tasks, dl_server_pick_f pick); +extern void dl_server_update_idle_time (struct rq *rq, +struct task_struct *p);extern void fair_server_init (struct rq *rq);#ifdef CONFIG_CGROUP_SCHED
Signature · 1 line
2.45.1
[tip: sched/core] sched/deadline: Deferrable dl server
The following commit has been merged into the sched/core branch of tip:
The following commit has been merged into the sched/core branch of tip:
Commit-ID: a110a81c52a9de73e2e57e826dd3bf0fd4c22226 Gitweb: https://git.kernel.org/tip/a110a81c52a9de73e2e57e826dd3bf0fd4c22226 Author: Daniel Bristot de Oliveira <[email protected]> AuthorDate: Mon, 27 May 2024 14:06:51 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 29 Jul 2024 12:22:36 +02:00
sched/deadline: Deferrable dl server
Among the motivations for the DL servers is the real-time throttling mechanism. This mechanism works by throttling the rt_rq after running for a long period without leaving space for fair tasks.
The base dl server avoids this problem by boosting fair tasks instead of throttling the rt_rq. The point is that it boosts without waiting for potential starvation, causing some non-intuitive cases.
For example, an IRQ dispatches two tasks on an idle system, a fair and an RT. The DL server will be activated, running the fair task before the RT one. This problem can be avoided by deferring the dl server activation.
By setting the defer option, the dl_server will dispatch an SCHED_DEADLINE reservation with replenished runtime, but throttled.
The dl_timer will be set for the defer time at (period - runtime) ns from start time. Thus boosting the fair rq at defer time.
If the fair scheduler has the opportunity to run while waiting for defer time, the dl server runtime will be consumed. If the runtime is completely consumed before the defer time, the server will be replenished while still in a throttled state. Then, the dl_timer will be reset to the new defer time
If the fair server reaches the defer time without consuming its runtime, the server will start running, following CBS rules (thus without breaking SCHED_DEADLINE). Then the server will continue the running state (without deferring) until it fair tasks are able to execute as regular fair scheduler (end of the starvation).
--- include/linux/sched.h | 12 ++- kernel/sched/deadline.c | 301 +++++++++++++++++++++++++++++++++------ kernel/sched/fair.c | 24 ++- kernel/sched/idle.c | 2 +- kernel/sched/sched.h | 4 +- 5 files changed, 298 insertions(+), 45 deletions(-)
include/linux/sched.h +12 -0
@@ -641,12 +641,24 @@ struct sched_dl_entity {* overruns. * * @dl_server tells if this is a server entity. +* +* @dl_defer tells if this is a deferred or regular server. For +* now only defer server exists. +* +* @dl_defer_armed tells if the deferrable server is waiting +* for the replenishment timer to activate it. +* +* @dl_defer_running tells if the deferrable server is actually +* running, skipping the defer phase. */ unsigned int dl_throttled : 1; unsigned int dl_yielded : 1; unsigned int dl_non_contending : 1; unsigned int dl_overrun : 1; unsigned int dl_server : 1; + unsigned int dl_defer : 1; + unsigned int dl_defer_armed : 1; + unsigned int dl_defer_running : 1;/* * Bandwidth enforcement timer. Each -deadline task has its
kernel/sched/deadline.c +261 -40
400 lines not on this page · raw message
kernel/sched/fair.c +20 -4
@@ -1156,12 +1156,13 @@ s64 update_curr_common(struct rq *rq)static void update_curr (struct cfs_rq *cfs_rq) {struct sched_entity *curr = cfs_rq->curr; +struct rq *rq =rq_of (cfs_rq);s64 delta_exec;if (unlikely (!curr))return ; - delta_exec =update_curr_se (rq_of (cfs_rq), curr); + delta_exec =update_curr_se (rq, curr);if (unlikely (delta_exec <=0 ))return ;
@@ -1169,8 +1170,19 @@ static void update_curr(struct cfs_rq *cfs_rq)update_deadline (cfs_rq, curr);update_min_vruntime (cfs_rq); -if (entity_is_task (curr)) -update_curr_task (task_of (curr), delta_exec); +if (entity_is_task (curr)) { +struct task_struct *p =task_of (curr); + +update_curr_task (p, delta_exec); + +/* +* Any fair task that runs outside of fair_server should +* account against fair_server such that it can account for +* this time and possibly avoid running this period. +*/ +if (p->dl_server != &rq->fair_server) +dl_server_update (&rq->fair_server, delta_exec); + }account_cfs_rq_runtime (cfs_rq, delta_exec); }
@@ -6768,8 +6780,12 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)*/ util_est_enqueue (&rq->cfs, p); -if (!throttled_hierarchy (task_cfs_rq (p)) && !rq->cfs.h_nr_running) +if (!throttled_hierarchy (task_cfs_rq (p)) && !rq->cfs.h_nr_running) { +/* Account for idle runtime */ +if (!rq->nr_running) +dl_server_update_idle_time (rq, rq->curr);dl_server_start (&rq->fair_server); + }/* * If in_iowait is set, the code below may not trigger any cpufreq
kernel/sched/idle.c +2 -0
@@ -452,12 +452,14 @@ static void wakeup_preempt_idle(struct rq *rq, struct task_struct *p, int flags)static void put_prev_task_idle (struct rq *rq,struct task_struct *prev) { +dl_server_update_idle_time (rq, prev); }static void set_next_task_idle (struct rq *rq,struct task_struct *next,bool first) {update_idle_core (rq);schedstat_inc (rq->sched_goidle); + next->se.exec_start =rq_clock_task (rq); }#ifdef CONFIG_SMP
kernel/sched/sched.h +3 -1
@@ -335,7 +335,7 @@ extern bool __checkparam_dl(const struct sched_attr *attr);extern bool dl_param_changed (struct task_struct *p,const struct sched_attr *attr);extern int dl_cpuset_cpumask_can_shrink (const struct cpumask *cur,const struct cpumask *trial);extern int dl_bw_check_overflow (int cpu); - +extern s64 dl_scaled_delta_exec (struct rq *rq,struct sched_dl_entity *dl_se,s64 delta_exec);/* * SCHED_DEADLINE supports servers (nested scheduling) with the following * interface:
@@ -363,6 +363,8 @@ extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,dl_server_has_tasks_f has_tasks, dl_server_pick_f pick); +extern void dl_server_update_idle_time (struct rq *rq, +struct task_struct *p);extern void fair_server_init (struct rq *rq);#ifdef CONFIG_CGROUP_SCHED
PATCH v7 6/9 sched/fair: Fair server interface
In reply to Daniel Bristot de OliveiraAdd an interface for fair server setup on debugfs.
Each CPU has two files under /debug/sched/fair_server/cpu{ID}:
- runtime: set runtime in ns
- period: set period in ns
This then leaves /proc/sys/kernel/sched_rt_{period,runtime}_us to set bounds on admission control.
The interface also add the server to the dl bandwidth accounting.
--- kernel/sched/deadline.c | 103 +++++++++++++++++++++----- kernel/sched/debug.c | 159 ++++++++++++++++++++++++++++++++++++++++ kernel/sched/sched.h | 3 + kernel/sched/topology.c | 8 ++ 4 files changed, 256 insertions(+), 17 deletions(-)
kernel/sched/deadline.c +86 -17
@@ -320,19 +320,12 @@ void sub_running_bw(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)__sub_running_bw (dl_se->dl_bw, dl_rq); } -static void dl_change_utilization (struct task_struct *p,u64 new_bw) +static void dl_rq_change_utilization (struct rq *rq,struct sched_dl_entity *dl_se,u64 new_bw) { -struct rq *rq; - -WARN_ON_ONCE (p->dl.flags &SCHED_FLAG_SUGOV ); - -if (task_on_rq_queued (p)) -return ; +if (dl_se->dl_non_contending) { +sub_running_bw (dl_se, &rq->dl); + dl_se->dl_non_contending =0 ; - rq =task_rq (p); -if (p->dl.dl_non_contending) { -sub_running_bw (&p->dl, &rq->dl); - p->dl.dl_non_contending =0 ;/* * If the timer handler is currently running and the * timer cannot be canceled, inactive_task_timer()
@@ -340,13 +333,25 @@ static void dl_change_utilization(struct task_struct *p, u64 new_bw)* will not touch the rq's active utilization, * so we are still safe. */ -if (hrtimer_try_to_cancel (&p->dl.inactive_timer) ==1 ) -put_task_struct (p); +if (hrtimer_try_to_cancel (&dl_se->inactive_timer) ==1 ) { +if (!dl_server (dl_se)) +put_task_struct (dl_task_of (dl_se)); + } } -__sub_rq_bw (p->dl.dl_bw, &rq->dl); +__sub_rq_bw (dl_se->dl_bw, &rq->dl);__add_rq_bw (new_bw, &rq->dl); } +static void dl_change_utilization (struct task_struct *p,u64 new_bw) +{ +WARN_ON_ONCE (p->dl.flags &SCHED_FLAG_SUGOV ); + +if (task_on_rq_queued (p)) +return ; + +dl_rq_change_utilization (task_rq (p), &p->dl, new_bw); +} +static void __dl_clear_params (struct sched_dl_entity *dl_se);/*
@@ -1621,11 +1626,17 @@ void dl_server_start(struct sched_dl_entity *dl_se) {struct rq *rq = dl_se->rq; +/* +* XXX: the apply do not work fine at the init phase for the +* fair server because things are not yet set. We need to improve +* this before getting generic. +*/ if (!dl_server (dl_se)) {/* Disabled */ - dl_se->dl_runtime =0 ; - dl_se->dl_deadline =1000 *NSEC_PER_MSEC ; - dl_se->dl_period =1000 *NSEC_PER_MSEC ; +u64 runtime =0 ; +u64 period =1000 *NSEC_PER_MSEC ; + +dl_server_apply_params (dl_se, runtime, period,1 ); dl_se->dl_server =1 ; dl_se->dl_defer =1 ;
@@ -1660,6 +1671,64 @@ void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq, dl_se->server_pick = pick; } +void __dl_server_attach_root (struct sched_dl_entity *dl_se,struct rq *rq) +{ +u64 new_bw = dl_se->dl_bw; +int cpu =cpu_of (rq); +struct dl_bw *dl_b; + + dl_b =dl_bw_of (cpu_of (rq)); +guard (raw_spinlock)(&dl_b->lock); + +if (!dl_bw_cpus (cpu)) +return ; + +__dl_add (dl_b, new_bw,dl_bw_cpus (cpu)); +} + +int dl_server_apply_params (struct sched_dl_entity *dl_se,u64 runtime,u64 period,bool init) +{ +u64 old_bw = init ?0 :to_ratio (dl_se->dl_period, dl_se->dl_runtime); +u64 new_bw =to_ratio (period, runtime); +struct rq *rq = dl_se->rq; +int cpu =cpu_of (rq); +struct dl_bw *dl_b; +unsigned long cap; +int retval =0 ; +int cpus; + + dl_b =dl_bw_of (cpu); +guard (raw_spinlock)(&dl_b->lock); + + cpus =dl_bw_cpus (cpu); + cap =dl_bw_capacity (cpu); + +if (__dl_overflow (dl_b, cap, old_bw, new_bw)) +return -EBUSY ; + +if (init) { +__add_rq_bw (new_bw, &rq->dl); +__dl_add (dl_b, new_bw, cpus); + }else { +__dl_sub (dl_b, dl_se->dl_bw, cpus); +__dl_add (dl_b, new_bw, cpus); + +dl_rq_change_utilization (rq, dl_se, new_bw); + } + + dl_se->dl_runtime = runtime; + dl_se->dl_deadline = period; + dl_se->dl_period = period; + + dl_se->runtime =0 ; + dl_se->deadline =0 ; + + dl_se->dl_bw =to_ratio (dl_se->dl_period, dl_se->dl_runtime); + dl_se->dl_density =to_ratio (dl_se->dl_deadline, dl_se->dl_runtime); + +return retval; +} +/* * Update the current task's runtime statistics (provided it is still * a -deadline task and has not been removed from the dl_rq).
kernel/sched/debug.c +159 -0
173 lines not on this page · raw message
kernel/sched/sched.h +3 -0
@@ -359,6 +359,9 @@ extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,extern void dl_server_update_idle_time (struct rq *rq,struct task_struct *p);extern void fair_server_init (struct rq *rq); +extern void __dl_server_attach_root (struct sched_dl_entity *dl_se,struct rq *rq); +extern int dl_server_apply_params (struct sched_dl_entity *dl_se, +u64 runtime,u64 period,bool init);#ifdef CONFIG_CGROUP_SCHED
kernel/sched/topology.c +8 -0
@@ -516,6 +516,14 @@ void rq_attach_root(struct rq *rq, struct root_domain *rd)if (cpumask_test_cpu (rq->cpu, cpu_active_mask))set_rq_online (rq); +/* +* Because the rq is not a task, dl_add_task_root_domain() did not +* move the fair server bw to the rd if it already started. +* Add it now. +*/ +if (rq->fair_server.dl_server) +__dl_server_attach_root (&rq->fair_server, rq); +rq_unlock_irqrestore (rq, &rf);if (old_rd)
Signature · 1 line
2.45.1
[tip: sched/core] sched/fair: Fair server interface
The following commit has been merged into the sched/core branch of tip:
The following commit has been merged into the sched/core branch of tip:
Commit-ID: d741f297bceaf52aa1b97b997708fc0cd853c73e Gitweb: https://git.kernel.org/tip/d741f297bceaf52aa1b97b997708fc0cd853c73e Author: Daniel Bristot de Oliveira <[email protected]> AuthorDate: Mon, 27 May 2024 14:06:52 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 29 Jul 2024 12:22:36 +02:00
sched/fair: Fair server interface
Add an interface for fair server setup on debugfs.
Each CPU has two files under /debug/sched/fair_server/cpu{ID}:
- runtime: set runtime in ns
- period: set period in ns
This then leaves /proc/sys/kernel/sched_rt_{period,runtime}_us to set bounds on admission control.
The interface also add the server to the dl bandwidth accounting.
--- kernel/sched/deadline.c | 103 ++++++++++++++++++++----- kernel/sched/debug.c | 159 +++++++++++++++++++++++++++++++++++++++- kernel/sched/sched.h | 3 +- kernel/sched/topology.c | 8 ++- 4 files changed, 256 insertions(+), 17 deletions(-)
kernel/sched/deadline.c +86 -17
@@ -320,19 +320,12 @@ void sub_running_bw(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)__sub_running_bw (dl_se->dl_bw, dl_rq); } -static void dl_change_utilization (struct task_struct *p,u64 new_bw) +static void dl_rq_change_utilization (struct rq *rq,struct sched_dl_entity *dl_se,u64 new_bw) { -struct rq *rq; - -WARN_ON_ONCE (p->dl.flags &SCHED_FLAG_SUGOV ); - -if (task_on_rq_queued (p)) -return ; +if (dl_se->dl_non_contending) { +sub_running_bw (dl_se, &rq->dl); + dl_se->dl_non_contending =0 ; - rq =task_rq (p); -if (p->dl.dl_non_contending) { -sub_running_bw (&p->dl, &rq->dl); - p->dl.dl_non_contending =0 ;/* * If the timer handler is currently running and the * timer cannot be canceled, inactive_task_timer()
@@ -340,13 +333,25 @@ static void dl_change_utilization(struct task_struct *p, u64 new_bw)* will not touch the rq's active utilization, * so we are still safe. */ -if (hrtimer_try_to_cancel (&p->dl.inactive_timer) ==1 ) -put_task_struct (p); +if (hrtimer_try_to_cancel (&dl_se->inactive_timer) ==1 ) { +if (!dl_server (dl_se)) +put_task_struct (dl_task_of (dl_se)); + } } -__sub_rq_bw (p->dl.dl_bw, &rq->dl); +__sub_rq_bw (dl_se->dl_bw, &rq->dl);__add_rq_bw (new_bw, &rq->dl); } +static void dl_change_utilization (struct task_struct *p,u64 new_bw) +{ +WARN_ON_ONCE (p->dl.flags &SCHED_FLAG_SUGOV ); + +if (task_on_rq_queued (p)) +return ; + +dl_rq_change_utilization (task_rq (p), &p->dl, new_bw); +} +static void __dl_clear_params (struct sched_dl_entity *dl_se);/*
@@ -1621,11 +1626,17 @@ void dl_server_start(struct sched_dl_entity *dl_se) {struct rq *rq = dl_se->rq; +/* +* XXX: the apply do not work fine at the init phase for the +* fair server because things are not yet set. We need to improve +* this before getting generic. +*/ if (!dl_server (dl_se)) {/* Disabled */ - dl_se->dl_runtime =0 ; - dl_se->dl_deadline =1000 *NSEC_PER_MSEC ; - dl_se->dl_period =1000 *NSEC_PER_MSEC ; +u64 runtime =0 ; +u64 period =1000 *NSEC_PER_MSEC ; + +dl_server_apply_params (dl_se, runtime, period,1 ); dl_se->dl_server =1 ; dl_se->dl_defer =1 ;
@@ -1660,6 +1671,64 @@ void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq, dl_se->server_pick = pick; } +void __dl_server_attach_root (struct sched_dl_entity *dl_se,struct rq *rq) +{ +u64 new_bw = dl_se->dl_bw; +int cpu =cpu_of (rq); +struct dl_bw *dl_b; + + dl_b =dl_bw_of (cpu_of (rq)); +guard (raw_spinlock)(&dl_b->lock); + +if (!dl_bw_cpus (cpu)) +return ; + +__dl_add (dl_b, new_bw,dl_bw_cpus (cpu)); +} + +int dl_server_apply_params (struct sched_dl_entity *dl_se,u64 runtime,u64 period,bool init) +{ +u64 old_bw = init ?0 :to_ratio (dl_se->dl_period, dl_se->dl_runtime); +u64 new_bw =to_ratio (period, runtime); +struct rq *rq = dl_se->rq; +int cpu =cpu_of (rq); +struct dl_bw *dl_b; +unsigned long cap; +int retval =0 ; +int cpus; + + dl_b =dl_bw_of (cpu); +guard (raw_spinlock)(&dl_b->lock); + + cpus =dl_bw_cpus (cpu); + cap =dl_bw_capacity (cpu); + +if (__dl_overflow (dl_b, cap, old_bw, new_bw)) +return -EBUSY ; + +if (init) { +__add_rq_bw (new_bw, &rq->dl); +__dl_add (dl_b, new_bw, cpus); + }else { +__dl_sub (dl_b, dl_se->dl_bw, cpus); +__dl_add (dl_b, new_bw, cpus); + +dl_rq_change_utilization (rq, dl_se, new_bw); + } + + dl_se->dl_runtime = runtime; + dl_se->dl_deadline = period; + dl_se->dl_period = period; + + dl_se->runtime =0 ; + dl_se->deadline =0 ; + + dl_se->dl_bw =to_ratio (dl_se->dl_period, dl_se->dl_runtime); + dl_se->dl_density =to_ratio (dl_se->dl_deadline, dl_se->dl_runtime); + +return retval; +} +/* * Update the current task's runtime statistics (provided it is still * a -deadline task and has not been removed from the dl_rq).
kernel/sched/debug.c +159 -0
173 lines not on this page · raw message
kernel/sched/sched.h +3 -0
@@ -366,6 +366,9 @@ extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,extern void dl_server_update_idle_time (struct rq *rq,struct task_struct *p);extern void fair_server_init (struct rq *rq); +extern void __dl_server_attach_root (struct sched_dl_entity *dl_se,struct rq *rq); +extern int dl_server_apply_params (struct sched_dl_entity *dl_se, +u64 runtime,u64 period,bool init);#ifdef CONFIG_CGROUP_SCHED
kernel/sched/topology.c +8 -0
@@ -516,6 +516,14 @@ void rq_attach_root(struct rq *rq, struct root_domain *rd)if (cpumask_test_cpu (rq->cpu, cpu_active_mask))set_rq_online (rq); +/* +* Because the rq is not a task, dl_add_task_root_domain() did not +* move the fair server bw to the rd if it already started. +* Add it now. +*/ +if (rq->fair_server.dl_server) +__dl_server_attach_root (&rq->fair_server, rq); +rq_unlock_irqrestore (rq, &rf);if (old_rd)
PATCH v7 7/9 sched/core: Fix priority checking for DL server picks
In reply to Daniel Bristot de OliveiraFrom: "Joel Fernandes (Google)" <[email protected]>
In core scheduling, a DL server pick (which is CFS task) should be given higher priority than tasks in other classes.
Not doing so causes CFS starvation. A kselftest is added later to demonstrate this. A CFS task that is competing with RT tasks can be completely starved without this and the DL server's boosting completely ignored.
Fix these problems.
--- kernel/sched/core.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
kernel/sched/core.c +21 -2
@@ -162,6 +162,9 @@ static inline int __task_prio(const struct task_struct *p)if (p->sched_class == &stop_sched_class)/* trumps deadline */ return -2 ; +if (p->dl_server) +return -1 ;/* deadline */ +if (rt_prio (p->prio))/* includes deadline */ return p->prio;/* [-1, 99] */
@@ -191,8 +194,24 @@ static inline bool prio_less(const struct task_struct *a,if (-pb < -pa)return false; -if (pa ==-1 )/* dl_prio() doesn't work because of stop_class above */ -return !dl_time_before (a->dl.deadline, b->dl.deadline); +if (pa ==-1 ) {/* dl_prio() doesn't work because of stop_class above */ +const struct sched_dl_entity *a_dl, *b_dl; + + a_dl = &a->dl; +/* +* Since,'a' and 'b' can be CFS tasks served by DL server, +* __task_prio() can return -1 (for DL) even for those. In that +* case, get to the dl_server's DL entity. +*/ +if (a->dl_server) + a_dl = a->dl_server; + + b_dl = &b->dl; +if (b->dl_server) + b_dl = b->dl_server; + +return !dl_time_before (a_dl->deadline, b_dl->deadline); + }if (pa ==MAX_RT_PRIO +MAX_NICE )/* fair */ return cfs_prio_less (a, b, in_fi);
Signature · 1 line
2.45.1
[tip: sched/core] sched/core: Fix priority checking for DL server picks
The following commit has been merged into the sched/core branch of tip:
The following commit has been merged into the sched/core branch of tip:
Commit-ID: 4b26cfdd395638918e370f62bd2c33e6f63ffb5e Gitweb: https://git.kernel.org/tip/4b26cfdd395638918e370f62bd2c33e6f63ffb5e Author: Joel Fernandes (Google) <[email protected]> AuthorDate: Mon, 27 May 2024 14:06:53 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 29 Jul 2024 12:22:36 +02:00
sched/core: Fix priority checking for DL server picks
In core scheduling, a DL server pick (which is CFS task) should be given higher priority than tasks in other classes.
Not doing so causes CFS starvation. A kselftest is added later to demonstrate this. A CFS task that is competing with RT tasks can be completely starved without this and the DL server's boosting completely ignored.
Fix these problems.
--- kernel/sched/core.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
kernel/sched/core.c +21 -2
@@ -163,6 +163,9 @@ static inline int __task_prio(const struct task_struct *p)if (p->sched_class == &stop_sched_class)/* trumps deadline */ return -2 ; +if (p->dl_server) +return -1 ;/* deadline */ +if (rt_prio (p->prio))/* includes deadline */ return p->prio;/* [-1, 99] */
@@ -192,8 +195,24 @@ static inline bool prio_less(const struct task_struct *a,if (-pb < -pa)return false; -if (pa ==-1 )/* dl_prio() doesn't work because of stop_class above */ -return !dl_time_before (a->dl.deadline, b->dl.deadline); +if (pa ==-1 ) {/* dl_prio() doesn't work because of stop_class above */ +const struct sched_dl_entity *a_dl, *b_dl; + + a_dl = &a->dl; +/* +* Since,'a' and 'b' can be CFS tasks served by DL server, +* __task_prio() can return -1 (for DL) even for those. In that +* case, get to the dl_server's DL entity. +*/ +if (a->dl_server) + a_dl = a->dl_server; + + b_dl = &b->dl; +if (b->dl_server) + b_dl = b->dl_server; + +return !dl_time_before (a_dl->deadline, b_dl->deadline); + }if (pa ==MAX_RT_PRIO +MAX_NICE )/* fair */ return cfs_prio_less (a, b, in_fi);
PATCH v7 8/9 sched/core: Fix picking of tasks for core scheduling with DL server
In reply to Daniel Bristot de OliveiraFrom: "Joel Fernandes (Google)" <[email protected]>
* Use simple CFS pick_task for DL pick_task
DL server's pick_task calls CFS's pick_next_task_fair(), this is wrong because core scheduling's pick_task only calls CFS's pick_task() for evaluation / checking of the CFS task (comparing across CPUs), not for actually affirmatively picking the next task. This causes RB tree corruption issues in CFS that were found by syzbot.
* Make pick_task_fair clear DL server
A DL task pick might set ->dl_server, but it is possible the task will never run (say the other HT has a stop task). If the CFS task is picked in the future directly (say without DL server), ->dl_server will be set. So clear it in pick_task_fair().
This fixes the KASAN issue reported by syzbot in set_next_entity().
(DL refactoring suggestions by Vineeth Pillai).
--- include/linux/sched.h | 3 ++- kernel/sched/deadline.c | 27 ++++++++++++++++++++++----- kernel/sched/fair.c | 23 +++++++++++++++++++++-- kernel/sched/sched.h | 3 ++- 4 files changed, 47 insertions(+), 9 deletions(-)
include/linux/sched.h +2 -1
@@ -684,7 +684,8 @@ struct sched_dl_entity {*/ struct rq *rq;dl_server_has_tasks_f server_has_tasks; -dl_server_pick_f server_pick; +dl_server_pick_f server_pick_next; +dl_server_pick_f server_pick_task;#ifdef CONFIG_RT_MUTEXES /*
kernel/sched/deadline.c +22 -5
@@ -1664,11 +1664,13 @@ void dl_server_stop(struct sched_dl_entity *dl_se)void dl_server_init (struct sched_dl_entity *dl_se,struct rq *rq,dl_server_has_tasks_f has_tasks, -dl_server_pick_f pick) +dl_server_pick_f pick_next, +dl_server_pick_f pick_task) { dl_se->rq = rq; dl_se->server_has_tasks = has_tasks; - dl_se->server_pick = pick; + dl_se->server_pick_next = pick_next; + dl_se->server_pick_task = pick_task; }void __dl_server_attach_root (struct sched_dl_entity *dl_se,struct rq *rq)
@@ -2394,7 +2396,12 @@ static struct sched_dl_entity *pick_next_dl_entity(struct dl_rq *dl_rq)return __node_2_dle (left); } -static struct task_struct *pick_task_dl (struct rq *rq) +/* +* __pick_next_task_dl - Helper to pick the next -deadline task to run. +* @rq: The runqueue to pick the next task from. +* @peek: If true, just peek at the next task. Only relevant for dlserver. +*/ +static struct task_struct *__pick_next_task_dl (struct rq *rq,bool peek) {struct sched_dl_entity *dl_se;struct dl_rq *dl_rq = &rq->dl;
@@ -2408,7 +2415,10 @@ static struct task_struct *pick_task_dl(struct rq *rq)WARN_ON_ONCE (!dl_se);if (dl_server (dl_se)) { - p = dl_se->server_pick (dl_se); +if (IS_ENABLED (CONFIG_SMP ) && peek) + p = dl_se->server_pick_task (dl_se); +else + p = dl_se->server_pick_next (dl_se);if (!p) {WARN_ON_ONCE (1 ); dl_se->dl_yielded =1 ;
@@ -2423,11 +2433,18 @@ static struct task_struct *pick_task_dl(struct rq *rq)return p; } +#ifdef CONFIG_SMP +static struct task_struct *pick_task_dl (struct rq *rq) +{ +return __pick_next_task_dl (rq, true); +} +#endif +static struct task_struct *pick_next_task_dl (struct rq *rq) {struct task_struct *p; - p =pick_task_dl (rq); + p =__pick_next_task_dl (rq, false);if (!p)return p;
kernel/sched/fair.c +21 -2
@@ -8484,6 +8484,14 @@ static struct task_struct *pick_task_fair(struct rq *rq) cfs_rq = group_cfs_rq(se); }while (cfs_rq); +/* +* This can be called from directly from CFS's ->pick_task() or indirectly +* from DL's ->pick_task when fair server is enabled. In the indirect case, +* DL will set ->dl_server just after this function is called, so its Ok to +* clear. In the direct case, we are picking directly so we must clear it. +*/ +task_of (se)->dl_server =NULL ; +return task_of (se); }#endif
@@ -8643,7 +8651,16 @@ static bool fair_server_has_tasks(struct sched_dl_entity *dl_se)return !!dl_se->rq->cfs.nr_running; } -static struct task_struct *fair_server_pick (struct sched_dl_entity *dl_se) +static struct task_struct *fair_server_pick_task (struct sched_dl_entity *dl_se) +{ +#ifdef CONFIG_SMP +return pick_task_fair (dl_se->rq); +#else +return NULL ; +#endif +} + +static struct task_struct *fair_server_pick_next (struct sched_dl_entity *dl_se) {return pick_next_task_fair (dl_se->rq,NULL ,NULL ); }
@@ -8654,7 +8671,9 @@ void fair_server_init(struct rq *rq)init_dl_entity (dl_se); -dl_server_init (dl_se, rq, fair_server_has_tasks, fair_server_pick); +dl_server_init (dl_se, rq, fair_server_has_tasks, fair_server_pick_next, + fair_server_pick_task); + }/*
kernel/sched/sched.h +2 -1
@@ -354,7 +354,8 @@ extern void dl_server_start(struct sched_dl_entity *dl_se);extern void dl_server_stop (struct sched_dl_entity *dl_se);extern void dl_server_init (struct sched_dl_entity *dl_se,struct rq *rq,dl_server_has_tasks_f has_tasks, -dl_server_pick_f pick); +dl_server_pick_f pick_next, +dl_server_pick_f pick_task);extern void dl_server_update_idle_time (struct rq *rq,struct task_struct *p);
Signature · 1 line
2.45.1
[tip: sched/core] sched/core: Fix picking of tasks for core scheduling with DL server
The following commit has been merged into the sched/core branch of tip:
The following commit has been merged into the sched/core branch of tip:
Commit-ID: c8a85394cfdb4696b4e2f8a0f3066a1c921af426 Gitweb: https://git.kernel.org/tip/c8a85394cfdb4696b4e2f8a0f3066a1c921af426 Author: Joel Fernandes (Google) <[email protected]> AuthorDate: Mon, 27 May 2024 14:06:54 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 29 Jul 2024 12:22:37 +02:00
sched/core: Fix picking of tasks for core scheduling with DL server
* Use simple CFS pick_task for DL pick_task
DL server's pick_task calls CFS's pick_next_task_fair(), this is wrong because core scheduling's pick_task only calls CFS's pick_task() for evaluation / checking of the CFS task (comparing across CPUs), not for actually affirmatively picking the next task. This causes RB tree corruption issues in CFS that were found by syzbot.
* Make pick_task_fair clear DL server
A DL task pick might set ->dl_server, but it is possible the task will never run (say the other HT has a stop task). If the CFS task is picked in the future directly (say without DL server), ->dl_server will be set. So clear it in pick_task_fair().
This fixes the KASAN issue reported by syzbot in set_next_entity().
(DL refactoring suggestions by Vineeth Pillai).
--- include/linux/sched.h | 3 ++- kernel/sched/deadline.c | 27 ++++++++++++++++++++++----- kernel/sched/fair.c | 23 +++++++++++++++++++++-- kernel/sched/sched.h | 3 ++- 4 files changed, 47 insertions(+), 9 deletions(-)
include/linux/sched.h +2 -1
@@ -686,7 +686,8 @@ struct sched_dl_entity {*/ struct rq *rq;dl_server_has_tasks_f server_has_tasks; -dl_server_pick_f server_pick; +dl_server_pick_f server_pick_next; +dl_server_pick_f server_pick_task;#ifdef CONFIG_RT_MUTEXES /*
kernel/sched/deadline.c +22 -5
@@ -1664,11 +1664,13 @@ void dl_server_stop(struct sched_dl_entity *dl_se)void dl_server_init (struct sched_dl_entity *dl_se,struct rq *rq,dl_server_has_tasks_f has_tasks, -dl_server_pick_f pick) +dl_server_pick_f pick_next, +dl_server_pick_f pick_task) { dl_se->rq = rq; dl_se->server_has_tasks = has_tasks; - dl_se->server_pick = pick; + dl_se->server_pick_next = pick_next; + dl_se->server_pick_task = pick_task; }void __dl_server_attach_root (struct sched_dl_entity *dl_se,struct rq *rq)
@@ -2399,7 +2401,12 @@ static struct sched_dl_entity *pick_next_dl_entity(struct dl_rq *dl_rq)return __node_2_dle (left); } -static struct task_struct *pick_task_dl (struct rq *rq) +/* +* __pick_next_task_dl - Helper to pick the next -deadline task to run. +* @rq: The runqueue to pick the next task from. +* @peek: If true, just peek at the next task. Only relevant for dlserver. +*/ +static struct task_struct *__pick_next_task_dl (struct rq *rq,bool peek) {struct sched_dl_entity *dl_se;struct dl_rq *dl_rq = &rq->dl;
@@ -2413,7 +2420,10 @@ again:WARN_ON_ONCE (!dl_se);if (dl_server (dl_se)) { - p = dl_se->server_pick (dl_se); +if (IS_ENABLED (CONFIG_SMP ) && peek) + p = dl_se->server_pick_task (dl_se); +else + p = dl_se->server_pick_next (dl_se);if (!p) {WARN_ON_ONCE (1 ); dl_se->dl_yielded =1 ;
@@ -2428,11 +2438,18 @@ again:return p; } +#ifdef CONFIG_SMP +static struct task_struct *pick_task_dl (struct rq *rq) +{ +return __pick_next_task_dl (rq, true); +} +#endif +static struct task_struct *pick_next_task_dl (struct rq *rq) {struct task_struct *p; - p =pick_task_dl (rq); + p =__pick_next_task_dl (rq, false);if (!p)return p;
kernel/sched/fair.c +21 -2
@@ -8479,6 +8479,14 @@ again: cfs_rq = group_cfs_rq(se); }while (cfs_rq); +/* +* This can be called from directly from CFS's ->pick_task() or indirectly +* from DL's ->pick_task when fair server is enabled. In the indirect case, +* DL will set ->dl_server just after this function is called, so its Ok to +* clear. In the direct case, we are picking directly so we must clear it. +*/ +task_of (se)->dl_server =NULL ; +return task_of (se); }#endif
@@ -8638,7 +8646,16 @@ static bool fair_server_has_tasks(struct sched_dl_entity *dl_se)return !!dl_se->rq->cfs.nr_running; } -static struct task_struct *fair_server_pick (struct sched_dl_entity *dl_se) +static struct task_struct *fair_server_pick_task (struct sched_dl_entity *dl_se) +{ +#ifdef CONFIG_SMP +return pick_task_fair (dl_se->rq); +#else +return NULL ; +#endif +} + +static struct task_struct *fair_server_pick_next (struct sched_dl_entity *dl_se) {return pick_next_task_fair (dl_se->rq,NULL ,NULL ); }
@@ -8649,7 +8666,9 @@ void fair_server_init(struct rq *rq)init_dl_entity (dl_se); -dl_server_init (dl_se, rq, fair_server_has_tasks, fair_server_pick); +dl_server_init (dl_se, rq, fair_server_has_tasks, fair_server_pick_next, + fair_server_pick_task); + }/*
kernel/sched/sched.h +2 -1
@@ -361,7 +361,8 @@ extern void dl_server_start(struct sched_dl_entity *dl_se);extern void dl_server_stop (struct sched_dl_entity *dl_se);extern void dl_server_init (struct sched_dl_entity *dl_se,struct rq *rq,dl_server_has_tasks_f has_tasks, -dl_server_pick_f pick); +dl_server_pick_f pick_next, +dl_server_pick_f pick_task);extern void dl_server_update_idle_time (struct rq *rq,struct task_struct *p);
PATCH v7 9/9 sched/rt: Remove default bandwidth control
In reply to Daniel Bristot de OliveiraFrom: Peter Zijlstra <[email protected]>
Now that fair_server exists, we no longer need RT bandwidth control unless RT_GROUP_SCHED.
Enable fair_server with parameters equivalent to RT throttling.
--- kernel/sched/core.c | 9 +- kernel/sched/deadline.c | 5 +- kernel/sched/debug.c | 3 + kernel/sched/rt.c | 242 ++++++++++++++++++---------------------- kernel/sched/sched.h | 3 +- 5 files changed, 120 insertions(+), 142 deletions(-)
kernel/sched/core.c +6 -3
@@ -9987,8 +9987,6 @@ void __init sched_init(void)#endif /* CONFIG_RT_GROUP_SCHED */ } -init_rt_bandwidth (&def_rt_bandwidth,global_rt_period (),global_rt_runtime ()); -#ifdef CONFIG_SMP init_defrootdomain ();#endif
@@ -10043,8 +10041,13 @@ void __init sched_init(void)init_tg_cfs_entry (&root_task_group, &rq->cfs,NULL , i,NULL );#endif /* CONFIG_FAIR_GROUP_SCHED */ - rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;#ifdef CONFIG_RT_GROUP_SCHED +/* +* This is required for init cpu because rt.c:__enable_runtime() +* starts working after scheduler_running, which is not the case +* yet. +*/ + rq->rt.rt_runtime =global_rt_runtime ();init_tg_rt_entry (&root_task_group, &rq->rt,NULL , i,NULL );#endif #ifdef CONFIG_SMP
kernel/sched/deadline.c +3 -2
@@ -1554,6 +1554,7 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64if (dl_se == &rq->fair_server)return ; +#ifdef CONFIG_RT_GROUP_SCHED /* * Because -- for now -- we share the rt bandwidth, we need to * account our runtime there too, otherwise actual rt tasks
@@ -1578,6 +1579,7 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64 rt_rq->rt_time += delta_exec; raw_spin_unlock(&rt_rq->rt_runtime_lock); } +#endif }/*
@@ -1632,8 +1634,7 @@ void dl_server_start(struct sched_dl_entity *dl_se)* this before getting generic. */ if (!dl_server (dl_se)) { -/* Disabled */ -u64 runtime =0 ; +u64 runtime =50 *NSEC_PER_MSEC ;u64 period =1000 *NSEC_PER_MSEC ;dl_server_apply_params (dl_se, runtime, period,1 );
kernel/sched/debug.c +3 -0
@@ -889,9 +889,12 @@ void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) SEQ_printf(m, " .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rt_rq->x))PU (rt_nr_running); + +#ifdef CONFIG_RT_GROUP_SCHED P (rt_throttled);PN (rt_time);PN (rt_runtime); +#endif #undef PN#undef PU
kernel/sched/rt.c +107 -135
338 lines not on this page · raw message
kernel/sched/sched.h +1 -2
@@ -729,13 +729,13 @@ struct rt_rq {#endif /* CONFIG_SMP */ int rt_queued; +#ifdef CONFIG_RT_GROUP_SCHED int rt_throttled;u64 rt_time;u64 rt_runtime;/* Nests inside the rq lock: */ raw_spinlock_t rt_runtime_lock; -#ifdef CONFIG_RT_GROUP_SCHED unsigned int rt_nr_boosted;struct rq *rq;
@@ -2478,7 +2478,6 @@ extern void reweight_task(struct task_struct *p, int prio);extern void resched_curr (struct rq *rq);extern void resched_cpu (int cpu); -extern struct rt_bandwidth def_rt_bandwidth;extern void init_rt_bandwidth (struct rt_bandwidth *rt_b,u64 period,u64 runtime);extern bool sched_rt_bandwidth_account (struct rt_rq *rt_rq);
Signature · 1 line
2.45.1
[tip: sched/core] sched/rt: Remove default bandwidth control
The following commit has been merged into the sched/core branch of tip:
The following commit has been merged into the sched/core branch of tip:
Commit-ID: 5f6bd380c7bdbe10f7b4e8ddcceed60ce0714c6d Gitweb: https://git.kernel.org/tip/5f6bd380c7bdbe10f7b4e8ddcceed60ce0714c6d Author: Peter Zijlstra <[email protected]> AuthorDate: Mon, 27 May 2024 14:06:55 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Mon, 29 Jul 2024 12:22:37 +02:00
sched/rt: Remove default bandwidth control
Now that fair_server exists, we no longer need RT bandwidth control unless RT_GROUP_SCHED.
Enable fair_server with parameters equivalent to RT throttling.
--- kernel/sched/core.c | 9 +- kernel/sched/deadline.c | 5 +- kernel/sched/debug.c | 3 +- kernel/sched/rt.c | 242 +++++++++++++++++---------------------- kernel/sched/sched.h | 3 +- 5 files changed, 120 insertions(+), 142 deletions(-)
kernel/sched/core.c +6 -3
@@ -8266,8 +8266,6 @@ void __init sched_init(void)#endif /* CONFIG_RT_GROUP_SCHED */ } -init_rt_bandwidth (&def_rt_bandwidth,global_rt_period (),global_rt_runtime ()); -#ifdef CONFIG_SMP init_defrootdomain ();#endif
@@ -8322,8 +8320,13 @@ void __init sched_init(void)init_tg_cfs_entry (&root_task_group, &rq->cfs,NULL , i,NULL );#endif /* CONFIG_FAIR_GROUP_SCHED */ - rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;#ifdef CONFIG_RT_GROUP_SCHED +/* +* This is required for init cpu because rt.c:__enable_runtime() +* starts working after scheduler_running, which is not the case +* yet. +*/ + rq->rt.rt_runtime =global_rt_runtime ();init_tg_rt_entry (&root_task_group, &rq->rt,NULL , i,NULL );#endif #ifdef CONFIG_SMP
kernel/sched/deadline.c +3 -2
@@ -1554,6 +1554,7 @@ throttle:if (dl_se == &rq->fair_server)return ; +#ifdef CONFIG_RT_GROUP_SCHED /* * Because -- for now -- we share the rt bandwidth, we need to * account our runtime there too, otherwise actual rt tasks
@@ -1578,6 +1579,7 @@ throttle: rt_rq->rt_time += delta_exec; raw_spin_unlock(&rt_rq->rt_runtime_lock); } +#endif }/*
@@ -1632,8 +1634,7 @@ void dl_server_start(struct sched_dl_entity *dl_se)* this before getting generic. */ if (!dl_server (dl_se)) { -/* Disabled */ -u64 runtime =0 ; +u64 runtime =50 *NSEC_PER_MSEC ;u64 period =1000 *NSEC_PER_MSEC ;dl_server_apply_params (dl_se, runtime, period,1 );
kernel/sched/debug.c +3 -0
@@ -885,9 +885,12 @@ void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) SEQ_printf(m, " .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rt_rq->x))PU (rt_nr_running); + +#ifdef CONFIG_RT_GROUP_SCHED P (rt_throttled);PN (rt_time);PN (rt_runtime); +#endif #undef PN#undef PU
kernel/sched/rt.c +107 -135
338 lines not on this page · raw message
kernel/sched/sched.h +1 -2
@@ -729,13 +729,13 @@ struct rt_rq {#endif /* CONFIG_SMP */ int rt_queued; +#ifdef CONFIG_RT_GROUP_SCHED int rt_throttled;u64 rt_time;u64 rt_runtime;/* Nests inside the rq lock: */ raw_spinlock_t rt_runtime_lock; -#ifdef CONFIG_RT_GROUP_SCHED unsigned int rt_nr_boosted;struct rq *rq;
@@ -2519,7 +2519,6 @@ extern void reweight_task(struct task_struct *p, const struct load_weight *lw);extern void resched_curr (struct rq *rq);extern void resched_cpu (int cpu); -extern struct rt_bandwidth def_rt_bandwidth;extern void init_rt_bandwidth (struct rt_bandwidth *rt_b,u64 period,u64 runtime);extern bool sched_rt_bandwidth_account (struct rt_rq *rt_rq);
Re: [PATCH V7 9/9] sched/rt: Remove default bandwidth control
In reply to Daniel Bristot de OliveiraHello.
(I'm replying now as I installed v6.12 and this message has the context.)
Quoted 21 lines · Daniel Bristot de Oliveira
kernel/sched/deadline.c +2
-0@@ -1554,6 +1554,7 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64if (dl_se == &rq->fair_server)return ; +#ifdef CONFIG_RT_GROUP_SCHED /* * Because -- for now -- we share the rt bandwidth, we need to * account our runtime there too, otherwise actual rt tasks @@ -1578,6 +1579,7 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64 rt_rq->rt_time += delta_exec; raw_spin_unlock(&rt_rq->rt_runtime_lock); } +#endif }/*
kernel/sched/deadline.c void dl_server_start(struct sched_dl_entity *dl_se) · line 1640
Quoted 9 lines
kernel/sched/deadline.c +1
-2@@ -1632,8 +1634,7 @@ void dl_server_start(struct sched_dl_entity *dl_se)* this before getting generic. */ if (!dl_server (dl_se)) { -/* Disabled */ -u64 runtime =0 ; +u64 runtime =50 *NSEC_PER_MSEC ;u64 period =1000 *NSEC_PER_MSEC ;dl_server_apply_params (dl_se, runtime, period,1 );
The global_rt_runtime() also applies to deadline class when CPU's DL bandwidth is init'd in init_dl_rq_bw_ratio().
The default DL bandwidth is thus is 95%. The fair server is given 5%. Is that 5% of those 95%?
Or is it meant to be complementary? (Perhaps not as I can configure rt_runtime_us/rt_period_us > 95% without an error. But then I don't understand what the global rt_runtime_us (w/out CONFIG_RT_GROUP_SCHED) configures.)
Thanks for some hints,
Michal
Juri Lelli
maintainerRe: [PATCH V7 9/9] sched/rt: Remove default bandwidth control
Hi Michal,
Quoted 35 lines · Michal Koutný
Hello.
(I'm replying now as I installed v6.12 and this message has the context.)
Quoted 29 lines · Daniel Bristot de Oliveira
kernel/sched/deadline.c +3
-2@@ -1554,6 +1554,7 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64if (dl_se == &rq->fair_server)return ; +#ifdef CONFIG_RT_GROUP_SCHED /* * Because -- for now -- we share the rt bandwidth, we need to * account our runtime there too, otherwise actual rt tasks @@ -1578,6 +1579,7 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64 rt_rq->rt_time += delta_exec; raw_spin_unlock(&rt_rq->rt_runtime_lock); } +#endif }/* @@ -1632,8 +1634,7 @@ void dl_server_start(struct sched_dl_entity *dl_se)* this before getting generic. */ if (!dl_server (dl_se)) { -/* Disabled */ -u64 runtime =0 ; +u64 runtime =50 *NSEC_PER_MSEC ;u64 period =1000 *NSEC_PER_MSEC ;
Quoted 7 lines
kernel/sched/deadline.c void dl_server_start(struct sched_dl_entity *dl_se) · line 1640
Quoted 1 line
kernel/sched/deadline.c +0
-0dl_server_apply_params (dl_se, runtime, period,1 );The
global_rt_runtime()also applies to deadline class when CPU's DL bandwidth is init'd ininit_dl_rq_bw_ratio().The default DL bandwidth is thus is 95%. The fair server is given 5%. Is that 5% of those 95%?
Yes, it is indeed.
Best,
Juri
Re: [PATCH V7 9/9] sched/rt: Remove default bandwidth control
Quoted 4 lines · Juri Lelli
Quoted 2 lines
The default DL bandwidth is thus is 95%. The fair server is given 5%. Is that 5% of those 95%?
Yes, it is indeed.
Thanks for navigating me. I have followup questions about /proc/sys/kernel/sched_rt_runtime_us / /proc/sys/kernel/sched_rt_period_us (a ratio, without CONGIG_RT_GROUP_SCHED)
- 0
- disables DL, (not RT, so they can monopolize a CPU)
- 1
- DL tasks can monopolize CPU, SCHED_NORMAL have 5% thanks to fair_server
- 1-Δ
- SCHED_NORMAL tasks have
- (1-Δ)*5% on behalf of DL (above RT)
- Δ regularly (below RT)
Is this breakdown correct?
I'm wondering if different values of Δ mean anything or how they can be used.
Regards,
Michal
Juri Lelli
maintainerRe: [PATCH V7 9/9] sched/rt: Remove default bandwidth control
Quoted 20 lines · Michal Koutný
Quoted 4 lines · Juri Lelli
Quoted 2 lines
The default DL bandwidth is thus is 95%. The fair server is given 5%. Is that 5% of those 95%?
Yes, it is indeed.
Thanks for navigating me. I have followup questions about
/proc/sys/kernel/sched_rt_runtime_us//proc/sys/kernel/sched_rt_period_us(a ratio, withoutCONGIG_RT_GROUP_SCHED)- 0
- disables DL, (not RT, so they can monopolize a CPU)
- 1
- DL tasks can monopolize CPU,SCHED_NORMALhave 5% thanks tofair_server
- 1-Δ
-SCHED_NORMALtasks have
- (1-Δ)*5% on behalf of DL (above RT)
- Δ regularly (below RT)
Quoted 1 line
Is this breakdown correct?
So, sched_rt_runtime_us/sched_rt_period_us only applies to admission control (for DEADLINE tasks, including dl_servers). The actual parameters controlling the dl_server for SCHED_NORMAL are under sched/ debug as per-cpu values, e.g.:
# grep . /sys/kernel/debug/sched/fair_server/cpu*/* /sys/kernel/debug/sched/fair_server/cpu0/period:1000000000 /sys/kernel/debug/sched/fair_server/cpu0/runtime:50000000 /sys/kernel/debug/sched/fair_server/cpu1/period:1000000000 /sys/kernel/debug/sched/fair_server/cpu1/runtime:50000000 /sys/kernel/debug/sched/fair_server/cpu2/period:1000000000 /sys/kernel/debug/sched/fair_server/cpu2/runtime:50000000 /sys/kernel/debug/sched/fair_server/cpu3/period:1000000000 /sys/kernel/debug/sched/fair_server/cpu3/runtime:50000000 /sys/kernel/debug/sched/fair_server/cpu4/period:1000000000 /sys/kernel/debug/sched/fair_server/cpu4/runtime:50000000 /sys/kernel/debug/sched/fair_server/cpu5/period:1000000000 /sys/kernel/debug/sched/fair_server/cpu5/runtime:50000000 /sys/kernel/debug/sched/fair_server/cpu6/period:1000000000 /sys/kernel/debug/sched/fair_server/cpu6/runtime:50000000 /sys/kernel/debug/sched/fair_server/cpu7/period:1000000000 /sys/kernel/debug/sched/fair_server/cpu7/runtime:50000000
You can disable admission control by echoing -1 in sched_rt_runtime_us, but still have the dl_server working for SCHED_NORMAL tasks. By disabling admission control SCHED_DEADLINE can indeed monopolize CPU (over subscription).
Best,
Juri
Re: [PATCH V7 9/9] sched/rt: Remove default bandwidth control
Quoted 4 lines · Juri Lelli
You can disable admission control by echoing -1 in
sched_rt_runtime_us, but still have thedl_serverworking forSCHED_NORMALtasks. By disabling admission controlSCHED_DEADLINEcan indeed monopolize CPU (over subscription).
| I'm wondering if different values of Δ mean anything or how they can | be used.
Aha, the knob therefore remains relevant for the DL admission control.
So if I put it together, I will write it down like this:
-- 8< --
Subject: [PATCH] sched/RT: Update paragraphs about RT bandwidth control
This has slightly changed with the introductions of fair_server. Update the most relevant parts.
--- Documentation/scheduler/sched-deadline.rst | 13 +++++++------ Documentation/scheduler/sched-rt-group.rst | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-)
Documentation/scheduler/sched-deadline.rst +7 -6
@@ -591,12 +591,13 @@ Deadline Task Scheduling The system wide settings are configured under the /proc virtual file system. - For now the -rt knobs are used for -deadline admission control and the - -deadline runtime is accounted against the -rt runtime. We realize that this - isn't entirely desirable; however, it is better to have a small interface for - now, and be able to change it easily later. The ideal situation (see 5.) is to - run -rt tasks from a -deadline server; in which case the -rt bandwidth is a - direct subset of dl_bw. + For now the -rt knobs are used for -deadline admission control and with + CONFIG_RT_GROUP_SCHED the -deadline runtime is accounted against the (root) + -rt runtime. With !CONFIG_RT_GROUP_SCHED the knob only serves for the -dl + admission control. We realize that this isn't entirely desirable; however, it + is better to have a small interface for now, and be able to change it easily + later. The ideal situation (see 5.) is to run -rt tasks from a -deadline + server; in which case the -rt bandwidth is a direct subset of dl_bw. This means that, for a root_domain comprising M CPUs, -deadline tasks can be created while the sum of their bandwidths stays below:
Documentation/scheduler/sched-rt-group.rst +4 -4
@@ -92,10 +92,10 @@ The system wide settings are configured under the /proc virtual file system: /proc/sys/kernel/sched_rt_runtime_us: A global limit on how much time real-time scheduling may use. This is always less or equal to the period_us, as it denotes the time allocated from the - period_us for the real-time tasks. Even without CONFIG_RT_GROUP_SCHED enabled, - this will limit time reserved to real-time processes. With - CONFIG_RT_GROUP_SCHED=y it signifies the total bandwidth available to all - real-time groups. + period_us for the real-time tasks. Without CONFIG_RT_GROUP_SCHED enabled, + this only serves for admission control of deadline tasks. With + CONFIG_RT_GROUP_SCHED=y it also signifies the total bandwidth available to + all real-time groups. * Time is specified in us because the interface is s32. This gives an operating range from 1us to about 35 minutes.
Signature · 1 line
2.47.0
Re: [PATCH V7 9/9] sched/rt: Remove default bandwidth control
Quoted 6 lines · Michal Koutný
Quoted 4 lines · Juri Lelli
You can disable admission control by echoing -1 in
sched_rt_runtime_us, but still have thedl_serverworking forSCHED_NORMALtasks. By disabling admission controlSCHED_DEADLINEcan indeed monopolize CPU (over subscription).
Quoted 6 lines
| I'm wondering if different values of Δ mean anything or how they can | be used.
Aha, the knob therefore remains relevant for the DL admission control.
So if I put it together, I will write it down like this:
Ah, yes sounds good to me, thanks for writing it down properly! :)
If you send it out as a separate patch, please feel free to add
Best,
Juri
Hi Daniel,
Quoted 2 lines · Daniel Bristot de Oliveira
This is v7 of Peter's
SCHED_DEADLINEserver infrastructure implementation [1].
I finally managed to give this a go and can report that it works great for what I've seen. :)
So, please consider this reply a
Quoted 4 lines
SCHED_DEADLINEservers can help fixing starvation issues of low priority tasks (e.g.,SCHED_OTHER) when higher priority tasks monopolize CPU cycles. Today we have RT Throttling; DEADLINE servers should be able to replace and improve that.
...
Quoted 20 lines
The problem with DL server only implementation is that FIFO tasks might suffer preemption from NORMAL even when spare CPU cycles are available. In fact, fair deadline server is enqueued right away when NORMAL tasks wake up and they are first scheduled by the server, thus potentially preempting a well behaving FIFO task. This is of course not ideal.
We had discussions about it, and one of the possibilities would be using a different scheduling algorithm for this. But IMHO that is an overkill.
Juri and I discussed this and though about delaying the server activation for the (period - runtime), thus enabling the server only if the fair scheduler is about to starve. We called it the defer server.
The defer the server start to the (absolute deadline - runtime) point in time. This is achieved by starting the dl server throttled, with a next replenishing time set to activate the server at (absolute deadline - runtime).
Quoted 5 lines
The server is enqueued with the runtime replenished. As the fair scheduler runs without boost, its runtime is consumed. If the fair server has its runtime before the runtime - deadline time, the a new period is set, and the timer armed for the new deadline.
I also wanted to pay particular attention to this part implementing the deferred server, but failed to find enough focus time for now. I will keep trying. One thing that I wondered though is if this change (and the move towards this replacing current RT throttling) would call for a Doc update. What do you think?
Thanks!
Juri
Quoted 6 lines · Juri Lelli
Hi Daniel,
Quoted 2 lines · Daniel Bristot de Oliveira
This is v7 of Peter's
SCHED_DEADLINEserver infrastructure implementation [1].
Quoted 6 lines
I finally managed to give this a go and can report that it works great for what I've seen. :)
So, please consider this reply a
Tested-by Juri Lelli <[email protected]>
Thanks!
Quoted 33 lines
Quoted 4 lines
SCHED_DEADLINEservers can help fixing starvation issues of low priority tasks (e.g.,SCHED_OTHER) when higher priority tasks monopolize CPU cycles. Today we have RT Throttling; DEADLINE servers should be able to replace and improve that....
Quoted 20 lines
The problem with DL server only implementation is that FIFO tasks might suffer preemption from NORMAL even when spare CPU cycles are available. In fact, fair deadline server is enqueued right away when NORMAL tasks wake up and they are first scheduled by the server, thus potentially preempting a well behaving FIFO task. This is of course not ideal.
We had discussions about it, and one of the possibilities would be using a different scheduling algorithm for this. But IMHO that is an overkill.
Juri and I discussed this and though about delaying the server activation for the (period - runtime), thus enabling the server only if the fair scheduler is about to starve. We called it the defer server.
The defer the server start to the (absolute deadline - runtime) point in time. This is achieved by starting the dl server throttled, with a next replenishing time set to activate the server at (absolute deadline - runtime).
Quoted 5 lines
The server is enqueued with the runtime replenished. As the fair scheduler runs without boost, its runtime is consumed. If the fair server has its runtime before the runtime - deadline time, the a new period is set, and the timer armed for the new deadline.
Quoted 5 lines
I also wanted to pay particular attention to this part implementing the deferred server, but failed to find enough focus time for now. I will keep trying. One thing that I wondered though is if this change (and the move towards this replacing current RT throttling) would call for a Doc update. What do you think?
Yeah, am I planning a v8 for the next week. It has no code changes, just a rebase and the addition of documentation.
I am not mentioning the RT throttling in the documentation. Instead, I am treating this as a new feature on its own, which is inline with the comments over the code.
I will add an rv monitor to it, extending the documentation, but I will do it on another series... once we get this done.
Thoughts?
Peter/Ingo, which branch should I rebase it?
-- Daniel
Quoted 3 lines
Thanks!
Juri
Juri Lelli
maintainerQuoted 58 lines · Daniel Bristot de Oliveira
Quoted 6 lines · Juri Lelli
Hi Daniel,
Quoted 2 lines · Daniel Bristot de Oliveira
This is v7 of Peter's
SCHED_DEADLINEserver infrastructure implementation [1].Quoted 6 lines
I finally managed to give this a go and can report that it works great for what I've seen. :)
So, please consider this reply a
Tested-by Juri Lelli <[email protected]>Thanks!
Quoted 33 lines
Quoted 4 lines
SCHED_DEADLINEservers can help fixing starvation issues of low priority tasks (e.g.,SCHED_OTHER) when higher priority tasks monopolize CPU cycles. Today we have RT Throttling; DEADLINE servers should be able to replace and improve that....
Quoted 20 lines
The problem with DL server only implementation is that FIFO tasks might suffer preemption from NORMAL even when spare CPU cycles are available. In fact, fair deadline server is enqueued right away when NORMAL tasks wake up and they are first scheduled by the server, thus potentially preempting a well behaving FIFO task. This is of course not ideal.
We had discussions about it, and one of the possibilities would be using a different scheduling algorithm for this. But IMHO that is an overkill.
Juri and I discussed this and though about delaying the server activation for the (period - runtime), thus enabling the server only if the fair scheduler is about to starve. We called it the defer server.
The defer the server start to the (absolute deadline - runtime) point in time. This is achieved by starting the dl server throttled, with a next replenishing time set to activate the server at (absolute deadline - runtime).
Quoted 5 lines
The server is enqueued with the runtime replenished. As the fair scheduler runs without boost, its runtime is consumed. If the fair server has its runtime before the runtime - deadline time, the a new period is set, and the timer armed for the new deadline.
Quoted 5 lines
I also wanted to pay particular attention to this part implementing the deferred server, but failed to find enough focus time for now. I will keep trying. One thing that I wondered though is if this change (and the move towards this replacing current RT throttling) would call for a Doc update. What do you think?
Yeah, am I planning a v8 for the next week. It has no code changes, just a rebase and the addition of documentation.
Quoted 7 lines
I am not mentioning the RT throttling in the documentation. Instead, I am treating this as a new feature on its own, which is inline with the comments over the code.
I will add an rv monitor to it, extending the documentation, but I will do it on another series... once we get this done.
Thoughts?
Works for me! Guess we can deal with the RT throttling references in the future when that gets eventually pruned.
Hi Daniel,
Quoted 4 lines
This is v7 of Peter's
SCHED_DEADLINEserver infrastructure implementation [1].
Thanks for the v7 :-)
Sorry that I could not get to reviewing and testing this revision. In v6 we had experienced a minor bug where suspend/resume had issues with dlserver. Since suspend does not do dequeue, dlserver is not stopped and this causes the premature wakeups. I haven't looked at v7 in detail, but I think the issue might still be present. We have a workaround patch for this in our 5.15 kernel based on v5 which I am attaching for reference. This might not apply cleanly on v7 and possibly not be the best solution, but thought of sharing it to give an insight about the issue.
Thanks,
Vineeth
Attached patch
-----------------------
Subject: [PATCH] sched/dlserver: Freeze dlserver on system suspend.
dlserver is stopped only if a dequeue or cfs rq throttle results in no runnable cfs tasks. But this doesn't happen during a system suspend and can cause the dl server to stay active and break suspend/resume.
Freeze the dlserver on system suspend. Freezing is stopping the dlserver, but maintaining the dl_server_active state so as to not confuse the enqueue/dequeue path.
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/5528103
Commit-Queue: Vineeth Pillai <[email protected]>
--- include/linux/sched.h | 27 +++++++++++++ kernel/power/suspend.c | 3 ++ kernel/sched/deadline.c | 87 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 110 insertions(+), 7 deletions(-)
include/linux/sched.h +27 -0
@@ -650,6 +650,15 @@ struct sched_dl_entity { unsigned int dl_defer : 1; unsigned int dl_defer_armed : 1; unsigned int dl_server_active : 1; +/* +* dl_server is marked as frozen when the system suspends. Frozen +* means that dl_server is stopped, but the dl_server_active state +* is maintained so that the enqueue/dequeue path is not confused. +* We need this separate state other than dl_server_active because +* suspend doesn't dequeue the tasks and hence does not stop the +* dl_server during suspend. And this may lead to spurious resumes. +*/ + unsigned int dl_server_frozen : 1;/* * Bandwidth enforcement timer. Each -deadline task has its
@@ -690,6 +699,24 @@ struct sched_dl_entity {#endif }; +/* +* Power management related actions for dl_server +*/ +enum dl_server_pm_action { + dl_server_pm_freeze =0 , + dl_server_pm_thaw =1 +}; +extern void freeze_thaw_dl_server (enum dl_server_pm_action action); +static inline void freeze_dl_server (void ) +{ +freeze_thaw_dl_server (dl_server_pm_freeze); +} +static inline void thaw_dl_server (void ) +{ +freeze_thaw_dl_server (dl_server_pm_thaw); +} + +#ifdef CONFIG_UCLAMP_TASK /* Number of utilization clamp buckets (shorter alias) */ #define UCLAMP_BUCKETS CONFIG_UCLAMP_BUCKETS_COUNT
kernel/power/suspend.c +3 -0
@@ -592,6 +592,8 @@ static int enter_state(suspend_state_t state)if (error) goto Unlock; +freeze_dl_server (); +if (suspend_test (TEST_FREEZER )) goto Finish;
@@ -602,6 +604,7 @@ static int enter_state(suspend_state_t state)pm_restore_gfp_mask (); Finish: +thaw_dl_server (); events_check_enabled = false;pm_pr_dbg ("Finishing wakeup.\n" );suspend_finish ();
kernel/sched/deadline.c +0 -0
@@ -1478,10 +1478,11 @@ static void update_curr_dl_se(struct rq *rq,
struct sched_dl_entity *dl_se, s64
void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec) {
- update_curr_dl_se(dl_se->rq, dl_se, delta_exec);
+ if (!dl_se->dl_server_frozen)
+ update_curr_dl_se(dl_se->rq, dl_se, delta_exec);
}
-void dl_server_start(struct sched_dl_entity *dl_se)
+static inline void __dl_server_start(struct sched_dl_entity *dl_se)
{
/*
* XXX: the apply do not work fine at the init phase for the
@@ -1500,25 +1501,97 @@ void dl_server_start(struct sched_dl_entity *dl_se)
setup_new_dl_entity(dl_se);
}+ enqueue_dl_entity(dl_se, ENQUEUE_WAKEUP);
+}
+
+void dl_server_start(struct sched_dl_entity *dl_se) +{
+ if (dl_se->dl_server_frozen)
+ goto set_active;
+
if (WARN_ON_ONCE(dl_se->dl_server_active))
return;- enqueue_dl_entity(dl_se, ENQUEUE_WAKEUP);
+ __dl_server_start(dl_se);
+
+set_active:
dl_se->dl_server_active = 1;
}
-void dl_server_stop(struct sched_dl_entity *dl_se) +static inline void __dl_server_stop(struct sched_dl_entity *dl_se)
{
- if (WARN_ON_ONCE(!dl_se->dl_server_active))
- return;
-
dequeue_dl_entity(dl_se, DEQUEUE_SLEEP);
hrtimer_try_to_cancel(&dl_se->dl_timer);
dl_se->dl_defer_armed = 0;
dl_se->dl_throttled = 0;+}
+
+void dl_server_stop(struct sched_dl_entity *dl_se) +{
+ if (dl_se->dl_server_frozen)
+ goto reset_active;
+
+ if (WARN_ON_ONCE(!dl_se->dl_server_active))
+ return;
+
+ __dl_server_stop(dl_se);
+
+reset_active:
dl_se->dl_server_active = 0;
}
+void dl_server_freeze(struct sched_dl_entity *dl_se) +{
+ if (dl_se->dl_server_active) {
+ update_rq_clock(dl_se->rq);
+ __dl_server_stop(dl_se);
+ }
+ dl_se->dl_server_frozen = 1;
+}
+
+void dl_server_thaw(struct sched_dl_entity *dl_se) +{
+ if (dl_se->dl_server_active) {
+ update_rq_clock(dl_se->rq);
+ __dl_server_start(dl_se);
+ }
+ dl_se->dl_server_frozen = 0;
+}
+
+void freeze_thaw_dl_server(enum dl_server_pm_action action) +{
+ int cpu;
+
+ cpus_read_lock();
+ for_each_online_cpu(cpu) {
+ struct rq_flags rf;
+ struct rq *rq = cpu_rq(cpu);
+ struct sched_dl_entity *dl_se;
+
+ sched_clock_tick();
+ rq_lock_irqsave(rq, &rf);
+ dl_se = &rq->fair_server;
+ switch (action) {
+ case dl_server_pm_freeze:+ if (WARN_ON_ONCE(dl_se->dl_server_frozen))
+ break;
+
+ dl_server_freeze(dl_se);
+ break;
+ case dl_server_pm_thaw:
+ if (WARN_ON_ONCE(!dl_se->dl_server_frozen))
+ break;
+
+
+ dl_server_thaw(dl_se);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+ rq_unlock_irqrestore(rq, &rf);
+ }
+ cpus_read_unlock();
+}
+
void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
dl_server_has_tasks_f has_tasks, dl_server_pick_f pick_next,
Signature · 1 line
2.45.2.741.gdbec12cfda-goog
Quoted 4 lines · Vineeth Remanan Pillai
Sorry that I could not get to reviewing and testing this revision. In v6 we had experienced a minor bug where suspend/resume had issues with dlserver. Since suspend does not do dequeue, dlserver is not stopped and this causes the premature wakeups.
Ouch! I will have a look next week on this. Do you guys know any other bug?
an earlier report without necessarily a fix/work around is a good thing for us to try to reproduce it/think about it as earlier as we can...
-- Daniel
Quoted 7 lines · Daniel Bristot de Oliveira
Quoted 4 lines · Vineeth Remanan Pillai
Sorry that I could not get to reviewing and testing this revision. In v6 we had experienced a minor bug where suspend/resume had issues with dlserver. Since suspend does not do dequeue, dlserver is not stopped and this causes the premature wakeups.
Quoted 5 lines
Ouch! I will have a look next week on this. Do you guys know any other bug?
an earlier report without necessarily a fix/work around is a good thing for us to try to reproduce it/think about it as earlier as we can...
Sorry my mistake, I was buried in other things and missed reporting this earlier.
There was another minor regression seen lately after we fixed the above issue- idle cpu was spending more time in C7 than C10 with the dlserver changes. This was reported very recently and we haven't investigated this much yet. Just a heads up and will keep you posted as we know more.
Thanks,
Vineeth
Quoted 9 lines · Vineeth Remanan Pillai
Quoted 7 lines · Daniel Bristot de Oliveira
Quoted 4 lines · Vineeth Remanan Pillai
Sorry that I could not get to reviewing and testing this revision. In v6 we had experienced a minor bug where suspend/resume had issues with dlserver. Since suspend does not do dequeue, dlserver is not stopped and this causes the premature wakeups.
Quoted 7 lines
Quoted 5 lines
Ouch! I will have a look next week on this. Do you guys know any other bug?
an earlier report without necessarily a fix/work around is a good thing for us to try to reproduce it/think about it as earlier as we can...
Sorry my mistake, I was buried in other things and missed reporting this earlier.
no worries.
Quoted 6 lines
There was another minor regression seen lately after we fixed the above issue- idle cpu was spending more time in C7 than C10 with the dlserver changes. This was reported very recently and we haven't investigated this much yet. Just a heads up and will keep you posted as we know more.
Maybe that is an expected side effect because of the timer for the server, AFAIR you guys are using a short period large runtime (25ms/50ms)?
Quoted 2 lines
Thanks,
Vineeth
Peter Zijlstra
maintainerQuoted 5 lines · Vineeth Remanan Pillai
Sorry that I could not get to reviewing and testing this revision. In v6 we had experienced a minor bug where suspend/resume had issues with dlserver. Since suspend does not do dequeue, dlserver is not stopped and this causes the premature wakeups. I haven't looked at v7 in detail, but I think the issue might still be present.
It is not.
Quoted 1 line
We have a workaround patch for this in our 5.15 kernel
That is the problem... your necro kernel doesn't yet have the freezer rewrite I imagine:
f5d39b020809 ("freezer,sched: Rewrite core freezer logic")
That would cause all frozen tasks to be dequeued, and once all tasks are dequeued, the deadline server stops itself too.
Juri did some testing to double check and no suspend / resume issues were found.
Anyway, I've merged the lot into tip/sched/core.
Thanks all!
Quoted 13 lines · Peter Zijlstra
Quoted 5 lines · Vineeth Remanan Pillai
Sorry that I could not get to reviewing and testing this revision. In v6 we had experienced a minor bug where suspend/resume had issues with dlserver. Since suspend does not do dequeue, dlserver is not stopped and this causes the premature wakeups. I haven't looked at v7 in detail, but I think the issue might still be present.
It is not.
Quoted 1 line
We have a workaround patch for this in our 5.15 kernel
Quoted 8 lines
That is the problem... your necro kernel doesn't yet have the freezer rewrite I imagine:
f5d39b020809("freezer,sched: Rewrite core freezer logic")That would cause all frozen tasks to be dequeued, and once all tasks are dequeued, the deadline server stops itself too.
You're right, we are on 5.15 kernel and do not have this fix. Thanks for pointing this out.
Quoted 5 lines
Juri did some testing to double check and no suspend / resume issues were found.
Anyway, I've merged the lot into tip/sched/core.
Thanks, I shall port it to chromeos kernel and run through the usual round of tests and update the details soon.
Thanks,
Vineeth