[PATCH v2] sched/numa: avoid doubling scan period for remote private faults

From: Hongling Zeng

Date: Tue Aug 04 2026 - 02:21:05 EST


update_task_scan_period() currently uses local + shared to determine
whether there were any relevant memory faults. This incorrectly treats
a workload with only remote private faults as having no faults:

local = 0
shared = 0
remote > 0

As a result, the NUMA scan period is unconditionally doubled.

Use local + remote for the no-fault check so that remote private faults
continue through the locality-ratio calculation. This does not necessarily
make the scan period shorter. For a pure private workload, ps_ratio reaches
NUMA_PERIOD_SLOTS and the ratio logic still increases the scan period.
However, it avoids the unconditional doubling and lets the normal policy
determine the adjustment.

Also fix the comments for ps_ratio and lr_ratio, which described the
opposite ratios.

Suggested-by: Zhan Xusheng <zhanxusheng@xxxxxxxxxx>
Signed-off-by: Hongling Zeng <zenghongling@xxxxxxxxxx>

---
Changes from v1:
- Corrected commit message to remove incorrect "speed up" claim
- Changed patch title to accurately reflect the behavioral change
- Removed stale comment in lr_ratio branch about shared memory
- Added scan period comparison for clarity
---
kernel/sched/fair.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 37001c63452e..78f8dc4cf5ea 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3505,9 +3505,13 @@ static void update_task_scan_period(struct task_struct *p,
* completely idle or all activity is in areas that are not of interest
* to automatic numa balancing. Related to that, if there were failed
* migration then it implies we are migrating too quickly or the local
- * node is overloaded. In either case, scan slower
+ * node is overloaded. In either case, scan slower.
+ *
+ * Slow down if there are no actual memory faults (local + remote == 0),
+ * or if previous migrations failed. Otherwise, use the locality ratios
+ * to decide whether the scan rate should be adjusted.
*/
- if (local + shared == 0 || p->numa_faults_locality[2]) {
+ if (local + remote == 0 || p->numa_faults_locality[2]) {
p->numa_scan_period = min(p->numa_scan_period_max,
p->numa_scan_period << 1);

@@ -3529,8 +3533,8 @@ static void update_task_scan_period(struct task_struct *p,

if (ps_ratio >= NUMA_PERIOD_THRESHOLD) {
/*
- * Most memory accesses are local. There is no need to
- * do fast NUMA scanning, since memory is already local.
+ * Most memory accesses are private. Slow down NUMA scanning
+ * since there is little shared memory to rebalance.
*/
int slot = ps_ratio - NUMA_PERIOD_THRESHOLD;
if (!slot)
@@ -3538,9 +3542,8 @@ static void update_task_scan_period(struct task_struct *p,
diff = slot * period_slot;
} else if (lr_ratio >= NUMA_PERIOD_THRESHOLD) {
/*
- * Most memory accesses are shared with other tasks.
- * There is no point in continuing fast NUMA scanning,
- * since other tasks may just move the memory elsewhere.
+ * Most memory accesses are local. There is no need to
+ * do fast NUMA scanning, since memory is already local.
*/
int slot = lr_ratio - NUMA_PERIOD_THRESHOLD;
if (!slot)
--
2.25.1