[RFC PATCH 4/6] sched/fair: Restrict newidle balance to LLC domain

From: Li kunyu

Date: Tue Oct 20 2026 - 04:44:27 EST


[Purpose]

The newidle CPU path logic update is solely intended to quickly obtain
eligible tasks. By restricting task acquisition to the LLC (L3)
scheduling domain and avoiding traversal and task migration at levels
above it, this change avoids jitter in scenarios where the entire
machine is idle or the CPU load is relatively balanced. This is because
each traversal of higher-level scheduling domains remains costly, and
migrating tasks across dies (LLCs) incurs substantial short-term
overhead, such as TLB flushes/refills and page migration:

1. When overall CPU utilization is relatively low, avoid the
scenario where the whole CPU is idle yet cross-die (high-latency) tasks
are being pulled. In such cases, it is better to run only one logical
CPU per core to avoid cache interference and frequent TLB flushes. This
applies when:
1.1. the CPU has multiple sleeping tasks (with delayed dequeue
disabled).
1.2. the number of runnable tasks on the CPU is less than 2.

2. When overall CPU load is relatively balanced, refrain from
pulling cross-die (high-latency) tasks. This avoids task jitter and
prevents resource exhaustion (similar to the issues in 2.1).

[Implementation]

After extensive testing on a Hygon 7447v CPU server (Model 7, with 384
logical cores), several issues were identified. For example, when the CPU
first enters idle mode, cross-NUMA-node task pulling performs poorly in
certain test scenarios, including MySQL, UnixBench, and tbench. Likewise,
certain advantages were observed in tests using hackbench -l 2560 -g 4 and
in additional test groups.

However, its benefits in some respects are simply too great: it avoids
more time-consuming and extensive scheduling-domain traversal, as well
as cross-NUMA-node task pulling (avoiding the problem of low hit rates
from memory to L3 cache). Limiting the task-pulling range to the L3
cache is more efficient.

In actual testing, the following scenarios have shown significant
improvements:

1. unixbench: Overall improvement of 5% to 8% across 384 logical CPUs.

2. mysql: TPS and QPS increased by approximately 5% (this may not be
entirely accurate), while the 95th percentile latency decreased by
3% to 5%.

Tested-by: Li Wang (Hieco) <li.wang@xxxxxxxxx>
Signed-off-by: Li kunyu <likunyu@xxxxxxxxxxxxxx>
---
kernel/sched/fair.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 6e2271484c86..f2bf4b53d8a9 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -14983,6 +14983,24 @@ static inline bool nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle
static inline void nohz_newidle_balance(struct rq *this_rq) { }
#endif /* !CONFIG_NO_HZ_COMMON */

+/*
+ * is_smt_buddy_newidle_constrain - After enabling the smt_buddy_assist
+ * feature, check whether the current
+ * scheduling domain meets the conditions
+ * for skipping statistics.
+ * @sd: The current scheduling domain that is to be traversed.
+ */
+static bool is_smt_buddy_newidle_constrain(struct sched_domain *sd)
+{
+ if (!sched_feat(SMT_BUDDY_ASSIST))
+ return false;
+
+ if (sd->flags & SD_NUMA)
+ return true;
+
+ return false;
+}
+
/*
* sched_balance_newidle is called by schedule() if this_cpu is about to become
* idle. Attempts to pull tasks from other CPUs.
@@ -15080,7 +15098,8 @@ static int sched_balance_newidle(struct rq *this_rq, struct rq_flags *rf)
weight = (1024 + weight/2) / weight;
}

- pulled_task = sched_balance_rq(this_cpu, this_rq,
+ if (!is_smt_buddy_newidle_constrain(sd))
+ pulled_task = sched_balance_rq(this_cpu, this_rq,
sd, CPU_NEWLY_IDLE,
&continue_balancing,
false);
--
2.47.3