Add a deadline server for sched_ext tasks
Subsystems (4)
Andrea Righi
reviewerPATCH RESEND v11 1/1 Add a deadline server for sched_ext tasks
This is a resend of the patch set originally posted here:
https://lore.kernel.org/all/[email protected]/
Re-sending to check whether there are any remaining objections. As discussed during the LPC sched_ext microconference in Tokyo, a potential "open issue" could be to define a better interface for configuring the assigned bandwidth for the DL servers (currently via debugfs). However, this shouldn't be a blocker and we can likely discuss this further at the upcoming OSPM.
Tejun, if there are no further comments, I think this series can be applied to sched_ext/for-6.20.
--
sched_ext tasks can be starved by long-running RT tasks, especially since RT throttling was replaced by deadline servers to boost only SCHED_NORMAL tasks.
Several users in the community have reported issues with RT stalling sched_ext tasks. This is fairly common on distributions or environments where applications like video compositors, audio services, etc. run as RT tasks by default.
Example trace (showing a per-CPU kthread stalled due to the sway Wayland compositor running as an RT task):
runnable task stall (kworker/0:0[106377] failed to run for 5.043s)
...
CPU 0 : nr_run=3 flags=0xd cpu_rel=0 ops_qseq=20646200 pnt_seq=45388738
curr=sway[994] class=rt_sched_class
R kworker/0:0[106377] -5043ms
scx_state/flags=3/0x1 dsq_flags=0x0 ops_state/qseq=0/0
sticky/holding_cpu=-1/-1 dsq_id=0x8000000000000002 dsq_vtime=0 slice=20000000
cpus=01This is often perceived as a bug in the BPF schedulers, but in reality they can't do much: RT tasks run outside their control and can potentially consume 100% of the CPU bandwidth.
Fix this by adding a sched_ext deadline server, so that sched_ext tasks are also boosted and do not suffer starvation.
Two kselftests are also provided to verify the starvation fixes and bandwidth allocation is correct.
== Design ==
- The EXT server is initialized at boot time and remains configured throughout the system's lifetime
- It starts automatically when the first sched_ext task is enqueued (rq->scx.nr_running == 1)
- The server's pick function (ext_server_pick_task) always selects sched_ext tasks when active
- Runtime accounting happens in update_curr_scx() during task execution and update_curr_idle() when idle
- Bandwidth accounting includes both fair and ext servers in root domain calculations
- A debugfs interface (/sys/kernel/debug/sched/ext_server/) allows runtime tuning of server parameters
== Highlights in this version ==
As discussed at the sched_ext microconference at LPC Tokyo, the plan is to start with a simpler approach, avoiding automatically creating or tearing down the EXT server bandwidth reservation when a BPF scheduler is loaded or unloaded. Instead, the reservation is kept permanently active. This significantly simplifies the logic while still addressing the starvation issue.
Any fine-tuning of the bandwidth reservation is delegated to the system administrator, who can adjust it via the debugfs interface. In the future, a more suitable interface can be introduced and automatic removal of the reservation when the BPF scheduler is unloaded can be revisited.
This patchset is also available in the following git branch:
git://git.kernel.org/pub/scm/linux/kernel/git/arighi/linux.git scx-dl-server
Changes in v11:
- do not create/remove the bandwidth reservation for the ext server when a BPF scheduler is loaded/unloaded, but keep the reservation bandwdith always active
- change rt_stall kselftest to validate both FAIR and EXT DL servers
- Link to v10: https://lore.kernel.org/all/[email protected]/
Changes in v10:
- reordered patches to better isolate sched_ext changes vs sched/deadline changes (Andrea Righi)
- define ext_server only with CONFIG_SCHED_CLASS_EXT=y (Andrea Righi)
- add WARN_ON_ONCE(!cpus) check in dl_server_apply_params() (Andrea Righi)
- wait for inactive_task_timer to fire before removing the bandwidth reservation (Juri Lelli)
- remove explicit dl_server_stop() in dequeue_task_scx() to reduce timer reprogramming overhead (Juri Lelli)
- do not restart pick_task() when invoked by the dl_server (Tejun Heo)
- rename rq_dl_server to dl_server (Peter Zijlstra)
- fixed a missing dl_server start in dl_server_on() (Christian Loehle)
- add a comment to the rt_stall selftest to better explain the 4% threshold (Emil Tsalapatis)
- Link to v9: https://lore.kernel.org/all/[email protected]/
Changes in v9:
- Drop the ->balance() logic as its functionality is now integrated into ->pick_task(), allowing dl_server to call pick_task_scx() directly
- Link to v8: https://lore.kernel.org/all/[email protected]/
Changes in v8:
- Add tj's patch to de-couple balance and pick_task and avoid changing sched/core callbacks to propagate @rf
- Simplify dl_se->dl_server check (suggested by PeterZ)
- Small coding style fixes in the kselftests
- Link to v7: https://lore.kernel.org/all/[email protected]/
Changes in v7:
- Rebased to Linus master
- Link to v6: https://lore.kernel.org/all/[email protected]/
Changes in v6:
- Added Acks to few patches
- Fixes to few nits suggested by Tejun
- Link to v5: https://lore.kernel.org/all/[email protected]/
Changes in v5:
- Added a kselftest (total_bw) to sched_ext to verify bandwidth values from debugfs
- Address comment from Andrea about redundant rq clock invalidation
- Link to v4: https://lore.kernel.org/all/[email protected]/
Changes in v4:
- Fixed issues with hotplugged CPUs having their DL server bandwidth altered due to loading SCX
- Fixed other issues
- Rebased on Linus master
- All sched_ext kselftests reliably pass now, also verified that the total_bw in debugfs (CONFIG_SCHED_DEBUG) is conserved with these patches
- Link to v3: https://lore.kernel.org/all/[email protected]/
Changes in v3:
- Removed code duplication in debugfs. Made ext interface separate
- Fixed issue where rq_lock_irqsave was not used in the relinquish patch
- Fixed running bw accounting issue in dl_server_remove_params
- Link to v2: https://lore.kernel.org/all/[email protected]/
Changes in v2:
- Fixed a hang related to using rq_lock instead of rq_lock_irqsave
- Added support to remove BW of DL servers when they are switched to/from EXT
- Link to v1: https://lore.kernel.org/all/[email protected]/
Andrea Righi (2):
sched_ext: Add a DL server for sched_ext tasks selftests/sched_ext: Add test for sched_ext dl_server
Joel Fernandes (5):
sched/deadline: Clear the defer params
sched/debug: Fix updating of ppos on server write ops sched/debug: Stop and start server based on if it was active sched/debug: Add support to change sched_ext server params selftests/sched_ext: Add test for DL server total_bw consistency
kernel/sched/core.c | 6 + kernel/sched/deadline.c | 87 +++++-- kernel/sched/debug.c | 171 +++++++++++--- kernel/sched/ext.c | 33 +++ kernel/sched/idle.c | 3 + kernel/sched/sched.h | 2 + kernel/sched/topology.c | 5 + tools/testing/selftests/sched_ext/Makefile | 2 + tools/testing/selftests/sched_ext/rt_stall.bpf.c | 23 ++ tools/testing/selftests/sched_ext/rt_stall.c | 240 +++++++++++++++++++ tools/testing/selftests/sched_ext/total_bw.c | 281 +++++++++++++++++++++++ 11 files changed, 802 insertions(+), 51 deletions(-) create mode 100644 tools/testing/selftests/sched_ext/rt_stall.bpf.c create mode 100644 tools/testing/selftests/sched_ext/rt_stall.c create mode 100644 tools/testing/selftests/sched_ext/total_bw.c
Andrea Righi
reviewerPATCH 1/7 sched/deadline: Clear the defer params
From: Joel Fernandes <[email protected]>
The defer params were not cleared in __dl_clear_params. Clear them.
Without this is some of my test cases are flaking and the DL timer is not starting correctly AFAICS.
--- kernel/sched/deadline.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/sched/deadline.c +3 -0
@@ -3644,6 +3644,9 @@ static void __dl_clear_params(struct sched_dl_entity *dl_se) dl_se->dl_non_contending =0 ; dl_se->dl_overrun =0 ; dl_se->dl_server =0 ; + dl_se->dl_defer =0 ; + dl_se->dl_defer_running =0 ; + dl_se->dl_defer_armed =0 ;#ifdef CONFIG_RT_MUTEXES dl_se->pi_se = dl_se;
Signature · 1 line
2.52.0
Andrea Righi
reviewerPATCH 2/7 sched/debug: Fix updating of ppos on server write ops
In reply to Andrea RighiFrom: Joel Fernandes <[email protected]>
Updating "ppos" on error conditions does not make much sense. The pattern is to return the error code directly without modifying the position, or modify the position on success and return the number of bytes written.
Since on success, the return value of apply is 0, there is no point in modifying ppos either. Fix it by removing all this and just returning error code or number of bytes written on success.
--- kernel/sched/debug.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
kernel/sched/debug.c +4 -3
@@ -345,8 +345,8 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubulong cpu = (long ) ((struct seq_file *) filp->private_data)->private;struct rq *rq =cpu_rq (cpu);u64 runtime, period; +int retval =0 ;size_t err; -int retval;u64 value; err =kstrtoull_from_user (ubuf, cnt,10 , &value);
@@ -380,8 +380,6 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubudl_server_stop (&rq->fair_server); retval =dl_server_apply_params (&rq->fair_server, runtime, period,0 ); -if (retval) - cnt = retval;if (!runtime) printk_deferred("Fair server disabled in CPU %d, system may crash due to starvation.\n",
@@ -389,6 +387,9 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubuif (rq->cfs.h_nr_queued)dl_server_start (&rq->fair_server); + +if (retval <0 ) +return retval; } *ppos += cnt;
Signature · 1 line
2.52.0
Andrea Righi
reviewerPATCH 3/7 sched/debug: Stop and start server based on if it was active
In reply to Andrea RighiFrom: Joel Fernandes <[email protected]>
Currently the DL server interface for applying parameters checks CFS-internals to identify if the server is active. This is error-prone and makes it difficult when adding new servers in the future.
Fix it, by using dl_server_active() which is also used by the DL server code to determine if the DL server was started.
v2: do not start the server if runtime is zero (Juri Lelli)
--- kernel/sched/debug.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
kernel/sched/debug.c +8 -3
@@ -354,6 +354,8 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubureturn err; scoped_guard (rq_lock_irqsave, rq) { +bool is_active; + runtime = rq->fair_server.dl_runtime; period = rq->fair_server.dl_period;
@@ -376,8 +378,11 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubureturn -EINVAL ; } -update_rq_clock (rq); -dl_server_stop (&rq->fair_server); + is_active =dl_server_active (&rq->fair_server); +if (is_active) { +update_rq_clock (rq); +dl_server_stop (&rq->fair_server); + } retval =dl_server_apply_params (&rq->fair_server, runtime, period,0 );
@@ -385,7 +390,7 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubuprintk_deferred ("Fair server disabled in CPU %d, system may crash due to starvation.\n" ,cpu_of (rq)); -if (rq->cfs.h_nr_queued) +if (is_active && runtime)dl_server_start (&rq->fair_server);if (retval <0 )
Signature · 1 line
2.52.0
Andrea Righi
reviewerPATCH 4/7 sched_ext: Add a DL server for sched_ext tasks
In reply to Andrea Righisched_ext currently suffers starvation due to RT. The same workload when converted to EXT can get zero runtime if RT is 100% running, causing EXT processes to stall. Fix it by adding a DL server for EXT.
A kselftest is also included later to confirm that both DL servers are functioning correctly:
# ./runner -t rt_stall ===== START ===== TEST: rt_stall DESCRIPTION: Verify that RT tasks cannot stall SCHED_EXT tasks OUTPUT: TAP version 13 1..1 # Runtime of FAIR task (PID 1511) is 0.250000 seconds # Runtime of RT task (PID 1512) is 4.750000 seconds # FAIR task got 5.00% of total runtime ok 1 PASS: FAIR task got more than 4.00% of runtime TAP version 13 1..1 # Runtime of EXT task (PID 1514) is 0.250000 seconds # Runtime of RT task (PID 1515) is 4.750000 seconds # EXT task got 5.00% of total runtime ok 2 PASS: EXT task got more than 4.00% of runtime TAP version 13 1..1 # Runtime of FAIR task (PID 1517) is 0.250000 seconds # Runtime of RT task (PID 1518) is 4.750000 seconds # FAIR task got 5.00% of total runtime ok 3 PASS: FAIR task got more than 4.00% of runtime TAP version 13 1..1 # Runtime of EXT task (PID 1521) is 0.250000 seconds # Runtime of RT task (PID 1522) is 4.750000 seconds # EXT task got 5.00% of total runtime ok 4 PASS: EXT task got more than 4.00% of runtime ok 1 rt_stall # ===== END =====
v5: - do not restart the EXT server on switch_class() (Juri Lelli)
v4: - initialize EXT server bandwidth reservation at init time and
always keep it active (Andrea Righi)
- check for rq->nr_running == 1 to determine when to account idle time (Juri Lelli)
v3: - clarify that fair is not the only dl_server (Juri Lelli)
- remove explicit stop to reduce timer reprogramming overhead (Juri Lelli)
- do not restart pick_task() when it's invoked by the dl_server (Tejun Heo)
- depend on CONFIG_SCHED_CLASS_EXT (Andrea Righi)
v2: - drop ->balance() now that pick_task() has an rf argument
(Andrea Righi)
--- kernel/sched/core.c | 6 +++ kernel/sched/deadline.c | 84 ++++++++++++++++++++++++++++++----------- kernel/sched/ext.c | 33 ++++++++++++++++ kernel/sched/idle.c | 3 ++ kernel/sched/sched.h | 2 + kernel/sched/topology.c | 5 +++ 6 files changed, 110 insertions(+), 23 deletions(-)
kernel/sched/core.c +6 -0
@@ -8477,6 +8477,9 @@ int sched_cpu_dying(unsigned int cpu)dump_rq_tasks (rq,KERN_WARNING ); }dl_server_stop (&rq->fair_server); +#ifdef CONFIG_SCHED_CLASS_EXT +dl_server_stop (&rq->ext_server); +#endif rq_unlock_irqrestore (rq, &rf);calc_load_migrate (rq);
@@ -8680,6 +8683,9 @@ void __init sched_init(void)hrtick_rq_init (rq);atomic_set (&rq->nr_iowait,0 );fair_server_init (rq); +#ifdef CONFIG_SCHED_CLASS_EXT +ext_server_init (rq); +#endif #ifdef CONFIG_SCHED_CORE rq->core = rq;
kernel/sched/deadline.c +61 -23
152 lines not on this page · raw message
kernel/sched/ext.c +33 -0
@@ -958,6 +958,8 @@ static void update_curr_scx(struct rq *rq)if (!curr->scx.slice)touch_core_sched (rq, curr); } + +dl_server_update (&rq->ext_server, delta_exec); } static bool scx_dsq_priq_less(struct rb_node *node_a,
@@ -1501,6 +1503,10 @@ static void enqueue_task_scx(struct rq *rq, struct task_struct *p, int enq_flagsif (enq_flags &SCX_ENQ_WAKEUP )touch_core_sched (rq, p); +/* Start dl_server if this is the first task being enqueued */ +if (rq->scx.nr_running ==1 ) +dl_server_start (&rq->ext_server); +do_enqueue_task (rq, p, enq_flags, sticky_cpu); out: rq->scx.flags &= ~SCX_RQ_IN_WAKEUP ;
@@ -2512,6 +2518,33 @@ static struct task_struct *pick_task_scx(struct rq *rq, struct rq_flags *rf)return do_pick_task_scx (rq, rf, false); } +/* +* Select the next task to run from the ext scheduling class. +* +* Use do_pick_task_scx() directly with @force_scx enabled, since the +* dl_server must always select a sched_ext task. +*/ +static struct task_struct * +ext_server_pick_task (struct sched_dl_entity *dl_se,struct rq_flags *rf) +{ +if (!scx_enabled ()) +return NULL ; + +return do_pick_task_scx (dl_se->rq, rf, true); +} + +/* +* Initialize the ext server deadline entity. +*/ +void ext_server_init (struct rq *rq) +{ +struct sched_dl_entity *dl_se = &rq->ext_server; + +init_dl_entity (dl_se); + +dl_server_init (dl_se, rq, ext_server_pick_task); +} +#ifdef CONFIG_SCHED_CORE /** * scx_prio_less - Task ordering for core-sched
kernel/sched/idle.c +3 -0
@@ -530,6 +530,9 @@ static void update_curr_idle(struct rq *rq) se->exec_start = now;dl_server_update_idle (&rq->fair_server, delta_exec); +#ifdef CONFIG_SCHED_CLASS_EXT +dl_server_update_idle (&rq->ext_server, delta_exec); +#endif }/*
kernel/sched/sched.h +2 -0
@@ -414,6 +414,7 @@ extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,extern void sched_init_dl_servers (void );extern void fair_server_init (struct rq *rq); +extern void ext_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);
@@ -1151,6 +1152,7 @@ struct rq {struct dl_rq dl;#ifdef CONFIG_SCHED_CLASS_EXT struct scx_rq scx; +struct sched_dl_entity ext_server;#endif struct sched_dl_entity fair_server;
kernel/sched/topology.c +5 -0
@@ -508,6 +508,11 @@ void rq_attach_root(struct rq *rq, struct root_domain *rd)if (rq->fair_server.dl_server)__dl_server_attach_root (&rq->fair_server, rq); +#ifdef CONFIG_SCHED_CLASS_EXT +if (rq->ext_server.dl_server) +__dl_server_attach_root (&rq->ext_server, rq); +#endif +rq_unlock_irqrestore (rq, &rf);if (old_rd)
Signature · 1 line
2.52.0
Peter Zijlstra
maintainerRe: [PATCH 4/7] sched_ext: Add a DL server for sched_ext tasks
kernel/sched/deadline.c void dl_server_stop(struct sched_dl_entity *dl_se) · line 1819
Quoted 8 lines · Andrea Righi
kernel/sched/deadline.c +1
-0@@ -1813,6 +1813,7 @@ void dl_server_stop(struct sched_dl_entity *dl_se)hrtimer_try_to_cancel (&dl_se->dl_timer); dl_se->dl_defer_armed =0 ; dl_se->dl_throttled =0 ; + dl_se->dl_defer_running =0 ; dl_se->dl_defer_idle =0 ; dl_se->dl_server_active =0 ; }
This should definitely not be in this patch. Why was this added? Were you trying to do the same as:
ca1e8eede4fc ("sched/deadline: Fix server stopping with runnable tasks")
Andrea Righi
reviewerRe: [PATCH 4/7] sched_ext: Add a DL server for sched_ext tasks
Quoted 14 lines · Peter Zijlstra
kernel/sched/deadline.c void dl_server_stop(struct sched_dl_entity *dl_se) · line 1819
Quoted 8 lines · Andrea Righi
kernel/sched/deadline.c +1
-0@@ -1813,6 +1813,7 @@ void dl_server_stop(struct sched_dl_entity *dl_se)hrtimer_try_to_cancel (&dl_se->dl_timer); dl_se->dl_defer_armed =0 ; dl_se->dl_throttled =0 ; + dl_se->dl_defer_running =0 ; dl_se->dl_defer_idle =0 ; dl_se->dl_server_active =0 ; }This should definitely not be in this patch. Why was this added? Were you trying to do the same as:
Quoted 2 lines
ca1e8eede4fc("sched/deadline: Fix server stopping with runnable tasks")
The problem is that if remove this, RT can completely stall EXT tasks, also with ca1e8eede4fc applied.
Example (with the rt_stall kselftest):
# Runtime of EXT task (PID 2100) is 0.000000 seconds # Runtime of RT task (PID 2101) is 4.990000 seconds # EXT task got 0.00% of total runtime
not ok 2 FAIL: EXT task got less than 4.00% of runtime
Thanks,
-Andrea
Peter Zijlstra
maintainerRe: [PATCH 4/7] sched_ext: Add a DL server for sched_ext tasks
Quoted 15 lines · Andrea Righi
Quoted 14 lines · Peter Zijlstra
kernel/sched/deadline.c void dl_server_stop(struct sched_dl_entity *dl_se) · line 1819
Quoted 8 lines · Andrea Righi
kernel/sched/deadline.c +1
-0@@ -1813,6 +1813,7 @@ void dl_server_stop(struct sched_dl_entity *dl_se)hrtimer_try_to_cancel (&dl_se->dl_timer); dl_se->dl_defer_armed =0 ; dl_se->dl_throttled =0 ; + dl_se->dl_defer_running =0 ; dl_se->dl_defer_idle =0 ; dl_se->dl_server_active =0 ; }This should definitely not be in this patch. Why was this added? Were you trying to do the same as:
Quoted 5 lines
Quoted 2 lines
ca1e8eede4fc("sched/deadline: Fix server stopping with runnable tasks")The problem is that if remove this, RT can completely stall EXT tasks, also with
ca1e8eede4fcapplied.
But that's not something ext specific, right? Can you pull this change out and write a sane Changelog for it, describing the problem and so?
Andrea Righi
reviewerRe: [PATCH 4/7] sched_ext: Add a DL server for sched_ext tasks
Quoted 16 lines · Peter Zijlstra
Quoted 15 lines · Andrea Righi
Quoted 14 lines · Peter Zijlstra
kernel/sched/deadline.c void dl_server_stop(struct sched_dl_entity *dl_se) · line 1819
Quoted 8 lines · Andrea Righi
kernel/sched/deadline.c +1
-0@@ -1813,6 +1813,7 @@ void dl_server_stop(struct sched_dl_entity *dl_se)hrtimer_try_to_cancel (&dl_se->dl_timer); dl_se->dl_defer_armed =0 ; dl_se->dl_throttled =0 ; + dl_se->dl_defer_running =0 ; dl_se->dl_defer_idle =0 ; dl_se->dl_server_active =0 ; }This should definitely not be in this patch. Why was this added? Were you trying to do the same as:
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
ca1e8eede4fc("sched/deadline: Fix server stopping with runnable tasks")The problem is that if remove this, RT can completely stall EXT tasks, also with
ca1e8eede4fcapplied.But that's not something ext specific, right? Can you pull this change out and write a sane Changelog for it, describing the problem and so?
Yeah, this should happen with fair as well. I'll try to reproduce the problem without ext and try to get more info.
Thanks,
-Andrea
Peter Zijlstra
maintainerRe: [PATCH 4/7] sched_ext: Add a DL server for sched_ext tasks
In reply to Andrea RighiQuoted 39 lines · Andrea Righi
sched_extcurrently suffers starvation due to RT. The same workload when converted to EXT can get zero runtime if RT is 100% running, causing EXT processes to stall. Fix it by adding a DL server for EXT.A kselftest is also included later to confirm that both DL servers are functioning correctly:
# ./runner -t rt_stall ===== START ===== TEST: rt_stall DESCRIPTION: Verify that RT tasks cannot stall SCHED_EXT tasks OUTPUT: TAP version 13 1..1 # Runtime of FAIR task (PID 1511) is 0.250000 seconds # Runtime of RT task (PID 1512) is 4.750000 seconds # FAIR task got 5.00% of total runtime ok 1 PASS: FAIR task got more than 4.00% of runtime TAP version 13 1..1 # Runtime of EXT task (PID 1514) is 0.250000 seconds # Runtime of RT task (PID 1515) is 4.750000 seconds # EXT task got 5.00% of total runtime ok 2 PASS: EXT task got more than 4.00% of runtime TAP version 13 1..1 # Runtime of FAIR task (PID 1517) is 0.250000 seconds # Runtime of RT task (PID 1518) is 4.750000 seconds # FAIR task got 5.00% of total runtime ok 3 PASS: FAIR task got more than 4.00% of runtime TAP version 13 1..1 # Runtime of EXT task (PID 1521) is 0.250000 seconds # Runtime of RT task (PID 1522) is 4.750000 seconds # EXT task got 5.00% of total runtime ok 4 PASS: EXT task got more than 4.00% of runtime ok 1 rt_stall # ===== END =====
Quoted 13 lines
v5: - do not restart the EXT server on
switch_class()(Juri Lelli)
v4: - initialize EXT server bandwidth reservation at init time and
always keep it active (Andrea Righi)
- check forrq->nr_running== 1 to determine when to account idle time (Juri Lelli)
v3: - clarify that fair is not the onlydl_server(Juri Lelli)
- remove explicit stop to reduce timer reprogramming overhead (Juri Lelli)
- do not restartpick_task()when it's invoked by thedl_server(Tejun Heo)
- depend onCONFIG_SCHED_CLASS_EXT(Andrea Righi)
v2: - drop ->balance() now thatpick_task()has an rf argument
(Andrea Righi)
FWIW (for all these patches), those v# comments, they go...
Quoted 6 lines
Reviewed-by Juri Lelli <[email protected]>Tested-by Christian Loehle <[email protected]>Co-developed-by Joel Fernandes <[email protected]>Signed-off-by Joel Fernandes <[email protected]>Signed-off-by Andrea Righi <[email protected]>---
... here, after the ---.
Andrea Righi
reviewerRe: [PATCH 4/7] sched_ext: Add a DL server for sched_ext tasks
On Wed, Jan 21, 2026 at 01:31:58PM +0100, Peter Zijlstra wrote:
...
Quoted 16 lines
Quoted 5 lines
v5: - do not restart the EXT server on
switch_class()(Juri Lelli)
v4: - initialize EXT server bandwidth reservation at init time and
always keep it active (Andrea Righi)
- check forrq->nr_running== 1 to determine when to account idle time (Juri Lelli)Quoted 8 lines
v3: - clarify that fair is not the only
dl_server(Juri Lelli)
- remove explicit stop to reduce timer reprogramming overhead (Juri Lelli)
- do not restartpick_task()when it's invoked by thedl_server(Tejun Heo)
- depend onCONFIG_SCHED_CLASS_EXT(Andrea Righi)
v2: - drop ->balance() now thatpick_task()has an rf argument
(Andrea Righi)FWIW (for all these patches), those v# comments, they go...
Quoted 8 lines
Quoted 6 lines
Reviewed-by Juri Lelli <[email protected]>Tested-by Christian Loehle <[email protected]>Co-developed-by Joel Fernandes <[email protected]>Signed-off-by Joel Fernandes <[email protected]>Signed-off-by Andrea Righi <[email protected]>---
... here, after the ---.
Oh... I used to do it this way, then noticed others were including the version in the patch and I started doing the same, I’ll revert to my original way. :)
Thanks,
-Andrea
Andrea Righi
reviewerPATCH 5/7 sched/debug: Add support to change sched_ext server params
In reply to Andrea RighiFrom: Joel Fernandes <[email protected]>
When a sched_ext server is loaded, tasks in the fair class are automatically moved to the sched_ext class. Add support to modify the ext server parameters similar to how the fair server parameters are modified.
Re-use common code between ext and fair servers as needed.
v2: - use dl_se->dl_server to determine if dl_se is a DL server
(Peter Zijlstra)
- depend on CONFIG_SCHED_CLASS_EXT (Andrea Righi)
--- kernel/sched/debug.c | 157 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 133 insertions(+), 24 deletions(-)
kernel/sched/debug.c +133 -24
@@ -336,14 +336,16 @@ enum dl_param { DL_PERIOD, }; -static unsigned long fair_server_period_max = (1UL <<22 ) *NSEC_PER_USEC ;/* ~4 seconds */ -static unsigned long fair_server_period_min = (100 ) *NSEC_PER_USEC ;/* 100 us */ +static unsigned long dl_server_period_max = (1UL <<22 ) *NSEC_PER_USEC ;/* ~4 seconds */ +static unsigned long dl_server_period_min = (100 ) *NSEC_PER_USEC ;/* 100 us */ -static ssize_t sched_fair_server_write (struct file *filp,const char __user *ubuf, -size_t cnt,loff_t *ppos,enum dl_param param) +static ssize_t sched_server_write_common (struct file *filp,const char __user *ubuf, +size_t cnt,loff_t *ppos,enum dl_param param, +void *server) {long cpu = (long ) ((struct seq_file *) filp->private_data)->private;struct rq *rq =cpu_rq (cpu); +struct sched_dl_entity *dl_se = (struct sched_dl_entity *)server;u64 runtime, period;int retval =0 ;size_t err;
@@ -356,8 +358,8 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubu scoped_guard (rq_lock_irqsave, rq) {bool is_active; - runtime = rq->fair_server.dl_runtime; - period = rq->fair_server.dl_period; + runtime = dl_se->dl_runtime; + period = dl_se->dl_period;switch (param) {case DL_RUNTIME :
@@ -373,25 +375,25 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubu }if (runtime > period || - period > fair_server_period_max || - period < fair_server_period_min) { + period > dl_server_period_max || + period < dl_server_period_min) {return -EINVAL ; } - is_active =dl_server_active (&rq->fair_server); + is_active =dl_server_active (dl_se);if (is_active) {update_rq_clock (rq); -dl_server_stop (&rq->fair_server); +dl_server_stop (dl_se); } - retval =dl_server_apply_params (&rq->fair_server, runtime, period,0 ); + retval =dl_server_apply_params (dl_se, runtime, period,0 );if (!runtime) -printk_deferred ("Fair server disabled in CPU %d, system may crash due to starvation.\n" , -cpu_of (rq)); +printk_deferred ("%s server disabled in CPU %d, system may crash due to starvation.\n" , + server == &rq->fair_server ?"Fair" :"Ext" ,cpu_of (rq));if (is_active && runtime) -dl_server_start (&rq->fair_server); +dl_server_start (dl_se);if (retval <0 )return retval;
@@ -401,36 +403,42 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubureturn cnt; } -static size_t sched_fair_server_show (struct seq_file *m,void *v,enum dl_param param) +static size_t sched_server_show_common (struct seq_file *m,void *v,enum dl_param param, +void *server) { -unsigned long cpu = (unsigned long ) m->private; -struct rq *rq =cpu_rq (cpu); +struct sched_dl_entity *dl_se = (struct sched_dl_entity *)server;u64 value;switch (param) {case DL_RUNTIME : - value = rq->fair_server.dl_runtime; + value = dl_se->dl_runtime;break ;case DL_PERIOD : - value = rq->fair_server.dl_period; + value = dl_se->dl_period;break ; }seq_printf (m,"%llu\n" , value);return 0 ; - }static ssize_t sched_fair_server_runtime_write (struct file *filp,const char __user *ubuf,size_t cnt,loff_t *ppos) { -return sched_fair_server_write (filp, ubuf, cnt, ppos,DL_RUNTIME ); +long cpu = (long ) ((struct seq_file *) filp->private_data)->private; +struct rq *rq =cpu_rq (cpu); + +return sched_server_write_common (filp, ubuf, cnt, ppos,DL_RUNTIME , + &rq->fair_server); }static int sched_fair_server_runtime_show (struct seq_file *m,void *v) { -return sched_fair_server_show (m, v,DL_RUNTIME ); +unsigned long cpu = (unsigned long ) m->private; +struct rq *rq =cpu_rq (cpu); + +return sched_server_show_common (m, v,DL_RUNTIME , &rq->fair_server); }static int sched_fair_server_runtime_open (struct inode *inode,struct file *filp)
@@ -446,16 +454,57 @@ static const struct file_operations fair_server_runtime_fops = { .release = single_release, }; +#ifdef CONFIG_SCHED_CLASS_EXT +static ssize_t +sched_ext_server_runtime_write (struct file *filp,const char __user *ubuf, +size_t cnt,loff_t *ppos) +{ +long cpu = (long ) ((struct seq_file *) filp->private_data)->private; +struct rq *rq =cpu_rq (cpu); + +return sched_server_write_common (filp, ubuf, cnt, ppos,DL_RUNTIME , + &rq->ext_server); +} + +static int sched_ext_server_runtime_show (struct seq_file *m,void *v) +{ +unsigned long cpu = (unsigned long ) m->private; +struct rq *rq =cpu_rq (cpu); + +return sched_server_show_common (m, v,DL_RUNTIME , &rq->ext_server); +} + +static int sched_ext_server_runtime_open (struct inode *inode,struct file *filp) +{ +return single_open (filp, sched_ext_server_runtime_show, inode->i_private); +} + +static const struct file_operations ext_server_runtime_fops = { + .open = sched_ext_server_runtime_open, + .write = sched_ext_server_runtime_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* CONFIG_SCHED_CLASS_EXT */ +static ssize_t sched_fair_server_period_write (struct file *filp,const char __user *ubuf,size_t cnt,loff_t *ppos) { -return sched_fair_server_write (filp, ubuf, cnt, ppos,DL_PERIOD ); +long cpu = (long ) ((struct seq_file *) filp->private_data)->private; +struct rq *rq =cpu_rq (cpu); + +return sched_server_write_common (filp, ubuf, cnt, ppos,DL_PERIOD , + &rq->fair_server); }static int sched_fair_server_period_show (struct seq_file *m,void *v) { -return sched_fair_server_show (m, v,DL_PERIOD ); +unsigned long cpu = (unsigned long ) m->private; +struct rq *rq =cpu_rq (cpu); + +return sched_server_show_common (m, v,DL_PERIOD , &rq->fair_server); }static int sched_fair_server_period_open (struct inode *inode,struct file *filp)
@@ -471,6 +520,40 @@ static const struct file_operations fair_server_period_fops = { .release = single_release, }; +#ifdef CONFIG_SCHED_CLASS_EXT +static ssize_t +sched_ext_server_period_write (struct file *filp,const char __user *ubuf, +size_t cnt,loff_t *ppos) +{ +long cpu = (long ) ((struct seq_file *) filp->private_data)->private; +struct rq *rq =cpu_rq (cpu); + +return sched_server_write_common (filp, ubuf, cnt, ppos,DL_PERIOD , + &rq->ext_server); +} + +static int sched_ext_server_period_show (struct seq_file *m,void *v) +{ +unsigned long cpu = (unsigned long ) m->private; +struct rq *rq =cpu_rq (cpu); + +return sched_server_show_common (m, v,DL_PERIOD , &rq->ext_server); +} + +static int sched_ext_server_period_open (struct inode *inode,struct file *filp) +{ +return single_open (filp, sched_ext_server_period_show, inode->i_private); +} + +static const struct file_operations ext_server_period_fops = { + .open = sched_ext_server_period_open, + .write = sched_ext_server_period_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* CONFIG_SCHED_CLASS_EXT */ +static struct dentry *debugfs_sched;static void debugfs_fair_server_init (void )
@@ -494,6 +577,29 @@ static void debugfs_fair_server_init(void) } } +#ifdef CONFIG_SCHED_CLASS_EXT +static void debugfs_ext_server_init (void ) +{ +struct dentry *d_ext; +unsigned long cpu; + + d_ext =debugfs_create_dir ("ext_server" , debugfs_sched); +if (!d_ext) +return ; + +for_each_possible_cpu (cpu) { +struct dentry *d_cpu; +char buf[32 ]; + +snprintf (buf,sizeof (buf),"cpu%lu" , cpu); + d_cpu =debugfs_create_dir (buf, d_ext); + +debugfs_create_file ("runtime" ,0644 , d_cpu, (void *) cpu, &ext_server_runtime_fops); +debugfs_create_file ("period" ,0644 , d_cpu, (void *) cpu, &ext_server_period_fops); + } +} +#endif /* CONFIG_SCHED_CLASS_EXT */ +static __init int sched_init_debug (void ) {struct dentry __maybe_unused *numa;
@@ -532,6 +638,9 @@ static __init int sched_init_debug(void)debugfs_create_file ("debug" ,0444 , debugfs_sched,NULL , &sched_debug_fops);debugfs_fair_server_init (); +#ifdef CONFIG_SCHED_CLASS_EXT +debugfs_ext_server_init (); +#endif return 0 ; }
Signature · 1 line
2.52.0
Andrea Righi
reviewerPATCH 6/7 selftests/sched_ext: Add test for sched_ext dl_server
Add a selftest to validate the correct behavior of the deadline server for the ext_sched_class.
v4: - cover full cycle: fair stop, ext start, ext stop, fair start
(Christian Loehle)
v3: - add a comment to explain the 4% threshold (Emil Tsalapatis)
v2: - replaced occurences of CFS in the test with EXT (Joel Fernandes)
--- tools/testing/selftests/sched_ext/Makefile | 1 + .../selftests/sched_ext/rt_stall.bpf.c | 23 ++ tools/testing/selftests/sched_ext/rt_stall.c | 240 ++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 tools/testing/selftests/sched_ext/rt_stall.bpf.c create mode 100644 tools/testing/selftests/sched_ext/rt_stall.c
tools/testing/selftests/sched_ext/Makefile +1 -0
@@ -183,6 +183,7 @@ auto-test-targets := \ select_cpu_dispatch_bad_dsq \ select_cpu_dispatch_dbl_dsp \ select_cpu_vtime \ + rt_stall \ test_example \ testcase-targets := $(addsuffix .o,$(addprefix $(SCXOBJ_DIR)/,$(auto-test-targets)))
tools/testing/selftests/sched_ext/rt_stall.bpf.c new file +23 -0
@@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* A scheduler that verified if RT tasks can stall SCHED_EXT tasks. +* +* Copyright (c) 2025 NVIDIA Corporation. +*/ + +#include <scx/common.bpf.h> + +char _license[] SEC("license") = "GPL"; + +UEI_DEFINE (uei); + +void BPF_STRUCT_OPS (rt_stall_exit ,struct scx_exit_info *ei) +{ +UEI_RECORD (uei, ei); +} + +SEC(".struct_ops.link") +struct sched_ext_ops rt_stall_ops = { + .exit = (void *)rt_stall_exit, + .name ="rt_stall" , +};
tools/testing/selftests/sched_ext/rt_stall.c new file +240 -0
240 lines not on this page · raw message
Signature · 1 line
2.52.0
Andrea Righi
reviewerPATCH 7/7 selftests/sched_ext: Add test for DL server total_bw consistency
In reply to Andrea RighiFrom: Joel Fernandes <[email protected]>
Add a new kselftest to verify that the total_bw value in /sys/kernel/debug/sched/debug remains consistent across all CPUs under different sched_ext BPF program states:
1. Before a BPF scheduler is loaded
2. While a BPF scheduler is loaded and active
3. After a BPF scheduler is unloaded
The test runs CPU stress threads to ensure DL server bandwidth values stabilize before checking consistency. This helps catch potential issues with DL server bandwidth accounting during sched_ext transitions.
v2: - small coding style fixes (Andrea Righi)
--- tools/testing/selftests/sched_ext/Makefile | 1 + tools/testing/selftests/sched_ext/total_bw.c | 281 +++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 tools/testing/selftests/sched_ext/total_bw.c
tools/testing/selftests/sched_ext/Makefile +1 -0
@@ -185,6 +185,7 @@ auto-test-targets := \ select_cpu_vtime \ rt_stall \ test_example \ + total_bw \ testcase-targets := $(addsuffix .o,$(addprefix $(SCXOBJ_DIR)/,$(auto-test-targets)))
tools/testing/selftests/sched_ext/total_bw.c new file +281 -0
281 lines not on this page · raw message
Signature · 1 line
2.52.0
Tejun Heo
reviewerHello,
Quoted 10 lines · Andrea Righi
This is a resend of the patch set originally posted here:
https://lore.kernel.org/all/[email protected]/Re-sending to check whether there are any remaining objections. As discussed during the LPC
sched_extmicroconference in Tokyo, a potential "open issue" could be to define a better interface for configuring the assigned bandwidth for the DL servers (currently via debugfs). However, this shouldn't be a blocker and we can likely discuss this further at the upcoming OSPM.
Quoted 2 lines
Tejun, if there are no further comments, I think this series can be applied to sched_ext/for-6.20.
Yeah, this has been pending forever. Peter, Ingo, Juri, if there aren't any objections, would it be okay to apply these through sched_ext? Or do you want to route deadline part through sched/core?
Thanks.
Signature · 1 line
tejun