* Re: [PATCH 2/2] sched/fair: Randomize equally shallow slow-path candidates
2026-09-16 10:01 ` [PATCH 2/2] sched/fair: Randomize equally shallow slow-path candidates Christian Loehle
@ 2026-09-16 11:06 ` Kayra Cizmeci
2026-09-16 11:10 ` Christian Loehle
2026-09-16 11:12 ` Christian Loehle
2026-09-16 19:43 ` Shubhang
2 siblings, 1 reply; 8+ messages in thread
From: Kayra Cizmeci @ 2026-09-16 11:06 UTC (permalink / raw)
To: christian.loehle
Cc: beata.michalska, cl, daniel.lezcano, dietmar.eggemann,
elif.topuz, juri.lelli, kprateek.nayak, linux-kernel, linux-pm,
mingo, peterz, rafael, rostedt, sh, vincent.guittot, vschneid
Hello Christian :>
> Picking the first eligible idle CPU leaves a scan-order bias. Concurrent
> slow-path selectors can choose the same CPU before either task is enqueued.
> Use reservoir sampling in the tie branch, resetting the candidate count
> when a lower advertised exit latency is found. Use the per-CPU scheduler
> PRNG and reciprocal_scale() to avoid variable division or a second scan.
> This reduces deterministic convergence without reserving the chosen CPU.
OK.
But, your test platform was 160 Cores too. I don't think randomization has the same effect on lower
CPU systems.
Let's create a scenario:
On a 80 Core System, that %50 of it's CPU's are idle the randomization's chance of choosing the same CPU
is low. Since there are 40 CPU's to choose from.
But on a 8 Core System in the same idle conditions, randomization's chance of choosing the same CPU
is really higher. Since there are only 4 CPU's to choose from.
I think this solution works better on higher CPU counted systems.
And I don't think it fully removes the issue. Just better than the original tho.
Thinks can still go bad on this one too, just harder.
Maybe we could add a fallback. Because the real concern is the selected CPU's state
changes when we come to enqueue. If possible tho, I did not really test anything.
Thanks,
Kayra :>>>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] sched/fair: Randomize equally shallow slow-path candidates
2026-09-16 11:06 ` Kayra Cizmeci
@ 2026-09-16 11:10 ` Christian Loehle
0 siblings, 0 replies; 8+ messages in thread
From: Christian Loehle @ 2026-09-16 11:10 UTC (permalink / raw)
To: Kayra Cizmeci
Cc: beata.michalska, cl, daniel.lezcano, dietmar.eggemann,
elif.topuz, juri.lelli, kprateek.nayak, linux-kernel, linux-pm,
mingo, peterz, rafael, rostedt, sh, vincent.guittot, vschneid
On 9/16/26 12:06, Kayra Cizmeci wrote:
> Hello Christian :>
>
>> Picking the first eligible idle CPU leaves a scan-order bias. Concurrent
>> slow-path selectors can choose the same CPU before either task is enqueued.
>
>> Use reservoir sampling in the tie branch, resetting the candidate count
>> when a lower advertised exit latency is found. Use the per-CPU scheduler
>> PRNG and reciprocal_scale() to avoid variable division or a second scan.
>
>> This reduces deterministic convergence without reserving the chosen CPU.
>
> OK.
>
> But, your test platform was 160 Cores too. I don't think randomization has the same effect on lower
> CPU systems.
>
> Let's create a scenario:
>
> On a 80 Core System, that %50 of it's CPU's are idle the randomization's chance of choosing the same CPU
> is low. Since there are 40 CPU's to choose from.
>
> But on a 8 Core System in the same idle conditions, randomization's chance of choosing the same CPU
> is really higher. Since there are only 4 CPU's to choose from.
>
> I think this solution works better on higher CPU counted systems.
Yes, this mostly works for higher CPU count domains, but the
issue I'm trying to fix basically doesn't exist in the 8 CPU domain
in the first place (first of all fewer chances of having simultaneous
slow paths running that can race and also the slow path is much faster,
i.e. the race window much smaller).
>
> And I don't think it fully removes the issue. Just better than the original tho.
> Thinks can still go bad on this one too, just harder.
Fully removing the issue would require some synchronisation which the
numbers (which admittedly are pretty modest already) just don't justify.
>
> Maybe we could add a fallback. Because the real concern is the selected CPU's state
> changes when we come to enqueue. If possible tho, I did not really test anything.
And then do what? rescan?
I don't think increasing the slow path is justified at all, when this relatively
straightforward randomization already significantly reduces the chance
for the 'pathological' test platform.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] sched/fair: Randomize equally shallow slow-path candidates
2026-09-16 10:01 ` [PATCH 2/2] sched/fair: Randomize equally shallow slow-path candidates Christian Loehle
2026-09-16 11:06 ` Kayra Cizmeci
@ 2026-09-16 11:12 ` Christian Loehle
2026-09-16 11:46 ` Kayra Cizmeci
2026-09-16 19:43 ` Shubhang
2 siblings, 1 reply; 8+ messages in thread
From: Christian Loehle @ 2026-09-16 11:12 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot
Cc: Dietmar Eggemann, Steven Rostedt, Valentin Schneider,
K Prateek Nayak, Beata Michalska, Elif Topuz, Rafael J . Wysocki,
Daniel Lezcano, Shubhang Kaushik, Christoph Lameter,
linux-kernel, linux-pm
On 9/16/26 11:01, Christian Loehle wrote:
> Picking the first eligible idle CPU leaves a scan-order bias. Concurrent
> slow-path selectors can choose the same CPU before either task is enqueued.
>
> Use reservoir sampling in the tie branch, resetting the candidate count
> when a lower advertised exit latency is found. Use the per-CPU scheduler
> PRNG and reciprocal_scale() to avoid variable division or a second scan.
>
> This reduces deterministic convergence without reserving the chosen CPU.
>
> Signed-off-by: Christian Loehle <christian.loehle@arm.com>
> ---
> kernel/sched/fair.c | 11 ++++++++---
> 1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index ff5793bddc35..6836a8364440 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -24,6 +24,7 @@
> #include <linux/mmap_lock.h>
> #include <linux/hugetlb_inline.h>
> #include <linux/jiffies.h>
> +#include <linux/math.h>
> #include <linux/mm_api.h>
> #include <linux/highmem.h>
> #include <linux/hrtimer.h>
> @@ -8459,6 +8460,7 @@ sched_balance_find_dst_group_cpu(struct sched_group *group, struct task_struct *
> {
> unsigned long load, min_load = ULONG_MAX;
> unsigned int min_exit_latency = UINT_MAX;
> + unsigned int nr_candidates = 0;
> int least_loaded_cpu = this_cpu;
> int shallowest_idle_cpu = -1;
> int i;
> @@ -8482,9 +8484,12 @@ sched_balance_find_dst_group_cpu(struct sched_group *group, struct task_struct *
> if (idle && idle->exit_latency < min_exit_latency) {
> min_exit_latency = idle->exit_latency;
> shallowest_idle_cpu = i;
> + nr_candidates = 1;
> - } else if ((!idle || idle->exit_latency == min_exit_latency) &&
> - shallowest_idle_cpu == -1) {
> - shallowest_idle_cpu = i;
> + } else if (!idle || idle->exit_latency == min_exit_latency) {
Sashiko:
"Can this branch cause the CPU picker to replace an optimal idle CPU with
a non-idle CPU?
In sched_balance_find_dst_group_cpu(), if a !idle CPU is scanned after an
idle CPU has already been found, min_exit_latency will be < UINT_MAX.
However, the condition !idle || idle->exit_latency == min_exit_latency
unconditionally evaluates to true for !idle CPUs.
This allows the !idle CPU to increment nr_candidates and enter the
reservoir, treating its unknown latency as a tie with the optimal known
latency. It then has a 1/nr_candidates chance to overwrite the optimal
shallowest_idle_cpu choice.
Doesn't this reintroduce a scan-order bias during normal load balancing where
non-idle CPUs can replace optimal idle CPUs just because they appear later
in the scan?"
Disagree, this is in the if block of if (available_idle_cpu(i)), so except for
the obvious race which is deliberately taken in the original code too, this
can't be right?
> + nr_candidates++;
> + if (nr_candidates == 1 ||
> + !reciprocal_scale(sched_rng(), nr_candidates))
> + shallowest_idle_cpu = i;
> }
> } else if (shallowest_idle_cpu == -1) {
> load = cpu_load(cpu_rq(i));
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 2/2] sched/fair: Randomize equally shallow slow-path candidates
2026-09-16 11:12 ` Christian Loehle
@ 2026-09-16 11:46 ` Kayra Cizmeci
0 siblings, 0 replies; 8+ messages in thread
From: Kayra Cizmeci @ 2026-09-16 11:46 UTC (permalink / raw)
To: christian.loehle
Cc: beata.michalska, cl, daniel.lezcano, dietmar.eggemann,
elif.topuz, juri.lelli, kprateek.nayak, linux-kernel, linux-pm,
mingo, peterz, rafael, rostedt, sh, vincent.guittot, vschneid
> > Hello Christian :>
> >
> >> Picking the first eligible idle CPU leaves a scan-order bias. Concurrent
> >> slow-path selectors can choose the same CPU before either task is enqueued.
> >
> >> Use reservoir sampling in the tie branch, resetting the candidate count
> >> when a lower advertised exit latency is found. Use the per-CPU scheduler
> >> PRNG and reciprocal_scale() to avoid variable division or a second scan.
> >
> >> This reduces deterministic convergence without reserving the chosen CPU.
> >
> > OK.
> >
> > But, your test platform was 160 Cores too. I don't think randomization has the same effect on lower
> > CPU systems.
> >
> > Let's create a scenario:
> >
> > On a 80 Core System, that %50 of it's CPU's are idle the randomization's chance of choosing the same CPU
> > is low. Since there are 40 CPU's to choose from.
> >
> > But on a 8 Core System in the same idle conditions, randomization's chance of choosing the same CPU
> > is really higher. Since there are only 4 CPU's to choose from.
> >
> > I think this solution works better on higher CPU counted systems.
> Yes, this mostly works for higher CPU count domains, but the
> issue I'm trying to fix basically doesn't exist in the 8 CPU domain
> in the first place (first of all fewer chances of having simultaneous
> slow paths running that can race and also the slow path is much faster,
> i.e. the race window much smaller).
> >
> > And I don't think it fully removes the issue. Just better than the original tho.
> > Thinks can still go bad on this one too, just harder.
> Fully removing the issue would require some synchronisation which the
> numbers (which admittedly are pretty modest already) just don't justify.
> >
> > Maybe we could add a fallback. Because the real concern is the selected CPU's state
> > changes when we come to enqueue. If possible tho, I did not really test anything.
> And then do what? rescan?
> I don't think increasing the slow path is justified at all, when this relatively
> straightforward randomization already significantly reduces the chance
> for the 'pathological' test platform.
Fair.
My real concern is that randomization is not predictable while the other solutions are.
I don't really care about their speed when it comes to that.
That's just a concern tho. I think this version is better than just placing the task
to the CPU anyways. (in terms of approach)
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] sched/fair: Randomize equally shallow slow-path candidates
2026-09-16 10:01 ` [PATCH 2/2] sched/fair: Randomize equally shallow slow-path candidates Christian Loehle
2026-09-16 11:06 ` Kayra Cizmeci
2026-09-16 11:12 ` Christian Loehle
@ 2026-09-16 19:43 ` Shubhang
2 siblings, 0 replies; 8+ messages in thread
From: Shubhang @ 2026-09-16 19:43 UTC (permalink / raw)
To: Christian Loehle
Cc: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Valentin Schneider,
K Prateek Nayak, Beata Michalska, Elif Topuz, Rafael J . Wysocki,
Daniel Lezcano, Christoph Lameter, linux-kernel, linux-pm
Hi Christian,
On Wed, 16 Sep 2026, Christian Loehle wrote:
> + } else if (!idle || idle->exit_latency == min_exit_latency) {
> + nr_candidates++;
> + if (nr_candidates == 1 ||
> + !reciprocal_scale(sched_rng(), nr_candidates))
> + shallowest_idle_cpu = i;
available_idle_cpu(i) ensures that this is an idle CPU, but !idle
means that no active cpuidle state, meaning no exit latency is
available for comparison.
[PATCH 1/2] treats such a CPU as a fallback i.e. it is selected only when
no idle candidate has been found yet. Here it becomes an equal reservoir
candidate, even after selecting a CPU with the minimum known exit latency.
That is, it is added to the random selection pool and can replace
shallowest_idle_cpu.
Is that intentional ? If not, should reservoir sampling be limited to
candidates with `idle->exit_latency == min_exit_latency`, while
retaining the first !idle CPU only as the fallback?
Regards,
Shubhang Kaushik
^ permalink raw reply [flat|nested] 8+ messages in thread