mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/7] sched: Flatten the pick
@ 2026-06-05 12:40 Peter Zijlstra
  2026-06-05 12:40 ` [PATCH v3 1/7] sched/fair: Add cgroup_mode switch Peter Zijlstra
                   ` (9 more replies)
  0 siblings, 10 replies; 55+ messages in thread
From: Peter Zijlstra @ 2026-06-05 12:40 UTC (permalink / raw)
  To: mingo
  Cc: longman, chenridong, peterz, juri.lelli, vincent.guittot,
	dietmar.eggemann, rostedt, bsegall, mgorman, vschneid, tj,
	hannes, mkoutny, cgroups, linux-kernel, jstultz, kprateek.nayak,
	qyousef


Hi!

New version, same story [1]. TL;DR:

 - Adds new cgroup_mode knob and implements new policies to address the
   hierarchy level weight mismatch.

 - Builds upon that base to create a flat / single runqueue scheduler where the
   cgroup hierarchy is expressed through dynamic weight management.

I'm hoping to be able to merge these patches early in the next cycle (after
7.2-rc1).

Random benchmark:

Game vs 'for ((i=0; i<8; i++)) do nice ./spin.sh; done':

  Lutris / GE-Proton10-34 / Steam Runtime 3 (sniper)
  Intel Core i7-2600K
  AMD Radeon RX 580

  Shadows Awakening (GOG)

	  default slice(*)

  FPS min   4.0   29.0
      avg  47.5   59.2
      max  83.7   83.7

  FT  min   9.3   10.2
      avg  34.0   17.0
      max 121.2   30.0

  FPS (Frames Per Second)
  FT  (FrameTime)

  [*] Command prefix: 'chrt -o --sched-runtime 100000 0'


Changes since v2:

 - merged debug and prep patches
 - fixed update_entity_lag() on dequeue (Vincent)
 - fixed throttle vs tick (Prateek)
 - fixed wakeup_preempt_fair()
 - rebased on tip/sched/core
 - rewritten cgroup_mode changelogs
 - reworked cgroup_mode concur
 - added cgroup_mode tasks
 - changed default cgroup_mode


[1] - https://lore.kernel.org/r/20260511113104.563854162@infradead.org

Can also be had:

  git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git sched/flat

 include/linux/cpuset.h |    6 
 include/linux/sched.h  |    1 
 kernel/cgroup/cpuset.c |   15 
 kernel/sched/core.c    |    5 
 kernel/sched/debug.c   |   89 ++++
 kernel/sched/fair.c    |  943 ++++++++++++++++++++++++-------------------------
 kernel/sched/pelt.c    |    6 
 kernel/sched/sched.h   |   30 -
 8 files changed, 607 insertions(+), 488 deletions(-)


^ permalink raw reply	[flat|nested] 55+ messages in thread
* Re: [PATCH v3 7/7] sched/eevdf: Move to a single runqueue
@ 2026-10-30 13:03 Chengfeng Lin
  2026-10-30 17:01 ` Mike Galbraith
  0 siblings, 1 reply; 55+ messages in thread
From: Chengfeng Lin @ 2026-10-30 13:03 UTC (permalink / raw)
  To: Vincent Guittot, Mike Galbraith, Peter Zijlstra
  Cc: Ingo Molnar, Juri Lelli, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4452 bytes --]

Hi Vincent, Mike, Peter,

I have additional pipe-handoff throughput results for 333238da9a19
("sched: Update time before requeueing delayed entities"), which Mike
identified in his wakeup-jitter test [1]. With 15 workers, will-it-scale
throughput on v7.3 is 15.69% lower than v7.1.3 in thread mode and 14.82%
lower in process mode. Reverting this commit on v7.2 in a separate controlled
comparison improves 15-worker thread throughput by 13.65%; the 2-worker
control changes by -0.48%.

I found this while running the existing MMTests recipe for will-it-scale's
context_switch1 test [2], not a generated workload.
Each worker exchanges one-byte messages with its own helper over two pipes,
counting two handoffs per round trip. I kept the default CORE affinity,
restricted to the i7-12700KF's eight P-cores, with both logical CPUs per core
available. Helpers inherit their worker's affinity mask; above eight
workers, cores are reused. All tasks ran at SCHED_OTHER/nice 0, with no extra
CPU-bound competitors or custom time slices. The benchmark loop was unchanged.

After each boot, I ran one warmup run followed by nine measured runs for
each condition. Each run excluded about six seconds of built-in warmup,
then measured throughput for 15 seconds. All kernels were built with
GCC 15.2.0 and run with full preemption, the powersave governor,
balance_performance EPP and Turbo enabled.

The v7.1.3 -> v7.3 -> v7.1.3 comparison used the recipe's worker counts,
plus 1/4/8-worker controls. Changes below are relative to the average of
the two baseline means:

  Workers       Thread mode       Process mode
   1/2/4/6/8    -0.70%..-4.52%    -1.32%..-4.59%
      11           -10.54%            -9.96%
      15           -15.69%           -14.82%
      20           -14.81%           -14.43%
      26           -12.69%           -13.55%
      33            -8.75%            -7.33%
      39            -7.39%            -6.46%
      40            -7.19%            -6.51%

For example, 15-worker thread throughput is 10,875,243 -> 9,168,152 ->
10,872,945 handoffs/s, about 1.71 million fewer handoffs/s on v7.3.
The within-boot coefficient of variation (CV) was at most 2.01%; the two
baseline means differed by at most 1.39%.

The matched v7.2 revert comparison used the same CORE affinity (handoffs/s):

  Thread workers     v7.2 A       v7.2 reverted        v7.2 B
        2          1,178,295         1,174,770       1,182,545
       15          9,413,892        10,695,877       9,409,225

At 15 workers the gain is about 1.28 million handoffs/s. The second baseline
was 0.05% lower than the first, and the maximum CV was 0.11%.

In separate PMU runs, I counted instructions and handoffs over the same
15-second post-warmup window. At 15 workers, kernel instructions per
handoff rose from 8,338 on v7.1.3 to 10,423 on v7.3 (+25.00%). Reverting
the commit on v7.2 reduced this from 10,239 to 8,355 (-18.40%). Context
switches stayed at about one per handoff in both comparisons, pointing to
more kernel work per handoff rather than more switches.

Separate entry probes over the same 15-second window observed about 1.0
delayed requeue per 100 handoffs at 2 workers and 92.6 at 15 workers on v7.2.
Almost every delayed requeue included the added update_curr() call.
The revert removed that call, but also reduced the 15-worker requeue rate
to 55.3 per 100 handoffs. With 15 workers, this accounting path was taken
much more often; reverting the commit also changed how often requeues
occurred.

CPU-location samples showed the same broad placement pattern across the
compared kernels.

These results point to additional work in the delayed-requeue path.
Updating time is needed for correct lag compensation, so the revert is
diagnostic, not a proposed fix. Can this overhead be reduced while
preserving correct lag accounting?

Reproduction details are attached; measurements and diagnostic summaries
are available at [3].

[1] https://lists.openwall.net/linux-kernel/2026/10/18/311
[2] https://github.com/antonblanchard/will-it-scale/blob/a34a85cc1e9b9b74e94fdd3ecc479019da610e6a/tests/context_switch1.c
[3] https://github.com/lcf0399/linux-regression-evidence/tree/8022fe1fb0256e65f63b4bde530b346027f63059/kernel/sched/sched-fair-delayed-requeue-handoff-333238da

LLMs assisted with experiment orchestration, analysis and drafting.
The workload is upstream will-it-scale; results are bare-metal measurements.

Assisted-by: LLM

Thanks,
Chengfeng

[-- Attachment #2: reproduce-wis.txt --]
[-- Type: text/plain, Size: 9043 bytes --]

Native CORE will-it-scale pipe-handoff reproduction
==================================================

This describes the native CORE measurements in the accompanying report.
Run on a dedicated test host.
CPU numbers describe the measured i7-12700KF; adapt them to the other host's
physical topology, then keep the chosen topology identical across kernels.

Pinned inputs
-------------
will-it-scale: https://github.com/antonblanchard/will-it-scale
  a34a85cc1e9b9b74e94fdd3ecc479019da610e6a
MMTests: https://github.com/gormanm/mmtests
  638401e07e70d67fa5a1e6295e1315ae0af831b2
Kernel peeled commits (not annotated-tag object IDs):
  v7.1.3  199c9959d3a9b53f346c221757fc7ac507fbac50
  v7.2    8d3ae59288f1e7d58d76558a6ee96d533bc5019f
  v7.3    c03c1a14507dfaf8b856c2608f9ac216021fc222
Diagnostic v7.2 variant: reverse 333238da9a193ffc58792995f3e951e4cb87bfd2.
It removes update_curr(cfs_rq) from requeue_delayed_entity and is NOT a
proposed fix. The intervention was not performed on v7.3.

Build
-----
Dependencies: C compiler, make, patch, hwloc development files, GNU time,
systemd and cgroup-v2 cpuset support. Tested GCC 15.2.0 and hwloc 2.13.0.
Use clean adjacent will-it-scale and mmtests checkouts. In will-it-scale:

  git checkout --detach a34a85cc1e9b9b74e94fdd3ecc479019da610e6a
  git -C ../mmtests checkout --detach 638401e07e70d67fa5a1e6295e1315ae0af831b2
  sed -n '/^==== BEGIN align-alloc.patch ====$/,/^==== END align-alloc.patch ====$/p' \
    ../mmtests/shellpack_src/src/wis/wis-install | sed '1d;$d' | patch -p1
  sed -i 's|/tmp/shared_area|shared_area|g' main.c
  make -j2 context_switch1_threads context_switch1_processes \
    CFLAGS='-Wall -O2 -g -std=gnu11'

The alignment patch and shared_area relocation are from the pinned MMTests
install recipe. tests/context_switch1.c is unchanged. Other file-path edits
in the recipe affect file-backed tests, not this pipe test.

Our executable SHA-256 values (different build environments can differ):
  threads:
    6fd5c63e4caec9916cbd3942b1ad037f738d24b1232c18711f96b72bc5f248d6
  processes:
    e0e9cf0017bdc0e5f276d7625ecfc0f26b1af1593bca1c50aafd9b1aa7497867

Placement and one invocation
----------------------------
Check lscpu -e=CPU,CORE,SOCKET,NODE. On this host CPU0-15 are eight P-cores;
CORE masks are 0,1; 2,3; ...; 14,15. CPU16-19 are E-cores and excluded from
the test group, but all 20 logical CPUs remain online.

Keep both SMT CPUs in each CORE mask. Native hwloc binding is enabled;
do not add -n or -m. Helpers inherit their worker's mask. Above eight
workers, cores are reused in native order. The coordinator retains CPU0-15.
This is not one worker/helper pair forced onto two separate physical cores.

Example for 15 workers in thread mode (replace mode with processes):
Use an ordinary account with sudo for service creation. Keep the checkout
outside /tmp and /var/tmp because PrivateTmp would hide it.

  workers=15
  mode=threads
  binary="$PWD/context_switch1_$mode"
  work=$(mktemp -d "$PWD/wis-run.XXXXXX")
  sudo systemd-run --quiet --wait --pipe --collect --service-type=exec \
    --unit="wis-handoff-$$" \
    -p "User=$(id -un)" -p "Group=$(id -gn)" \
    -p 'CPUAffinity=0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15' \
    -p AllowedCPUs=0-15 -p MemoryMax=2G -p MemorySwapMax=0 \
    -p "TasksMax=$((2 * workers + 16))" \
    -p RuntimeMaxSec=45 -p TimeoutStopSec=5 -p KillMode=control-group \
    -p NoNewPrivileges=yes -p Environment=LC_ALL=C \
    -p "WorkingDirectory=$work" -p "ReadWritePaths=$work" \
    -p PrivateTmp=yes -p PrivateDevices=yes \
    -p ProtectSystem=strict -p ProtectHome=read-only \
    -p TemporaryFileSystem=/dev/shm:rw,size=16M,mode=1777 \
    -p LimitCORE=0 -p LimitFSIZE=536870912 -p LimitNOFILE=8192 \
    -- /usr/bin/time -v -o "$work/time.txt" \
    "$binary" -t "$workers" -s 15 > "$work/native.txt"

Separately validate affinity/clone inheritance using strace -f with
sched_setaffinity, clone and clone3 before clean timing. Check the effective
mask after intersection with the cgroup, not merely the requested mask.
At 15 workers, 30 worker/helper tasks use the eight CORE masks; the first
seven masks have four tasks each and the last has two. The coordinator is
additional. In process mode these are processes, not the same thread group.
Do not use strace or perf during timing. Preserve failed/incomplete runs.

Separate actual-placement check (not clean timing): two inherited 199-Hz
CPU-clock records per condition on v7.1.3, v7.3, v7.2 and the diagnostic
revert. In each record, 14/15 worker/helper pairs at 15 workers had all
captured samples on one logical CPU per pair; the remaining pair used the
CPU14/15 core. At 2 workers, both pairs had samples across their core's
SMT CPUs. Thus an allowed CORE mask does not imply the pair actually runs
on separate logical CPUs. The pattern was unchanged across the four kernels.
Pairs were reconstructed from fork events, with independently checked
affinity masks. The sampled window starts six seconds after the last test
thread is created and ends at the first test-thread exit. It approximates
the measured interval, not an exact benchmark marker or a complete schedule;
unsampled migrations and other timing effects cannot be excluded.

Parameters, runtime and sampling
--------------------------------
Native recipe worker list on this host:
  2, 6, 11, 15, 20, 26, 33, 39, 40
Also measured separately: 1, 4, 8. Both thread and process modes were tested.
This does not cover every possible MMTests configuration.

Bare metal, i7-12700KF, 32 GiB RAM; GCC 15.2.0, runtime preempt=full.
SCHED_OTHER/nice 0, no custom sched_runtime/slice, no extra CPU-bound spinner.
powersave governor, balance_performance EPP, Turbo enabled at every point.
No CPU bandwidth quota; 2 GiB memory cap and no swap for the test group.
RT budget remains 950000 us per 1000000 us; these are not RT tasks.
The matched v7.2 builds differ only in the diagnostic revert and LOCALVERSION.
Keep other settings matched and restore temporary changes afterward.
No benchmark, kernel build, coverage observer or profiler runs concurrently.

For each condition in each boot: one placement diagnostic, one complete
warmup run, then nine measured runs without instrumentation. Each run has
six native warmup intervals, fifteen
measurement intervals and average:N. The average is the integer floor of
the sum of fifteen measured totals divided by fifteen.

The main metric is aggregate native handoffs/s, two increments per
write/read round trip. It is not a PMU context-switch count. GNU time records
whole-run user/system CPU and elapsed time separately. Runs last about
21 seconds; lower throughput does not mean a correspondingly longer run.

Independent comparisons:
  24 conditions: v7.1.3 -> v7.3 -> v7.1.3.
  Thread workers 2/15: v7.2 A -> diagnostic revert -> v7.2 B.
Nine runs within one boot are not nine independent boots. Keep comparisons
and boot positions separate; do not pool batches. Compare the middle mean
to the mean of the first/return means. CV uses sample standard deviation;
return drift is return / first - 1.

Per-run measurements and raw-output verification are retained locally and
available on request; no measurement CSV accompanies the initial report.

Separate post-warmup diagnostics
-------------------------------
Counter diagnostics use the same fifteen native intervals as the throughput
denominator, not the whole 21-second invocation. A diagnostic-only preload
reads inherited task-scoped perf descriptors at the original "measurement"
and "average" output boundaries; the benchmark executable and hot loop are
unchanged. Subtract the two readings and divide by the sum of the fifteen
native handoff totals. Record enabled/running time and boundary read times;
these are short sequential snapshots, not a simultaneous stop of all workers.

There were three counter runs per condition at v7.1.3, v7.3, v7.2 and the
matched revert, for 2/15 workers. Kernel instructions/cycles cover the test
task family, not update_curr alone; interrupt work in that context can count.
They are diagnostics, never additional clean-throughput samples.

A different batch used two entry-probe runs per condition on v7.2 and the
revert, with the same native window markers. Count requeue_delayed_entity
entries/returns, update_curr entries, and update_curr inside the requeue,
restricted to the marked benchmark thread group. Check entry/return bounds
and per-object count conservation; the first arguments are sched_entity and
cfs_rq respectively, not a common runqueue identifier. Exact tested symbols
and the presence/absence of the internal update_curr call were checked in
both vmlinux files. Probe overhead changes execution, so no PMU or throughput
values from these instrumented runs are used as performance evidence. The counts
do not reconstruct every lag value, hierarchy or scheduling decision.

^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2026-10-30 17:01 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-05 12:40 [PATCH v3 0/7] sched: Flatten the pick Peter Zijlstra
2026-06-05 12:40 ` [PATCH v3 1/7] sched/fair: Add cgroup_mode switch Peter Zijlstra
2026-06-30  9:03   ` [tip: sched/core] " tip-bot2 for Peter Zijlstra
2026-06-05 12:40 ` [PATCH v3 2/7] sched/fair: Add cgroup_mode: up Peter Zijlstra
2026-06-05 15:07   ` Peter Zijlstra
2026-06-30  9:03   ` [tip: sched/core] " tip-bot2 for Peter Zijlstra
2026-06-05 12:40 ` [PATCH v3 3/7] sched/fair: Add cgroup_mode: max Peter Zijlstra
2026-06-10 15:09   ` Waiman Long
2026-06-10 15:42     ` Waiman Long
2026-06-11 13:49       ` Peter Zijlstra
2026-06-11 13:47     ` Peter Zijlstra
2026-06-11 20:57       ` Waiman Long
2026-06-30  9:03   ` [tip: sched/core] " tip-bot2 for Peter Zijlstra
2026-06-05 12:40 ` [PATCH v3 4/7] sched/fair: Add cgroup_mode: concur Peter Zijlstra
2026-06-30  9:03   ` [tip: sched/core] " tip-bot2 for Peter Zijlstra
2026-06-05 12:40 ` [PATCH v3 5/7] sched/fair: Add cgroup_mode: tasks Peter Zijlstra
2026-06-30  9:03   ` [tip: sched/core] " tip-bot2 for Peter Zijlstra
2026-06-05 12:40 ` [PATCH v3 6/7] sched/fair: Change the default cgroup_mode to concur Peter Zijlstra
2026-06-30  9:03   ` [tip: sched/core] " tip-bot2 for Peter Zijlstra
2026-06-05 12:40 ` [PATCH v3 7/7] sched/eevdf: Move to a single runqueue Peter Zijlstra
2026-06-20  3:54   ` Chen, Yu C
2026-06-26 11:40     ` Peter Zijlstra
2026-06-29 14:02       ` Vincent Guittot
2026-06-30  9:03     ` [tip: sched/core] sched/fair: Fix overflow in update_tg_cfs_runnable() tip-bot2 for Chen, Yu C
2026-06-30  9:03   ` [tip: sched/core] sched/eevdf: Move to a single runqueue tip-bot2 for Peter Zijlstra (Intel)
2026-09-23 14:21   ` [REGRESSION] [PATCH v3 7/7] " Aishwarya Rambhadran
2026-09-23 16:48     ` Chen Yu
2026-09-24  7:05       ` K Prateek Nayak
2026-09-24  8:19       ` Mike Galbraith
2026-09-28  3:12         ` Chen Yu
2026-09-28 13:00           ` Mike Galbraith
2026-10-07 12:05             ` Aishwarya Rambhadran
2026-10-12 11:27               ` Mike Galbraith
2026-10-16 13:18   ` Jakub Okoński
2026-10-18  6:49     ` Mike Galbraith
2026-10-19 17:01       ` Vincent Guittot
2026-10-19 17:35         ` Jakub Okoński
2026-10-19 18:04           ` Vincent Guittot
2026-10-19 18:24             ` Jakub Okoński
2026-10-19 18:26               ` Vincent Guittot
2026-10-21 11:55                 ` Vincent Guittot
2026-10-22 12:05                   ` Jakub Okoński
2026-10-30 15:48       ` Chengfeng Lin
2026-10-22  2:12     ` Mike Galbraith
2026-06-09  5:37 ` [PATCH v3 0/7] sched: Flatten the pick K Prateek Nayak
2026-06-12  2:29 ` Shubhang Kaushik
2026-08-17 16:05 ` Szabina Korbai
2026-08-17 16:35   ` K Prateek Nayak
2026-08-18  9:04     ` Szabina Korbai
2026-08-18  9:16       ` Peter Zijlstra
2026-08-21 10:37         ` Szabina Korbai
2026-08-24 14:51         ` Chen Yu
2026-08-24 13:53           ` Peter Zijlstra
2026-10-30 13:03 [PATCH v3 7/7] sched/eevdf: Move to a single runqueue Chengfeng Lin
2026-10-30 17:01 ` Mike Galbraith

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®