* [PATCH] sched/fair: Skip NUMA balancing scan on memoryless nodes
@ 2026-07-30 17:51 Phineas Su
2026-07-31 5:55 ` K Prateek Nayak
2026-07-31 10:31 ` Peter Zijlstra
0 siblings, 2 replies; 3+ messages in thread
From: Phineas Su @ 2026-07-30 17:51 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot
Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak, linux-kernel, Phineas Su
On systems with memoryless NUMA nodes (e.g. CPU-only nodes created via
memory hiding, socket topologies with unpopulated memory, or CPU-only
NUMA nodes), tasks running on these CPUs cause automatic NUMA balancing
(kernel.numa_balancing=1) to repeatedly schedule task_numa_work() from
task_tick_numa().
When task_numa_work() executes, it unmaps VMAs (PROT_NONE) to induce
NUMA hinting faults (do_numa_page()). Fault handling then attempts page
migration (migrate_misplaced_folio()) to the task's current CPU NUMA
node. However, because the node has no managed memory (N_MEMORY is
false), page allocations continuously fail (TNF_MIGRATE_FAIL), while
task_tick_numa() repeatedly reschedules VMA scanning every scan period.
This results in heavy kernel system overhead (%sys CPU usage spiking up
to ~78%) and continuous page fault storms without any possible NUMA
placement benefit.
Fix this by:
1. Checking node_state(task_node(curr), N_MEMORY) in task_tick_numa() so
tasks executing on CPUs of memoryless nodes do not schedule
numa_work callbacks via task_work_add().
2. Checking node_state(task_node(p), N_MEMORY) in task_numa_work() as a
safeguard to immediately abort VMA scanning if a task migrated to a
memoryless node while numa_work was already enqueued.
Signed-off-by: Phineas Su <pohaosu@google.com>
---
kernel/sched/fair.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6ee1..214cf0f2c692 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4101,6 +4101,9 @@ static void task_numa_work(struct callback_head *work)
if (p->flags & PF_EXITING)
return;
+ if (!node_state(task_node(p), N_MEMORY))
+ return;
+
/*
* Memory is pinned to only one NUMA node via cpuset.mems, naturally
* no page can be migrated.
@@ -4391,6 +4394,9 @@ static void task_tick_numa(struct rq *rq, struct task_struct *curr)
if (!curr->mm || (curr->flags & (PF_EXITING | PF_KTHREAD)) || work->next != work)
return;
+ if (!node_state(task_node(curr), N_MEMORY))
+ return;
+
/*
* Using runtime rather than walltime has the dual advantage that
* we (mostly) drive the selection from busy threads and that the
--
2.55.0.508.g3f0d502094-goog
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] sched/fair: Skip NUMA balancing scan on memoryless nodes
2026-07-30 17:51 [PATCH] sched/fair: Skip NUMA balancing scan on memoryless nodes Phineas Su
@ 2026-07-31 5:55 ` K Prateek Nayak
2026-07-31 10:31 ` Peter Zijlstra
1 sibling, 0 replies; 3+ messages in thread
From: K Prateek Nayak @ 2026-07-31 5:55 UTC (permalink / raw)
To: Phineas Su, Ingo Molnar, Peter Zijlstra, Juri Lelli,
Vincent Guittot
Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, linux-kernel
Hello Phineas,
On 7/30/2026 11:21 PM, Phineas Su wrote:
> On systems with memoryless NUMA nodes (e.g. CPU-only nodes created via
> memory hiding, socket topologies with unpopulated memory, or CPU-only
> NUMA nodes), tasks running on these CPUs cause automatic NUMA balancing
> (kernel.numa_balancing=1) to repeatedly schedule task_numa_work() from
> task_tick_numa().
>
> When task_numa_work() executes, it unmaps VMAs (PROT_NONE) to induce
> NUMA hinting faults (do_numa_page()). Fault handling then attempts page
> migration (migrate_misplaced_folio()) to the task's current CPU NUMA
> node. However, because the node has no managed memory (N_MEMORY is
> false), page allocations continuously fail (TNF_MIGRATE_FAIL), while
> task_tick_numa() repeatedly reschedules VMA scanning every scan period.
Isn't task_numa_work() also responsible for scanning? Inhibiting that
can be problematic - task can perhaps move to a node which has both CPUs
and memory and the hinting faults can help determine that.
I feel the page migration to !N_MEMORY node should be inhibited at
numa_migrate_check() on the mm side rather than skipping the
task_numa_work() entirely which can still be beneficial.
task_numa_fault() on the failure path there can instead move the task to
the node with CPU where the hot pages reside instead of trying to move
the pages to the node where task is running which, as it turns out, has
no memory to accept these pages.
Am I missing something?
> This results in heavy kernel system overhead (%sys CPU usage spiking up
> to ~78%) and continuous page fault storms without any possible NUMA
> placement benefit.
Now if you have a case where task is moveable only between a set of
nodes that don't have any memory and the hinting fault overhead keeps
adding up, that is a different problem.
>
> Fix this by:
> 1. Checking node_state(task_node(curr), N_MEMORY) in task_tick_numa() so
> tasks executing on CPUs of memoryless nodes do not schedule
> numa_work callbacks via task_work_add().
> 2. Checking node_state(task_node(p), N_MEMORY) in task_numa_work() as a
> safeguard to immediately abort VMA scanning if a task migrated to a
> memoryless node while numa_work was already enqueued.
>
> Signed-off-by: Phineas Su <pohaosu@google.com>
> ---
> kernel/sched/fair.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index d78467ec6ee1..214cf0f2c692 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -4101,6 +4101,9 @@ static void task_numa_work(struct callback_head *work)
> if (p->flags & PF_EXITING)
> return;
>
> + if (!node_state(task_node(p), N_MEMORY))
> + return;
> +
> /*
> * Memory is pinned to only one NUMA node via cpuset.mems, naturally
> * no page can be migrated.
> @@ -4391,6 +4394,9 @@ static void task_tick_numa(struct rq *rq, struct task_struct *curr)
> if (!curr->mm || (curr->flags & (PF_EXITING | PF_KTHREAD)) || work->next != work)
> return;
>
> + if (!node_state(task_node(curr), N_MEMORY))
> + return;
> +
> /*
> * Using runtime rather than walltime has the dual advantage that
> * we (mostly) drive the selection from busy threads and that the
> --
> 2.55.0.508.g3f0d502094-goog
>
--
Thanks and Regards,
Prateek
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] sched/fair: Skip NUMA balancing scan on memoryless nodes
2026-07-30 17:51 [PATCH] sched/fair: Skip NUMA balancing scan on memoryless nodes Phineas Su
2026-07-31 5:55 ` K Prateek Nayak
@ 2026-07-31 10:31 ` Peter Zijlstra
1 sibling, 0 replies; 3+ messages in thread
From: Peter Zijlstra @ 2026-07-31 10:31 UTC (permalink / raw)
To: Phineas Su
Cc: Ingo Molnar, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, linux-kernel
On Thu, Jul 30, 2026 at 05:51:51PM +0000, Phineas Su wrote:
> On systems with memoryless NUMA nodes (e.g. CPU-only nodes created via
> memory hiding, socket topologies with unpopulated memory, or CPU-only
> NUMA nodes), tasks running on these CPUs cause automatic NUMA balancing
> (kernel.numa_balancing=1) to repeatedly schedule task_numa_work() from
> task_tick_numa().
>
> When task_numa_work() executes, it unmaps VMAs (PROT_NONE) to induce
> NUMA hinting faults (do_numa_page()). Fault handling then attempts page
> migration (migrate_misplaced_folio()) to the task's current CPU NUMA
> node. However, because the node has no managed memory (N_MEMORY is
> false), page allocations continuously fail (TNF_MIGRATE_FAIL), while
> task_tick_numa() repeatedly reschedules VMA scanning every scan period.
> This results in heavy kernel system overhead (%sys CPU usage spiking up
> to ~78%) and continuous page fault storms without any possible NUMA
> placement benefit.
>
> Fix this by:
> 1. Checking node_state(task_node(curr), N_MEMORY) in task_tick_numa() so
> tasks executing on CPUs of memoryless nodes do not schedule
> numa_work callbacks via task_work_add().
> 2. Checking node_state(task_node(p), N_MEMORY) in task_numa_work() as a
> safeguard to immediately abort VMA scanning if a task migrated to a
> memoryless node while numa_work was already enqueued.
Rather than fully disabling, I would argue the right thing is to ensure
the pages are nearest the node the task runs on.
That is, rather than force migrate to *this* node, ensure they are on a
node such that the distance to *this* node is minimal.
After all, the tasks still run here. Not migrating the memory just
because this node doesn't have memory might mean the memory stays
maximally far away, which is suboptimal.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-31 10:31 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 17:51 [PATCH] sched/fair: Skip NUMA balancing scan on memoryless nodes Phineas Su
2026-07-31 5:55 ` K Prateek Nayak
2026-07-31 10:31 ` Peter Zijlstra
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.