mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC PATCH v2 00/23] sched: Scale cache-aware aggregation at LLC granularity
@ 2026-08-27 12:27 Jianyong Wu
  2026-08-27 12:27 ` [RFC PATCH v2 01/23] sched/topology: Add llc_to_node() to translate LLC id to NUMA node Jianyong Wu
                   ` (22 more replies)
  0 siblings, 23 replies; 25+ messages in thread
From: Jianyong Wu @ 2026-08-27 12:27 UTC (permalink / raw)
  To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
	Chen Yu, Tim Chen
  Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Valentin Schneider, K Prateek Nayak, Shrikanth Hegde, Phil Auld,
	Andrew Morton, David Hildenbrand, linux-kernel, linux-mm,
	wujianyong, jianyong.wu, zhongyuan, huangsj, wangfengyu,
	yingzhiwei, justin.he

[Problem Statement]
The current cache-aware scheduling implementation adopts an
LLC-centric task aggregation model. While effective for workloads
that fit within a single LLC domain, this design is fundamentally
limited by its fixed aggregation scope and cannot scale across LLCs.

[Proposal]
Peter Zijlstra suggested scaling resources at LLC granularity instead,
and this patch set implements that idea.

To achieve this goal, we need to answer two questions: in which order
should LLCs be considered, and how far along that order does a thread
group need to spread? The scheduler aggregates threads near the
preferred LLC first, then expands through the ordered LLCs as the
thread group's aggregate demand requires.

For each preferred LLC, the topology-based affinity model defines a
fixed order in which LLCs should be used. The scheduler estimates the
thread group's total utilization and selects the smallest leading
portion of that order whose allowed capacity can accommodate the
group. A task may migrate to an LLC in that portion only if the
destination can also accommodate the task.

For example, in a simplified system, there are 4 NUMA nodes, each
node with 4 LLCs. The node distance matrix is:
        NODE0    NODE1    NODE2    NODE3
NODE0   10       20       30       40
NODE1   20       10       25       30
NODE2   30       25       10       20
NODE3   40       30       20       10

Given a preferred LLC, its node's distance row ranks the other NUMA
nodes. For example, if the preferred LLC is in NODE0, NODE1 is ranked
before NODE2, so LLCs in NODE1 precede LLCs in NODE2 in the resulting
affinity sequence.

To rank LLCs inside the node containing the preferred LLC, there is no
existing LLC distance matrix to use. So, we construct one which has no
real physical meaning and is only a hint for constructing the affinity
sequence. For example, consider this LLC distance matrix:

        LLC0    LLC1    LLC2    LLC3
LLC0    0       2       3       4
LLC1    2       0       4       1
LLC2    3       4       0       2
LLC3    4       1       2       0

Each row ranks the other LLCs relative to the LLC represented by that
row. With LLC0 as the preferred LLC, its row ranks LLC1 before LLC2 and
LLC2 before LLC3. A different preferred LLC selects a different row and
may therefore produce a different order.

Combining the node ranking, the selected preferred-LLC row, and the
ascending LLC-ID order used inside other nodes produces one affinity
sequence for a given preferred LLC. It does not define a global order
between arbitrary LLC pairs.

Note that there may be identical numbers inside a row of a real
node distance. So, we should build a new node distance matrix in
which the distance values within each row are unique. This node
distance matrix is only used for migration decisions in the
cache-aware scheduling (CAS) extension.

Once a preferred LLC affinity sequence is constructed, the scheduler
uses it as an input to migration decisions. For example, assume LLC0
is the preferred LLC and its affinity sequence is as follows:
LLC0->LLC1->LLC2->LLC3...->LLC15. (Note that this is a simple example.
Generally, for the node containing the preferred LLC, the sequence is
decided by the LLC distance matrix inside the node. For other nodes,
LLCs are ordered by ascending LLC ID within each node,
while the node sequence is decided by the node distance matrix.)

The affinity sequence gives an ordered expansion preference, rather
than an unconditional per-LLC saturation gate. The scheduler estimates
the aggregate utilization of a thread group and derives the furthest
LLC-distance tier required for that demand. A destination LLC within
the resulting range is eligible when it has capacity for the task,
even if an earlier LLC in the sequence is not yet saturated. For
example, LLC3 may be selected when the estimated range reaches LLC3
and LLC3 has capacity. A destination outside that range still uses
the ordered saturation check to preserve aggregation.

Thus, for a given preferred LLC, the affinity sequence is fixed, while
the scheduler dynamically determines how many LLCs from the beginning
of that sequence the thread group may use, based on its estimated total
utilization.

Before this implementation, we tried to maintain an LLC mask for each
process's thread group to record its current resource scope. However,
this approach proved to be difficult to maintain. The mask is updated in
task_cache_work() but consulted during load balancing, so rapid
workload changes can leave the mask temporarily out of date. As a
result, it may no longer accurately represent the thread group's
actual resource usage, making migration decisions unreliable.

The LLC mask is also insufficient for guiding source group
selection during load balancing. The mask is associated with a
specific thread group, but when load balancing searches for a
source sched_group or runqueue, there is no available task context
to retrieve the corresponding LLC mask. We need a task-independent
mechanism that can provide such information during load balancing.

This patch set also tries to address NUMA balancing-related impacts.
With NUMA balancing enabled, the preferred LLC fails to stay stable
since the scan range is limited to the current task's preferred node.
We fix this by adding all preferred nodes of active tasks in the thread
group to the scan range.

We also seek to suppress task-migration conflicts between CAS and
NUMA balancing, including splitting NUMA balancing into task and page
migration paths (suggested by Chen Yu <yu.c.chen@intel.com>) and removing
unnecessary preferred node checks in load balancing code. These parts
are unfinished and open for further discussion.

[Patch organization]
The series is organized as follows:

  Patches 1-6 build the topology infrastructure: LLC-to-node mapping,
  unique node-distance values, node/LLC traversal helpers, and an sd_node
  scheduling domain.

  Patches 7-10 collect preferred-NUMA-node information for tasks and CPUs,
  and add the per-sched-domain state needed by load balancing.

  Patches 11-16 implement LLC-granular migration decisions. They calculate
  affinity gain, select source runqueues and groups, decide migration
  eligibility, and allow active balancing to expand to another LLC.

  Patches 17-19 handle the interaction with NUMA balancing: they make its
  decisions LLC-granular, scan all preferred nodes of a thread group, and
  remove no-longer-needed preferred LLC/node restrictions.

  Patches 20-22 estimate whole-thread-group utilization, derive the LLC
  range needed for that utilization, allow migration within that range, and
  walk the preferred node starting from the preferred LLC.

  Patch 23 exposes a task's preferred LLC for scheduler debugging.

This patch set is far from perfect and still contains some unresolved
issues. Before proceeding further, I would like to confirm whether I am
heading in the right direction. Therefore, I am sending these patches
out to gather early feedback.

v1: https://lore.kernel.org/all/20260625030759.25928-1-wujianyong@hygon.cn/

Changes since v1:
(1) No longer scale resources based on sched domain boundaries.
(2) Add a new node distance matrix with no duplicate values within a row.
(3) Add an intra-node LLC distance matrix to rank candidate LLCs
    relative to a given preferred LLC within a node.
(4) Change the way affinity gain is calculated.
(5) Change the way migration permission is decided.
(6) Fix saturation issues in some tests like schbench.
(7) Include all preferred nodes related to the thread group into the scan
    range.
(8) Add a tunable to enable/disable task/page migration for NUMA balancing
    independently. (Suggested by Chen Yu)
(9) Estimate whole thread-group utilization to derive its LLC capacity
    range.
(10) Permit migration to an LLC within that estimated range, even when an
     earlier LLC in the affinity sequence is not saturated.
(11) Walk LLCs in the preferred node from the preferred LLC.
(12) Fix a bug in the debug print patch. (Suggested by XIAO WU)

Tested on a Hygon machine with the following topology:
* 2 sockets
* 4 NUMA nodes per socket
* 4 LLCs per NUMA node
* 4 cores per LLC domain
* 2 SMT threads per core

The scheduler changes apply cleanly on Linus' tree at 0f23d56f17fd
("Merge tag 'linux_kselftest-next-7.3-rc1' of ...kselftest") and build
there.

Functional test:
Ran a busy loop test program with 4, 8, 12, 16, 20, 24, 28, 32, and
64 threads. The scheduler is able to roughly scale resources at LLC
granularity.

Performance test:
* llc_gran refers to this patch set.
* The baseline is the same tree without this series, that is Linus' tree at
  0f23d56f17fd. Note that the baseline already carries CONFIG_SCHED_CACHE,
  so these numbers compare the existing single-LLC aggregation against the
  LLC-granular expansion this series adds, not against a kernel without
  cache-aware scheduling.
* Both kernels run with NUMA balancing disabled and with 'aggr_tolerance'
  set to 90, so the two aggregate under the same threshold and the
  difference reflects the code rather than the tunable.
* Each test is repeated at least 20 times; results take the average value.

To reproduce:

  # baseline
  git checkout 0f23d56f17fd
  make olddefconfig && make -j$(nproc) && install and boot it

  # llc_gran
  git am v2-00*.patch     # the 23 patches of this series
  make olddefconfig && make -j$(nproc) && install and boot it

  # on each kernel, before measuring
  echo 0  > /proc/sys/kernel/numa_balancing
  echo 90 > /sys/kernel/debug/sched/llc_balancing/aggr_tolerance

  # then
  for f in 2 4 8 12 16 20 24 32 48; do
      for g in 1 2; do
          hackbench -T -p -f $f -g $g -l 100000
      done
  done
  for t in 2 4 6 8 12 16 32 48 64 96 128; do
      schbench -m 1 -t $t -r 30
  done

The reported schbench figure is the 99.0th percentile of the Wakeup
Latencies block from the final cumulative report.

[hackbench]
(lower is better, normalized to baseline; the figure in parentheses is the
standard deviation, as a percentage of the mean)
test cmd: hackbench -T -p -f $f -g $g -l 100000

pipe   groups  baseline          llc_gran          lg improve
============================================================
2      1       1.000 (47.90%)    0.919 (3.73%)     8.094%
2      2       1.000 (58.79%)    0.799 (11.97%)    20.126%
4      1       1.000 (42.69%)    0.930 (26.53%)    6.966%
4      2       1.000 (29.86%)    0.717 (8.96%)     28.312%
8      1       1.000 (20.44%)    0.654 (7.32%)     34.613%
8      2       1.000 (11.39%)    0.711 (12.57%)    28.928%
12     1       1.000 (13.72%)    0.646 (9.45%)     35.399%
12     2       1.000 (10.97%)    0.701 (6.73%)     29.907%
16     1       1.000 (12.48%)    0.703 (7.51%)     29.711%
16     2       1.000 (5.28%)     0.728 (6.41%)     27.171%
20     1       1.000 (5.89%)     0.663 (3.76%)     33.651%
20     2       1.000 (5.47%)     0.861 (4.25%)     13.894%
24     1       1.000 (6.18%)     0.678 (2.88%)     32.167%
24     2       1.000 (6.23%)     0.942 (6.78%)     5.776%
32     1       1.000 (4.64%)     0.690 (3.70%)     31.023%
32     2       1.000 (1.51%)     1.002 (4.86%)     -0.151%
48     1       1.000 (2.08%)     0.942 (2.45%)     5.847%
48     2       1.000 (1.51%)     1.041 (2.49%)     -4.060%

llc_gran is faster at 16 of the 18 configurations, by a median of 27.7%.
The largest gains occur in the middle of the range, especially for one group
from 8 to 32 pipes; gains taper off at both ends and vary with group count.

Two configurations are slower. Only 48 pipes with 2 groups exceeds
run-to-run noise, at -4.1%; 32 pipes with 2 groups is within it.

Run-to-run variance improves at 12 of the 18 configurations, most clearly
at the small end, where the baseline reaches 30-59% against 4-27% for
llc_gran.

[schbench]
p99 wakeup latency (lower is better, normalized to baseline; the figure in
parentheses is the standard deviation, as a percentage of the mean)
test cmd: schbench -m 1 -t $threads -r 30

threads   baseline          llc_gran          lg improve
=========================================================
2         1.000 (33.11%)    0.801 (6.27%)     19.86%
4         1.000 (31.09%)    0.787 (11.43%)    21.32%
6         1.000 (21.89%)    0.832 (11.11%)    16.79%
8         1.000 (15.20%)    0.863 (14.70%)    13.72%
12        1.000 (14.23%)    0.883 (1.97%)     11.68%
16        1.000 (11.30%)    0.919 (1.21%)     8.14%
32        1.000 (12.81%)    0.784 (2.97%)     21.55%
48        1.000 (6.79%)     0.670 (3.67%)     33.02%
64        1.000 (3.04%)     0.647 (3.28%)     35.33%
96        1.000 (3.18%)     0.863 (18.11%)    13.72%
128       1.000 (4.66%)     0.952 (15.24%)    4.79%

llc_gran improves the p99 wakeup latency at all 11 thread counts, by a
median of 16.8%, and 10 of the 11 exceed run-to-run noise. The gain is
largest at 48 and 64 threads (+33.0% and +35.3%). Only 128 threads, at
+4.8%, stays within noise.

Variance improves at 8 of the 11 thread counts. It remains higher than the
baseline at 96 and 128 threads, where llc_gran runs at 15-18% against
3-5%.

The root cause of the hackbench regression at 48 pipes, and of the wider
spread in wakeup latency at high thread counts, will be investigated in
future work.

Further testing across a wider range of workloads and hardware platforms
is needed.

Jianyong Wu (23):
  sched/topology: Add llc_to_node() to translate LLC id to NUMA node
  sched/topology: Introduce a NUMA distance matrix with unique distance
    values
  sched/topology: Introduce a macro to traverse node
  sched/topology: Introduce a method to calculate the llc distance
  sched/topology: Introduce a macro to traverse LLC inside node
  sched/topology: Add sd_node for the NODE sched domain
  sched/cache: Prioritize preferred NUMA node selection over LLC
    selection
  sched/topology: Introduce a per-CPU tasks NUMA preferred counter
  sched/cache: Account percpu sd task NUMA preference
  sched/topology: Add per-sd scratch for the load balance affinity score
  sched/cache: Introduce helpers for task migration decisions
  sched/cache: Introduce rq affinity gain calculation
  sched/cache: Pick optimal src rq/group using affinity promotion metric
  sched/cache: Drop prefer_sibling restriction for llc_balance
  sched/cache: Judge migration eligibility in LLC granularity
  sched/cache: Allow un-throttled active balance to spread out of a full
    LLC
  sched/fair: Fine-granularity NUMA balancing
  sched/cache: Scan all prefer nodes in thread group
  sched/cache: Remove preferred LLC/node check no longer needed
  sched/cache: Estimate utilization of the whole thread group
  sched/cache: Spread workloads within an estimated LLC range
  sched/cache: Walk the preferred node from the preferred LLC
  sched/debug: Print task preferred LLC for scheduler debugging

 include/linux/mm_types.h       |    6 +-
 include/linux/sched.h          |    5 +
 include/linux/sched/sysctl.h   |   12 +
 include/linux/sched/topology.h |    7 +
 include/linux/topology.h       |    6 +
 kernel/sched/core.c            |   87 +++
 kernel/sched/debug.c           |   28 +-
 kernel/sched/fair.c            | 1112 +++++++++++++++++++++++++++-----
 kernel/sched/sched.h           |   49 ++
 kernel/sched/topology.c        |  873 ++++++++++++++++++++++++-
 mm/memory.c                    |    3 +
 11 files changed, 2007 insertions(+), 181 deletions(-)

-- 
2.34.1


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

end of thread, other threads:[~2026-08-29 10:31 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-27 12:27 [RFC PATCH v2 00/23] sched: Scale cache-aware aggregation at LLC granularity Jianyong Wu
2026-08-27 12:27 ` [RFC PATCH v2 01/23] sched/topology: Add llc_to_node() to translate LLC id to NUMA node Jianyong Wu
2026-08-29 10:31   ` Peter Zijlstra
2026-08-27 12:27 ` [RFC PATCH v2 02/23] sched/topology: Introduce a NUMA distance matrix with unique distance values Jianyong Wu
2026-08-27 12:27 ` [RFC PATCH v2 03/23] sched/topology: Introduce a macro to traverse node Jianyong Wu
2026-08-27 12:27 ` [RFC PATCH v2 04/23] sched/topology: Introduce a method to calculate the llc distance Jianyong Wu
2026-08-27 12:27 ` [RFC PATCH v2 05/23] sched/topology: Introduce a macro to traverse LLC inside node Jianyong Wu
2026-08-27 12:27 ` [RFC PATCH v2 06/23] sched/topology: Add sd_node for the NODE sched domain Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 07/23] sched/cache: Prioritize preferred NUMA node selection over LLC selection Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 08/23] sched/topology: Introduce a per-CPU tasks NUMA preferred counter Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 09/23] sched/cache: Account percpu sd task NUMA preference Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 10/23] sched/topology: Add per-sd scratch for the load balance affinity score Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 11/23] sched/cache: Introduce helpers for task migration decisions Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 12/23] sched/cache: Introduce rq affinity gain calculation Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 13/23] sched/cache: Pick optimal src rq/group using affinity promotion metric Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 14/23] sched/cache: Drop prefer_sibling restriction for llc_balance Jianyong Wu
2026-08-28  1:58 ` [RFC PATCH v2 15/23] sched/cache: Judge migration eligibility in LLC granularity Jianyong Wu
2026-08-28  2:04 ` [RFC PATCH v2 16/23] sched/cache: Allow un-throttled active balance to spread out of a full LLC Jianyong Wu
2026-08-28  2:07 ` [RFC PATCH v2 17/23] sched/fair: Fine-granularity NUMA balancing Jianyong Wu
2026-08-28  2:09 ` [RFC PATCH v2 18/23] sched/cache: Scan all prefer nodes in thread group Jianyong Wu
2026-08-28  2:10 ` [RFC PATCH v2 19/23] sched/cache: Remove preferred LLC/node check no longer needed Jianyong Wu
2026-08-28  2:11 ` [RFC PATCH v2 20/23] sched/cache: Estimate utilization of the whole thread group Jianyong Wu
2026-08-28  2:13 ` [RFC PATCH v2 21/23] sched/cache: Spread workloads within an estimated LLC range Jianyong Wu
2026-08-28  2:14 ` [RFC PATCH v2 22/23] sched/cache: Walk the preferred node from the preferred LLC Jianyong Wu
2026-08-28  2:15 ` [RFC PATCH v2 23/23] sched/debug: Print task preferred LLC for scheduler debugging Jianyong Wu

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®