mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Breno Leitao <leitao@debian.org>
To: Tejun Heo <tj@kernel.org>
Cc: Lai Jiangshan <jiangshanlai@gmail.com>,
	 Marco Crivellari <marco.crivellari@suse.com>,
	linux-kernel@vger.kernel.org, kernel-team@meta.com
Subject: Re: [PATCH RFC 0/3] workqueue: Take the pwq backend from the attrs
Date: Tue, 22 Sep 2026 03:34:48 -0700	[thread overview]
Message-ID: <arJO4eEGNzltAOk-@gmail.com> (raw)
In-Reply-To: <8a1437751a6da2c166284b1ca562fb0a@kernel.org>

Hello Tejun,

On Fri, Sep 18, 2026 at 04:13:36PM -1000, Tejun Heo wrote:
> On Fri, Sep 18, 2026 at 07:25:32AM -0700, Breno Leitao wrote:
> >  * Keep wq->max_active and wq->percpu_max_active both current. The two
> >    backends meter work differently, and a pwq must not end up metered
> >    against a limit nobody set. (this is the semi-conflictual with my previous
> >    commit 27db9dd7f84f3a ("workqueue: Give percpu workqueues their own
> >    max_active")
> 
> Both should stay current but I don't think they should be the same number.

Ok, that means we are going to keep both as commit 27db9dd7f84f3a, and
keep both values set at a given time, and the values will be different.

> max_active means different things in the two domains, per-CPU on one side and
> across the whole workqueue on the other, so let's keep the two sets of values
> separate and link them through scaling.

Right, I will create a function that maps/scale one to another. Maybe
the following?

	 static int percpu_to_unbound_max_active(int percpu_max_active)
	 {
		 s64 max_active = (s64)percpu_max_active * num_possible_cpus();

		 return min_t(s64, max_active, WQ_MAX_ACTIVE);
	 }

	 static int unbound_to_percpu_max_active(int max_active)
	 {
		 return DIV_ROUND_UP(max_active, num_possible_cpus());
	 }

> On creation, the argument sets the
> values for the domain the workqueue starts in and the other domain is derived
> from it. Afterwards, each domain has its own interface, kernel and sysfs, and
> adjusting one updates the other accordingly. That way a switch always lands
> on a sensible limit without anyone having to think about it.

Sure, and probably call them from wq_adjust_max_active(), so,
independent of the one that is being set (percpu or unbound), it will
change the other as well according to the function above.

> >  * Create a ->concurrency_managed field in the wq attributes, used to
> >    decide whether to do concurrency management or not.
> >
> >  * Move WQ_PERCPU onto an UNBOUND workqueue with WQ_AFFN_CPU affinity and
> >    the newly created ->concurrency_managed. WQ_PERCPU is then only the
> >    promise that the workqueue stays on that backend.
> 
> I'd rather not build percpu on top of CPU scope. Unbound with strict CPU
> scope and percpu are different things. The pools, the metering and how the
> unbound cpumask applies all differ, and both should keep existing. So, how
> about making PERCPU its own scope? 

Ack! I will proceed with a newly created WQ_AFFN_PERCPU scope then.

> Whether concurrency management is then
> expressed as a flag or an attribute doesn't matter much as long as it can be
> turned on and off. WQ_PERCPU would mean that the workqueue can't leave the
> PERCPU scope while CM can still be toggled.

Oh, interesting, so, we are going to have CM toggable even for
WQ_PERCPU and also for WQ_UNBOUND+WQ_AFFN_PERCPU, is this right?

Once we have it, what will be the difference between
WQ_UNBOUND+WQ_AFFN_PERCPU+CM from WQ_PERCPU? They look exactly the same
from a user perspective, no?

> BH can be a scope value too for consistency. It's only selectable on creation
> and can't be switched into or out of, but having it in the same enum keeps
> things uniform.

Do you mean something like WQ_AFFN_BH or an entry in workqueue_attrs,
similar to affn_strict and the recently propsoed concurrency_managed?

I understand that scope means 'enum wq_affn_scope affn_scope', so, you
want a WQ_AFFN_BH, right?

> With scope carrying the backend, nice can apply verbatim on unbound and snap
> to normal or highpri when the workqueue is on percpu, picked from the current
> value. No need to restrict what can be written.

So, it means that we are going to expose the wq_sysfs_unbound_attrs to
WQ_PERCPU as well, and we are going to map nice to high priority queues
and normal queues. For instance:

  - echo -5 > nice succeeds and stores -5, whatever scope the wq is in
  - For WQ_PERCPU it runs on the highpri pool (nice -20 in practice)
  - echo 0 > nice, will turn the WQ_PERCPU workqueue into the normal
    pool.

Am I getting the idea right here?

> > Not done: the switching itself. concurrency_managed is fixed when the
> > workqueue is created and is not exported through sysfs, so nothing takes a
> > workqueue onto the backend or off it yet.
> 
> For PREFER_PERCPU type workqueues, which benefit from cmwq but don't depend
> on it for correctness, there's no reason to block switching in either
> direction. Having them follow the unbound cpumask when picking the queueing
> CPU even while on percpu, the way the last patch keys that on WQ_PERCPU
> rather than on the backend, makes sense for them.

let me back up a bit and talk about the scopes. The final state of the
scopes will be:

enum wq_affn_scope {
        WQ_AFFN_DFL,    
        WQ_AFFN_CPU,     
        WQ_AFFN_SMT,      
        WQ_AFFN_CACHE,     
        WQ_AFFN_CACHE_SHARD,
        WQ_AFFN_NUMA,       
        WQ_AFFN_SYSTEM,     
+       WQ_AFFN_PERCPU,                 /* one pod per CPU + CM + affinity */
+       WQ_AFFN_PEREFER_PERCPU,         /* one pod per CPU + CM + relaxed affinity */
+       WQ_AFFN_BH,			/* scope for WQ_BH */
}

Is this the final state you are envisioning?

Thanks for the excellent review and guidance,
--breno

  reply	other threads:[~2026-09-22 10:34 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-18 14:25 Breno Leitao
2026-09-18 14:25 ` [PATCH RFC 1/3] workqueue: Maintain both max_active limits Breno Leitao
2026-09-18 14:25 ` [PATCH RFC 2/3] workqueue: Add a concurrency_managed workqueue attribute Breno Leitao
2026-09-18 15:25   ` Marco Crivellari
2026-09-18 14:25 ` [PATCH RFC 3/3] workqueue: Back every workqueue with the unbound machinery Breno Leitao
2026-09-18 15:23 ` [PATCH RFC 0/3] workqueue: Take the pwq backend from the attrs Marco Crivellari
2026-09-19  2:13 ` Tejun Heo
2026-09-22 10:34   ` Breno Leitao [this message]
2026-09-22 21:54     ` Tejun Heo

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=arJO4eEGNzltAOk-@gmail.com \
    --to=leitao@debian.org \
    --cc=jiangshanlai@gmail.com \
    --cc=kernel-team@meta.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marco.crivellari@suse.com \
    --cc=tj@kernel.org \
    /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

all inboxes | Powered by JetHome®