kernel/sched/ext.c | 20 ++++++++++++++++++-- kernel/sched/ext.h | 8 ++++---- kernel/sched/idle.c | 18 ++++++++++++++++-- 3 files changed, 38 insertions(+), 8 deletions(-)
With the consolidation of put_prev_task/set_next_task(), see
commit 436f3eed5c69 ("sched: Combine the last put_prev_task() and the
first set_next_task()"), we are now skipping the transition between
these two functions when the previous and the next tasks are the same.
As a result, the scx idle state is updated only when a CPU transitions
in or out of SCHED_IDLE. While this is generally correct, it can lead to
uneven and inefficient core utilization in certain scenarios [1].
A typical scenario involves proactive wake-ups: scx_bpf_pick_idle_cpu()
selects and mark an idle CPU as busy, followed by a wake-up via
scx_bpf_kick_cpu(), without dispatching any tasks. In this case, the CPU
continues running the idle task, returns to idle, but remains marked as
busy, preventing it from being selected again as an idle CPU (until
a task eventually runs on it and releases the CPU).
For example, running a workload that uses 20% of each CPU, combined with
an scx scheduler using proactive wake-ups, results in the following core
utilization:
CPU 0: 25.7%
CPU 1: 29.3%
CPU 2: 26.5%
CPU 3: 25.5%
CPU 4: 0.0%
CPU 5: 25.5%
CPU 6: 0.0%
CPU 7: 10.5%
To address this, refresh the idle state also in pick_task_idle(), during
idle-to-idle transitions, but only trigger ops.update_idle() on actual
state changes to prevent unnecessary updates to the scx scheduler and
maintain balanced state transitions.
With this change in place, the core utilization in the previous example
becomes the following:
CPU 0: 18.8%
CPU 1: 19.4%
CPU 2: 18.0%
CPU 3: 18.7%
CPU 4: 19.3%
CPU 5: 18.9%
CPU 6: 18.7%
CPU 7: 19.3%
[1] https://github.com/sched-ext/scx/pull/1139
Fixes: 7c65ae81ea86 ("sched_ext: Don't call put_prev_task_scx() before picking the next task")
Signed-off-by: Andrea Righi <arighi@nvidia.com>
---
kernel/sched/ext.c | 20 ++++++++++++++++++--
kernel/sched/ext.h | 8 ++++----
kernel/sched/idle.c | 18 ++++++++++++++++--
3 files changed, 38 insertions(+), 8 deletions(-)
ChangeLog v4 -> v5:
- prevent unbalanced ops.update_idle() invocations
ChangeLog v3 -> v4:
- handle the core-sched case that may ignore the result of
pick_task(), triggering spurious ops.update_idle() events
ChangeLog v2 -> v3:
- add a comment to clarify why we need to update the scx idle state in
pick_task()
ChangeLog v1 -> v2:
- move the logic from put_prev_set_next_task() to scx_update_idle()
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 96b6d6aea26e..9ed09e5df064 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -3651,11 +3651,27 @@ static void reset_idle_masks(void)
cpumask_copy(idle_masks.smt, cpu_online_mask);
}
-void __scx_update_idle(struct rq *rq, bool idle)
+/*
+ * Update the idle state of a CPU to @idle.
+ *
+ * If @do_update is true, ops.update_idle() is invoked to notify the scx
+ * scheduler of an actual idle state transition (idle to busy or vice
+ * versa). If @do_update is false, only the idle state in the idle masks is
+ * refreshed without invoking ops.update_idle().
+ *
+ * This distinction is necessary, because an idle CPU can be "reserved" and
+ * awakened via scx_bpf_pick_idle_cpu() + scx_bpf_kick_cpu(), marking it as
+ * busy even if no tasks are dispatched. In this case, the CPU may return
+ * to idle without a true state transition. Refreshing the idle masks
+ * without invoking ops.update_idle() ensures accurate idle state tracking
+ * while avoiding unnecessary updates and maintaining balanced state
+ * transitions.
+ */
+void __scx_update_idle(struct rq *rq, bool idle, bool do_update)
{
int cpu = cpu_of(rq);
- if (SCX_HAS_OP(update_idle) && !scx_rq_bypassing(rq)) {
+ if (do_update && SCX_HAS_OP(update_idle) && !scx_rq_bypassing(rq)) {
SCX_CALL_OP(SCX_KF_REST, update_idle, cpu_of(rq), idle);
if (!static_branch_unlikely(&scx_builtin_idle_enabled))
return;
diff --git a/kernel/sched/ext.h b/kernel/sched/ext.h
index b1675bb59fc4..34e614c1e871 100644
--- a/kernel/sched/ext.h
+++ b/kernel/sched/ext.h
@@ -57,15 +57,15 @@ static inline void init_sched_ext_class(void) {}
#endif /* CONFIG_SCHED_CLASS_EXT */
#if defined(CONFIG_SCHED_CLASS_EXT) && defined(CONFIG_SMP)
-void __scx_update_idle(struct rq *rq, bool idle);
+void __scx_update_idle(struct rq *rq, bool idle, bool do_update);
-static inline void scx_update_idle(struct rq *rq, bool idle)
+static inline void scx_update_idle(struct rq *rq, bool idle, bool do_update)
{
if (scx_enabled())
- __scx_update_idle(rq, idle);
+ __scx_update_idle(rq, idle, do_update);
}
#else
-static inline void scx_update_idle(struct rq *rq, bool idle) {}
+static inline void scx_update_idle(struct rq *rq, bool idle, bool do_update) {}
#endif
#ifdef CONFIG_CGROUP_SCHED
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index 621696269584..ffc636ccd54e 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -452,19 +452,33 @@ 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, struct task_struct *next)
{
dl_server_update_idle_time(rq, prev);
- scx_update_idle(rq, false);
+ scx_update_idle(rq, false, true);
}
static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first)
{
update_idle_core(rq);
- scx_update_idle(rq, true);
+ scx_update_idle(rq, true, true);
schedstat_inc(rq->sched_goidle);
next->se.exec_start = rq_clock_task(rq);
}
struct task_struct *pick_task_idle(struct rq *rq)
{
+ /*
+ * The scx idle state is updated only when the CPU transitions
+ * in/out of SCHED_IDLE, see put_prev_task_idle() and
+ * set_next_task_idle().
+ *
+ * However, the CPU may also exit/enter the idle state while
+ * running the idle task, for example waking up the CPU via
+ * scx_bpf_kick_cpu() without dispatching a task on it.
+ *
+ * In this case we still need to trigger scx_update_idle() to
+ * ensure a proper management of the scx idle state.
+ */
+ if (rq->curr == rq->idle)
+ scx_update_idle(rq, true, false);
return rq->idle;
}
--
2.47.1
Hi Andrea,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tip/sched/core]
[also build test WARNING on linus/master v6.13-rc6 next-20250109]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Andrea-Righi/sched_ext-Refresh-scx-idle-state-during-idle-to-idle-transitions/20250109-182533
base: tip/sched/core
patch link: https://lore.kernel.org/r/20250109101952.443769-1-arighi%40nvidia.com
patch subject: [PATCH v5] sched_ext: Refresh scx idle state during idle-to-idle transitions
config: x86_64-randconfig-121-20250110 (https://download.01.org/0day-ci/archive/20250110/202501101452.wa7SRR7Q-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250110/202501101452.wa7SRR7Q-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202501101452.wa7SRR7Q-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
kernel/sched/build_policy.c: note: in included file:
>> kernel/sched/idle.c:480:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/sched/idle.c:480:22: sparse: struct task_struct [noderef] __rcu *
kernel/sched/idle.c:480:22: sparse: struct task_struct *
kernel/sched/build_policy.c: note: in included file:
kernel/sched/rt.c:851:70: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/sched/rt.c:851:70: sparse: struct task_struct [noderef] __rcu *
kernel/sched/rt.c:851:70: sparse: struct task_struct *
kernel/sched/rt.c:2336:25: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/sched/rt.c:2336:25: sparse: struct task_struct *
kernel/sched/rt.c:2336:25: sparse: struct task_struct [noderef] __rcu *
kernel/sched/rt.c:531:55: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct task_struct *donor @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/rt.c:531:55: sparse: expected struct task_struct *donor
kernel/sched/rt.c:531:55: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/rt.c:991:39: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct task_struct *donor @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/rt.c:991:39: sparse: expected struct task_struct *donor
kernel/sched/rt.c:991:39: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/rt.c:1529:31: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct task_struct *p @@ got struct task_struct [noderef] __rcu *curr @@
kernel/sched/rt.c:1529:31: sparse: expected struct task_struct *p
kernel/sched/rt.c:1529:31: sparse: got struct task_struct [noderef] __rcu *curr
kernel/sched/rt.c:1849:9: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct sched_domain *[assigned] sd @@ got struct sched_domain [noderef] __rcu *parent @@
kernel/sched/rt.c:1849:9: sparse: expected struct sched_domain *[assigned] sd
kernel/sched/rt.c:1849:9: sparse: got struct sched_domain [noderef] __rcu *parent
kernel/sched/rt.c:1549:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct task_struct *curr @@ got struct task_struct [noderef] __rcu * @@
kernel/sched/rt.c:1549:14: sparse: expected struct task_struct *curr
kernel/sched/rt.c:1549:14: sparse: got struct task_struct [noderef] __rcu *
kernel/sched/rt.c:1550:15: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct task_struct *donor @@ got struct task_struct [noderef] __rcu * @@
kernel/sched/rt.c:1550:15: sparse: expected struct task_struct *donor
kernel/sched/rt.c:1550:15: sparse: got struct task_struct [noderef] __rcu *
kernel/sched/rt.c:1611:45: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct task_struct *p @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/rt.c:1611:45: sparse: expected struct task_struct *p
kernel/sched/rt.c:1611:45: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/rt.c:1654:39: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct task_struct *donor @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/rt.c:1654:39: sparse: expected struct task_struct *donor
kernel/sched/rt.c:1654:39: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/rt.c:1674:64: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *tsk @@ got struct task_struct [noderef] __rcu *curr @@
kernel/sched/rt.c:1674:64: sparse: expected struct task_struct *tsk
kernel/sched/rt.c:1674:64: sparse: got struct task_struct [noderef] __rcu *curr
kernel/sched/rt.c:2018:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *task @@ got struct task_struct [noderef] __rcu *curr @@
kernel/sched/rt.c:2018:40: sparse: expected struct task_struct *task
kernel/sched/rt.c:2018:40: sparse: got struct task_struct [noderef] __rcu *curr
kernel/sched/rt.c:2041:13: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/sched/rt.c:2041:13: sparse: struct task_struct *
kernel/sched/rt.c:2041:13: sparse: struct task_struct [noderef] __rcu *
kernel/sched/rt.c:2387:54: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *tsk @@ got struct task_struct [noderef] __rcu *curr @@
kernel/sched/rt.c:2387:54: sparse: expected struct task_struct *tsk
kernel/sched/rt.c:2387:54: sparse: got struct task_struct [noderef] __rcu *curr
kernel/sched/rt.c:2389:40: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *p @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/rt.c:2389:40: sparse: expected struct task_struct *p
kernel/sched/rt.c:2389:40: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/rt.c:2389:62: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *p @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/rt.c:2389:62: sparse: expected struct task_struct *p
kernel/sched/rt.c:2389:62: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/build_policy.c: note: in included file:
kernel/sched/deadline.c:2715:23: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *p @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/deadline.c:2715:23: sparse: expected struct task_struct *p
kernel/sched/deadline.c:2715:23: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/deadline.c:2725:13: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/sched/deadline.c:2725:13: sparse: struct task_struct *
kernel/sched/deadline.c:2725:13: sparse: struct task_struct [noderef] __rcu *
kernel/sched/deadline.c:2831:25: sparse: sparse: incompatible types in comparison expression (different address spaces):
kernel/sched/deadline.c:2831:25: sparse: struct task_struct *
kernel/sched/deadline.c:2831:25: sparse: struct task_struct [noderef] __rcu *
kernel/sched/deadline.c:2357:42: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct sched_dl_entity const *b @@ got struct sched_dl_entity [noderef] __rcu * @@
kernel/sched/deadline.c:2357:42: sparse: expected struct sched_dl_entity const *b
kernel/sched/deadline.c:2357:42: sparse: got struct sched_dl_entity [noderef] __rcu *
kernel/sched/deadline.c:2368:38: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *tsk @@ got struct task_struct [noderef] __rcu *curr @@
kernel/sched/deadline.c:2368:38: sparse: expected struct task_struct *tsk
kernel/sched/deadline.c:2368:38: sparse: got struct task_struct [noderef] __rcu *curr
kernel/sched/deadline.c:1262:39: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *p @@ got struct task_struct [noderef] __rcu *curr @@
kernel/sched/deadline.c:1262:39: sparse: expected struct task_struct *p
kernel/sched/deadline.c:1262:39: sparse: got struct task_struct [noderef] __rcu *curr
kernel/sched/deadline.c:1262:85: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct sched_dl_entity const *b @@ got struct sched_dl_entity [noderef] __rcu * @@
kernel/sched/deadline.c:1262:85: sparse: expected struct sched_dl_entity const *b
kernel/sched/deadline.c:1262:85: sparse: got struct sched_dl_entity [noderef] __rcu *
kernel/sched/deadline.c:1362:23: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *p @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/deadline.c:1362:23: sparse: expected struct task_struct *p
kernel/sched/deadline.c:1362:23: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/deadline.c:1671:31: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *p @@ got struct task_struct [noderef] __rcu *curr @@
kernel/sched/deadline.c:1671:31: sparse: expected struct task_struct *p
kernel/sched/deadline.c:1671:31: sparse: got struct task_struct [noderef] __rcu *curr
kernel/sched/deadline.c:1671:70: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct sched_dl_entity const *b @@ got struct sched_dl_entity [noderef] __rcu * @@
kernel/sched/deadline.c:1671:70: sparse: expected struct sched_dl_entity const *b
kernel/sched/deadline.c:1671:70: sparse: got struct sched_dl_entity [noderef] __rcu *
kernel/sched/deadline.c:1759:39: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected struct task_struct *donor @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/deadline.c:1759:39: sparse: expected struct task_struct *donor
kernel/sched/deadline.c:1759:39: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/deadline.c:2576:9: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct sched_domain *[assigned] sd @@ got struct sched_domain [noderef] __rcu *parent @@
kernel/sched/deadline.c:2576:9: sparse: expected struct sched_domain *[assigned] sd
kernel/sched/deadline.c:2576:9: sparse: got struct sched_domain [noderef] __rcu *parent
kernel/sched/deadline.c:2242:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct task_struct *curr @@ got struct task_struct [noderef] __rcu * @@
kernel/sched/deadline.c:2242:14: sparse: expected struct task_struct *curr
kernel/sched/deadline.c:2242:14: sparse: got struct task_struct [noderef] __rcu *
kernel/sched/deadline.c:2243:15: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct task_struct *donor @@ got struct task_struct [noderef] __rcu * @@
kernel/sched/deadline.c:2243:15: sparse: expected struct task_struct *donor
kernel/sched/deadline.c:2243:15: sparse: got struct task_struct [noderef] __rcu *
kernel/sched/deadline.c:2318:43: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct task_struct *p @@ got struct task_struct [noderef] __rcu *donor @@
kernel/sched/deadline.c:2318:43: sparse: expected struct task_struct *p
kernel/sched/deadline.c:2318:43: sparse: got struct task_struct [noderef] __rcu *donor
kernel/sched/deadline.c:2876:38: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected struct task_struct *tsk @@ got struct task_struct [noderef] __rcu *curr @@
kernel/sched/deadline.c:2876:38: sparse: expected struct task_struct *tsk
kernel/sched/deadline.c:2876:38: sparse: got struct task_struct [noderef] __rcu *curr
vim +480 kernel/sched/idle.c
465
466 struct task_struct *pick_task_idle(struct rq *rq)
467 {
468 /*
469 * The scx idle state is updated only when the CPU transitions
470 * in/out of SCHED_IDLE, see put_prev_task_idle() and
471 * set_next_task_idle().
472 *
473 * However, the CPU may also exit/enter the idle state while
474 * running the idle task, for example waking up the CPU via
475 * scx_bpf_kick_cpu() without dispatching a task on it.
476 *
477 * In this case we still need to trigger scx_update_idle() to
478 * ensure a proper management of the scx idle state.
479 */
> 480 if (rq->curr == rq->idle)
481 scx_update_idle(rq, true, false);
482 return rq->idle;
483 }
484
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
On Thu, Jan 09, 2025 at 11:19:52AM +0100, Andrea Righi wrote:
> diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
> index 621696269584..ffc636ccd54e 100644
> --- a/kernel/sched/idle.c
> +++ b/kernel/sched/idle.c
> @@ -452,19 +452,33 @@ 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, struct task_struct *next)
> {
> dl_server_update_idle_time(rq, prev);
> - scx_update_idle(rq, false);
> + scx_update_idle(rq, false, true);
> }
>
> static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first)
> {
> update_idle_core(rq);
> - scx_update_idle(rq, true);
> + scx_update_idle(rq, true, true);
> schedstat_inc(rq->sched_goidle);
> next->se.exec_start = rq_clock_task(rq);
> }
>
> struct task_struct *pick_task_idle(struct rq *rq)
> {
> + /*
> + * The scx idle state is updated only when the CPU transitions
> + * in/out of SCHED_IDLE, see put_prev_task_idle() and
Idle thread != SCHED_IDLE
> + * set_next_task_idle().
> + *
> + * However, the CPU may also exit/enter the idle state while
> + * running the idle task, for example waking up the CPU via
> + * scx_bpf_kick_cpu() without dispatching a task on it.
> + *
> + * In this case we still need to trigger scx_update_idle() to
> + * ensure a proper management of the scx idle state.
> + */
> + if (rq->curr == rq->idle)
> + scx_update_idle(rq, true, false);
> return rq->idle;
> }
>
> --
> 2.47.1
>
On Thu, Jan 09, 2025 at 11:22:12AM +0100, Peter Zijlstra wrote:
> On Thu, Jan 09, 2025 at 11:19:52AM +0100, Andrea Righi wrote:
>
> > diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
> > index 621696269584..ffc636ccd54e 100644
> > --- a/kernel/sched/idle.c
> > +++ b/kernel/sched/idle.c
> > @@ -452,19 +452,33 @@ 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, struct task_struct *next)
> > {
> > dl_server_update_idle_time(rq, prev);
> > - scx_update_idle(rq, false);
> > + scx_update_idle(rq, false, true);
> > }
> >
> > static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first)
> > {
> > update_idle_core(rq);
> > - scx_update_idle(rq, true);
> > + scx_update_idle(rq, true, true);
> > schedstat_inc(rq->sched_goidle);
> > next->se.exec_start = rq_clock_task(rq);
> > }
> >
> > struct task_struct *pick_task_idle(struct rq *rq)
> > {
> > + /*
> > + * The scx idle state is updated only when the CPU transitions
> > + * in/out of SCHED_IDLE, see put_prev_task_idle() and
>
> Idle thread != SCHED_IDLE
Ah good point, in this case it's probably better to say something like:
"when the current task transitions to/from the idle thread". I'll clarify
that.
Thanks,
-Andrea
>
> > + * set_next_task_idle().
> > + *
> > + * However, the CPU may also exit/enter the idle state while
> > + * running the idle task, for example waking up the CPU via
> > + * scx_bpf_kick_cpu() without dispatching a task on it.
> > + *
> > + * In this case we still need to trigger scx_update_idle() to
> > + * ensure a proper management of the scx idle state.
> > + */
> > + if (rq->curr == rq->idle)
> > + scx_update_idle(rq, true, false);
> > return rq->idle;
> > }
> >
> > --
> > 2.47.1
> >
© 2016 - 2026 Red Hat, Inc.