Re: [PATCH v3 7/7] sched/eevdf: Move to a single runqueue
From: Jakub Okoński
Date: Fri Oct 16 2026 - 09:20:27 EST
Hi Peter,
On 6/5/26 14:40, Peter Zijlstra wrote:
> Change fair/cgroup to a single runqueue.
>
> [...]
>
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -9916,7 +9837,6 @@ static void wakeup_preempt_fair(struct r
> if (!sched_feat(WAKEUP_PREEMPTION))
> return;
>
> - find_matching_se(&se, &pse);
> WARN_ON_ONCE(!pse);
>
> cse_is_idle = se_is_idle(se);
I think this changes how cpu.idle affects wakeup preemption.
With the single runqueue, find_matching_se() is gone and se_is_idle()
reduces to task_has_idle_policy(). Wouldn't this mean that SCHED_NORMAL
tasks in a cpu.idle cgroup are no longer treated as idle for
wakeup_preempt_fair()?
I tested my existing 7.2.9 desktop against 7.3-rc6 with the setup below.
cyclictest doesn't reproduce it because it just sleeps and wakes, no CPU
burn and therefore its accrued EEVDF lag keeps the latency low?
cc -O2 -o wakelat wakelat.c
systemd-run --user --collect --unit=spin -p AllowedCPUs=7 -p CPUWeight=idle sh -c 'while :; do :; done'
systemd-run --user --collect --wait --pipe --same-dir -p AllowedCPUs=7 ./wakelat 1000 15 200 |
mlr --inidx --ifs space --opprint --barred --right label lat \
then stats1 -a count,p50,p90,p99,max -f lat then rename -r '^lat_,' \
then put -q 'emit mapsum({"kernel": system("uname -r")}, $*)'
systemctl --user stop spin
wakelat wakes on a fixed 1 ms schedule, records how late each wakeup
was, then busy-loops for 200 micros (wall clock).
+-----------+-------+-----+-----+------+------+
| kernel | count | p50 | p90 | p99 | max |
+-----------+-------+-----+-----+------+------+
| 7.2.9 | 14998 | 11 | 11 | 12 | 1869 |
| 7.3.0-rc6 | 13853 | 11 | 12 | 2029 | 2116 |
+-----------+-------+-----+-----+------+------+
count is out of 15000 periods. rc6 had 1147 wakeups delayed by over 1 ms.
wakelat.c:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <time.h>
static long long now_ns(void)
{
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
return t.tv_sec * 1000000000LL + t.tv_nsec;
}
int main(int argc, char **argv)
{
if (argc != 4)
return 2;
long long interval = atoll(argv[1]) * 1000, dur = atoll(argv[2]) * 1000000000LL;
long long work = atoll(argv[3]) * 1000;
long max = dur / interval + 1, n = 0;
long *lat = malloc(max * sizeof(*lat));
prctl(PR_SET_TIMERSLACK, 1UL);
long long start = now_ns(), next = start + interval;
while (next - start < dur && n < max) {
struct timespec ts = { next / 1000000000LL, next % 1000000000LL };
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL);
long long now = now_ns();
lat[n++] = (now - next) / 1000;
while (now_ns() - now < work)
;
do next += interval; while (next <= now);
}
for (long i = 0; i < n; i++)
printf("%ld\n", lat[i]);
return 0;
}
Regards,
Jakub