Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Jianyong Wu <wujianyong@hygon.cn>
To: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>,
	Juri Lelli <juri.lelli@redhat.com>,
	Vincent Guittot <vincent.guittot@linaro.org>,
	Chen Yu <yu.c.chen@intel.com>,
	Tim Chen <tim.c.chen@linux.intel.com>,
	Dietmar Eggemann <dietmar.eggemann@arm.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Ben Segall <bsegall@google.com>, Mel Gorman <mgorman@suse.de>,
	Valentin Schneider <vschneid@redhat.com>,
	K Prateek Nayak <kprateek.nayak@amd.com>,
	"Shrikanth Hegde" <sshegde@linux.ibm.com>,
	Phil Auld <pauld@redhat.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	David Hildenbrand <david@kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"linux-mm@kvack.org" <linux-mm@kvack.org>,
	"jianyong.wu@outlook.com" <jianyong.wu@outlook.com>,
	Yuan Zhong <zhongyuan@hygon.cn>, Huangsj <huangsj@hygon.cn>,
	Fengyu Wang <wangfengyu@hygon.cn>,
	Zhiwei Ying <yingzhiwei@hygon.cn>,
	"justin.he@arm.com" <justin.he@arm.com>
Subject: RE: [RFC PATCH v2 11/23] sched/cache: Introduce helpers for task migration decisions
Date: Wed, 2 Sep 2026 05:08:40 +0000	[thread overview]
Message-ID: <226d79fa93a84193aa2507113747d348@hygon.cn> (raw)
In-Reply-To: <20260901090843.GQ4120091@noisy.programming.kicks-ass.net>

Hi Peter,

> -----Original Message-----
> From: Peter Zijlstra <peterz@infradead.org>
> Sent: Tuesday, September 1, 2026 5:09 PM
> To: Jianyong Wu <wujianyong@hygon.cn>
> Cc: Ingo Molnar <mingo@redhat.com>; Juri Lelli <juri.lelli@redhat.com>;
> Vincent Guittot <vincent.guittot@linaro.org>; Chen Yu
> <yu.c.chen@intel.com>; Tim Chen <tim.c.chen@linux.intel.com>; Dietmar
> Eggemann <dietmar.eggemann@arm.com>; Steven Rostedt
> <rostedt@goodmis.org>; Ben Segall <bsegall@google.com>; Mel Gorman
> <mgorman@suse.de>; Valentin Schneider <vschneid@redhat.com>; K
> Prateek Nayak <kprateek.nayak@amd.com>; Shrikanth Hegde
> <sshegde@linux.ibm.com>; Phil Auld <pauld@redhat.com>; Andrew
> Morton <akpm@linux-foundation.org>; David Hildenbrand
> <david@kernel.org>; linux-kernel@vger.kernel.org; linux-mm@kvack.org;
> jianyong.wu@outlook.com; Yuan Zhong <zhongyuan@hygon.cn>; Huangsj
> <huangsj@hygon.cn>; Fengyu Wang <wangfengyu@hygon.cn>; Zhiwei Ying
> <yingzhiwei@hygon.cn>; justin.he@arm.com
> Subject: Re: [RFC PATCH v2 11/23] sched/cache: Introduce helpers for task
> migration decisions
> 
> On Thu, Aug 27, 2026 at 08:28:04PM +0800, Jianyong Wu wrote:
> 
> > +/*
> > + * Decide if migration should happen on a specific node.
> > + * The node here is an LLC or a NUMA.
> > + */
> > +static enum llc_mig __maybe_unused can_migrate_node(int src_cpu, int
> dst_cpu,
> > +			struct task_struct *p, bool to_pref)
> > +{
> > +	const struct cpumask *span;
> > +	struct mm_struct *mm;
> > +	unsigned long dst_util, dst_cap, tsk_util = 0;
> > +	unsigned long src_util = 0, src_cap = 0;
> > +	unsigned long acc_util = 0, acc_cap = 0;
> > +	int node, target_cpu = src_cpu;
> > +	int get_src = 0;
> > +
> > +	if (!get_llc_stats(dst_cpu, &dst_util, &dst_cap))
> > +		return mig_unrestricted;
> > +
> > +	if (!get_llc_stats(src_cpu, &src_util, &src_cap))
> > +		src_cap = 0;
> 
> Comparing against can_migrate_llc(), that bails with mig_unrestricted
> when !get_llc_stats(src_cpu).
> 
Agreed.

> > +
> > +	if (p) {
> > +		mm = p->mm;
> > +		if (mm) {
> > +			if (mm->sc_stat.cpu >= 0)
> > +				target_cpu = mm->sc_stat.cpu;
> > +		}
> > +		tsk_util = task_util(p);
> > +	}
> 
> It isn't clear when !p would be valid. migration is always about a task,
> no?
>
This helper is also called by llc_balance which will pass NULL task. So, !p
is valid here, same as can_migrate_llc(). In that case tsk_util is 0 and the
decision is made via the to_pref path.
 
> > +
> > +	dst_util = dst_util + tsk_util;
> 
> can_migrate_llc() also adjusts src_util by subtracting tsk_util (and
> flooring at 0).

Both the pre- and post-migration utilization are needed here. The current imbalance
check uses the utilization before the move, while the capacity and anti-bounce checks
need the utilization after the move.

I'll introduce explicit src_pre/src_post and dst_pre/dst_post values with the source
subtraction floored to zero.

> 
> > +	if (to_pref) {
> > +		unsigned long dst_pre = dst_util - tsk_util;
> > +
> > +		if (fits_llc_capacity(dst_util, dst_cap))
> > +			return mig_llc;
> > +
> > +		/*
> > +		 * The destination is over the margin. That is a reason to
> > +		 * refuse a task while the margin can still be met, but not
> > +		 * while every LLC of the node is over it: no placement
> > +		 * satisfies the margin then, and refusing every migration
> > +		 * leaves the imbalance in place.
> > +		 *
> > +		 * Let the task through when the move still lowers the peak,
> > +		 * that is when the source is noticeably heavier than the
> > +		 * destination and carries at least two more tasks worth of
> > +		 * utilization. The second condition keeps the destination
> > +		 * from becoming the heavier side, which would bounce the
> > +		 * task straight back.
> > +		 */
> > +		if (src_cap && util_greater(src_util, dst_pre) &&
> > +		    src_util >= dst_pre + 2 * tsk_util)
> > +			return mig_llc;
> > +
> > +		return mig_forbid;
> > +	}
> > +
> > +	for_each_sched_node(target_cpu, node) {
> 
> So this iterates the nodes in the order specific to the node that
> contains target_cpu.

Yes, the node including target_cpu decides the affinity node sequence.

> 
> > +		unsigned long u = 0, c = 0, nu, nc;
> > +
> > +		/*
> > +		 * The walk starts at the anchor, so the nodes it crosses before
> > +		 * reaching the source say nothing about this migration: the task
> > +		 * does not live there and is not going there. Judging them only
> > +		 * lets an unrelated node with room refuse the move. Start at
> the
> > +		 * node the task actually sits on.
> > +		 */
> > +		if (!get_src) {
> > +			if (!cpumask_test_cpu(src_cpu, cpumask_of_node(node)))
> > +				continue;
> > +			else
> 
> Strictly speaking this else is superfluous.
>
Yeah, will remove it.
 
> > +				get_src = 1;
> > +		}
> 
> And then you skip the nodes between target and src, which are the nodes
> with best locality, confusing, but lets read on..
> 
> (sometimes target == src, and you thus don't skip anything, but other
> times this is the preferred cpu)
>

As this is the "!to-prefer" path, dest cpu is not in the sub-sequence from the target_llc to src_llc in the affinity node sequence. That's why we skip them here. 
 
> > +		if (cpumask_test_cpu(dst_cpu, cpumask_of_node(node))) {
> 
> For the node that contains dst_cpu..
> 
> > +			nu = 0;
> > +			nc = 0;
> > +			for_each_llc_node_span(node, span) {
> 
> Iterate the LLCs in this node..
> 
> > +				get_span_stats(span, &u, &c);
> 
> Now I'm confused again, @span is the span of the llc, but
> get_span_stats() is a wrapper around get_llc_stats(), and since span is
> just a single llc, why use this rather than get_llc_stats() directly?
>
Oh, it's simpler to use get_llc_stats here. Will change it.
 
> > +				nu += u;
> > +				nc += c;
> > +				if (cpumask_test_cpu(dst_cpu, span)) {
> 
> If llc includes dst_cpu
> 
> (indent is getting a little out of hand here)
>
OK, the nesting got too deep here. I'll refactor these code.

> > +					if (fits_llc_capacity(u + tsk_util, c))
> > +						return mig_llc;
> > +
> > +					/*
> > +					 * The destination is over the margin,
> > +					 * but so may be the source. Refusing
> > +					 * then leaves the peak where it is:
> > +					 * a LLC at seven tasks stays at seven
> > +					 * while a neighbour in the same node
> > +					 * sits at four, because taking one
> > +					 * more would put that neighbour over
> > +					 * the margin as well.
> > +					 *
> > +					 * Let the task through when the move
> > +					 * still lowers the peak, guarded the
> > +					 * same way as the aggregation path:
> > +					 * the source must be noticeably
> > +					 * heavier and carry at least two more
> > +					 * tasks worth of utilization, so the
> > +					 * destination cannot end up the
> > +					 * heavier side and bounce it back.
> > +					 */
> > +					if (src_cap &&
> > +					    util_greater(src_util, u + tsk_util) &&
> > +					    src_util >= u + 2 * tsk_util)
> > +						return mig_llc;
> > +
> > +					return mig_forbid;
> 
> This is an unconditional return..

This unconditional return is intentional. Once the walk reaches the dst llc,
we have enough information to make the final decision about whether to
migrate or not. LLCs after the destination llc don't affect this decision.
> 
> > +				/*
> > +				 * A nearer LLC only justifies vetoing this
> > +				 * migration if the task would actually fit
> 
> But you just skipped the nodes between target and src, those are nearer,
> no?

Yes, they are nearer. But they don't contain the destination LLC, so they are
irrelevant to this migration.

> 
> > +				 * there, so account for its utilization the
> > +				 * same way the destination branch above does.
> > +				 * Without it a LLC already holding one task
> > +				 * per core still reads as having room and
> > +				 * vetoes every migration towards a farther,
> > +				 * genuinely idle LLC.
> > +				 */
> > +				} else if (fits_llc_capacity(acc_util + nu + tsk_util,
> 
> .. which renders this else superfluous, but that won't help with the
> indent because you still have the chained if :-(

Right, this else is unnecessary. It needs some refactoring here to make it readable.

> 
> > +						acc_cap + nc)
> > +						&& fits_llc_capacity(u + tsk_util, c)
> > +						&& !util_greater(u, dst_pre))
> 
> (logical operators go at the end of the previous line, your patch is
> inconsistent on this point, since that is what you do elsewhere)

OK, I will move the logical operators to the ends of the preceding line.

> 
> > +					return mig_forbid;
> > +			}
> > +		}
> > +
> > +		/* Don't migrate if this is a good place to live. */
> > +		for_each_llc_node_span(node, span) {
> > +			get_span_stats(span, &u, &c);
> 
> This is shared with the above loop, meaning you're now duplicating this
> work in case you fell through.

The destination node walk is intended to be terminal: it should find the llc
containing dst_cpu and return a decision.

I will make that explicit by returning mig_unrestricted if the destination llc is
unexpectedly not found, so that the generic llc walk is only used for
non-destination nodes. Thus, duplicate scan is avoided.
 
> 
> > +			if (cpumask_test_cpu(src_cpu, span)) {
> > +				if (fits_llc_capacity(u, c))
> > +					return mig_forbid;
> > +			} else {
> > +				if (fits_llc_capacity(u + tsk_util, c))
> > +					return mig_forbid;
> > +			}
> > +		}
> > +	}
> > +
> > +	return mig_unrestricted;
> > +}
> > +
> >  /*
> >   * Check if task p can migrate from source LLC to
> >   * destination LLC in terms of cache aware load balance.
> > --
> > 2.34.1
> >
> >




  reply	other threads:[~2026-09-02  5:08 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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-31  9:43     ` Jianyong Wu
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-31 11:50   ` Peter Zijlstra
2026-09-01  6:57     ` Jianyong Wu
2026-09-01  7:13       ` Peter Zijlstra
2026-09-01  7:37         ` Jianyong Wu
2026-09-01  8:48   ` Peter Zijlstra
2026-09-02  7:11     ` 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-31 13:12   ` Peter Zijlstra
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-31 13:16   ` Peter Zijlstra
2026-09-01  7:44     ` Jianyong Wu
2026-08-31 13:22   ` Peter Zijlstra
2026-09-01  8:05     ` 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-31 13:23   ` Peter Zijlstra
2026-09-01  8:14     ` Jianyong Wu
2026-08-31 13:24   ` Peter Zijlstra
2026-09-01  8:31     ` Jianyong Wu
2026-09-01 10:21       ` Peter Zijlstra
2026-09-01 13:02         ` Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 09/23] sched/cache: Account percpu sd task NUMA preference Jianyong Wu
2026-09-01  7:54   ` Peter Zijlstra
2026-09-01  8:41     ` 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-09-01  8:02   ` Peter Zijlstra
2026-09-01 11:55     ` Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 11/23] sched/cache: Introduce helpers for task migration decisions Jianyong Wu
2026-09-01  9:08   ` Peter Zijlstra
2026-09-02  5:08     ` Jianyong Wu [this message]
2026-09-01 11:32   ` Peter Zijlstra
2026-09-02  5:46     ` Jianyong Wu
2026-09-02 21:11   ` Tim Chen
2026-09-03  2:04     ` Jianyong Wu
2026-08-27 12:28 ` [RFC PATCH v2 12/23] sched/cache: Introduce rq affinity gain calculation Jianyong Wu
2026-09-01  9:58   ` Peter Zijlstra
2026-09-01 12:23     ` Jianyong Wu
2026-09-01 10:16   ` Peter Zijlstra
2026-09-01 12:34     ` 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-09-01 10:29   ` Peter Zijlstra
2026-09-01 13:25     ` 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-09-01 12:47   ` Peter Zijlstra
2026-09-02  6:43     ` 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-09-01 14:44   ` Peter Zijlstra
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=226d79fa93a84193aa2507113747d348@hygon.cn \
    --to=wujianyong@hygon.cn \
    --cc=akpm@linux-foundation.org \
    --cc=bsegall@google.com \
    --cc=david@kernel.org \
    --cc=dietmar.eggemann@arm.com \
    --cc=huangsj@hygon.cn \
    --cc=jianyong.wu@outlook.com \
    --cc=juri.lelli@redhat.com \
    --cc=justin.he@arm.com \
    --cc=kprateek.nayak@amd.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mgorman@suse.de \
    --cc=mingo@redhat.com \
    --cc=pauld@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=sshegde@linux.ibm.com \
    --cc=tim.c.chen@linux.intel.com \
    --cc=vincent.guittot@linaro.org \
    --cc=vschneid@redhat.com \
    --cc=wangfengyu@hygon.cn \
    --cc=yingzhiwei@hygon.cn \
    --cc=yu.c.chen@intel.com \
    --cc=zhongyuan@hygon.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox