mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: LKML <linux-kernel@vger.kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>,
	Gabriele Monaco <gmonaco@redhat.com>,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	Michael Jeanson <mjeanson@efficios.com>,
	Jens Axboe <axboe@kernel.dk>,
	"Paul E. McKenney" <paulmck@kernel.org>,
	"Gautham R. Shenoy" <gautham.shenoy@amd.com>,
	Florian Weimer <fweimer@redhat.com>,
	Tim Chen <tim.c.chen@intel.com>,
	Yury Norov <yury.norov@gmail.com>,
	Shrikanth Hegde <sshegde@linux.ibm.com>
Subject: [patch V3 15/20] sched/mmcid: Introduce per task/CPU ownership infrastrcuture
Date: Wed, 29 Oct 2025 14:09:22 +0100 (CET)	[thread overview]
Message-ID: <20251029124516.221091724@linutronix.de> (raw)
In-Reply-To: <20251029123717.886619142@linutronix.de>

The MM CID management has two fundamental requirements:

  1) It has to guarantee that at no given point in time the same CID is
     used by concurrent tasks in userspace.

  2) The CID space must not exceed the number of possible CPUs in a
     system. While most allocators (glibc, tcmalloc, jemalloc) do not
     care about that, there seems to be at least some LTTng library
     depending on it.

The CID space compaction itself is not a functional correctness
requirement, it is only a useful optimization mechanism to reduce the
memory foot print in unused user space pools.

The optimal CID space is:

    min(nr_tasks, nr_cpus_allowed);

Where @nr_tasks is the number of actual user space threads associated to
the mm and @nr_cpus_allowed is the superset of all task affinities. It is
growth only as it would be insane to take a racy snapshot of all task
affinities when the affinity of one task changes just do redo it 2
milliseconds later when the next task changes it's affinity.

That means that as long as the number of tasks is lower or equal than the
number of CPUs allowed, each task owns a CID. If the number of tasks
exceeds the number of CPUs allowed it switches to per CPU mode, where the
CPUs own the CIDs and the tasks borrow them as long as they are scheduled
in.

For transition periods CIDs can go beyond the optimal space as long as they
don't go beyond the number of possible CPUs.

The current upstream implementation tries to keep the CID with the task
even in overcommit situations, which complicates task migration. It also
has to do the CID space consolidation work from a task work in the exit to
user space path. As that work is assigned to a random task related to a MM
this can inflict unwanted exit latencies.

This can be done differently by implementing a strict CID ownership
mechanism. Either the CIDs are owned by the tasks or by the CPUs. The
latter provides less locality when tasks are heavily migrating, but there
is no justification to optimize for overcommit scenarios and thereby
penalazing everyone else.

Provide the basic infrastructure to implement this:

  - Change the UNSET marker to BIT(31) from ~0U
  - Add the ONCPU marker as BIT(30)
  - Add the TRANSIT marker as BIT(29)

That allows to check for ownership trivialy and provides a simple check for
UNSET as well. The TRANSIT marker is required to prevent CID space
exhaustion when switching from per CPU to per task mode.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Add the TRANSIT(ion) bit
---
 include/linux/rseq_types.h |    4 ++-
 include/linux/sched.h      |    6 ++--
 kernel/sched/core.c        |   10 +++++++
 kernel/sched/sched.h       |   59 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 75 insertions(+), 4 deletions(-)

--- a/include/linux/rseq_types.h
+++ b/include/linux/rseq_types.h
@@ -92,7 +92,9 @@ struct rseq_data { };
 
 #ifdef CONFIG_SCHED_MM_CID
 
-#define MM_CID_UNSET	(~0U)
+#define MM_CID_UNSET	BIT(31)
+#define MM_CID_ONCPU	BIT(30)
+#define MM_CID_TRANSIT	BIT(29)
 
 /**
  * struct sched_mm_cid - Storage for per task MM CID data
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2299,16 +2299,16 @@ void sched_mm_cid_before_execve(struct t
 void sched_mm_cid_after_execve(struct task_struct *t);
 void sched_mm_cid_fork(struct task_struct *t);
 void sched_mm_cid_exit(struct task_struct *t);
-static inline int task_mm_cid(struct task_struct *t)
+static __always_inline int task_mm_cid(struct task_struct *t)
 {
-	return t->mm_cid.cid;
+	return t->mm_cid.cid & ~(MM_CID_ONCPU | MM_CID_TRANSIT);
 }
 #else
 static inline void sched_mm_cid_before_execve(struct task_struct *t) { }
 static inline void sched_mm_cid_after_execve(struct task_struct *t) { }
 static inline void sched_mm_cid_fork(struct task_struct *t) { }
 static inline void sched_mm_cid_exit(struct task_struct *t) { }
-static inline int task_mm_cid(struct task_struct *t)
+static __always_inline int task_mm_cid(struct task_struct *t)
 {
 	/*
 	 * Use the processor id as a fall-back when the mm cid feature is
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -10384,6 +10384,16 @@ void call_trace_sched_update_nr_running(
  *
  * The mm::mm_cid:pcpu per CPU storage is protected by the CPUs runqueue
  * lock.
+ *
+ * CID ownership:
+ *
+ * A CID is either owned by a task (stored in task_struct::mm_cid.cid) or
+ * by a CPU (stored in mm::mm_cid.pcpu::cid). CIDs owned by CPUs have the
+ * MM_CID_ONCPU bit set. During transitioning from CPU to task ownership
+ * mode, MM_CID_TRANSIT is set on the per task CIDs. When this bit is set
+ * the task needs to drop the CID into the pool when scheduling out.  Both
+ * bits (ONCPU and TRANSIT) are filtered out by task_cid() when the CID is
+ * actualy handed over to user space in the RSEQ memory.
  */
 
 /*
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -3539,6 +3539,65 @@ extern void sched_dynamic_update(int mod
 extern const char *preempt_modes[];
 
 #ifdef CONFIG_SCHED_MM_CID
+
+static __always_inline bool cid_on_cpu(unsigned int cid)
+{
+	return cid & MM_CID_ONCPU;
+}
+
+static __always_inline bool cid_in_transit(unsigned int cid)
+{
+	return cid & MM_CID_TRANSIT;
+}
+
+static __always_inline unsigned int cpu_cid_to_cid(unsigned int cid)
+{
+	return cid & ~MM_CID_ONCPU;
+}
+
+static __always_inline unsigned int cid_to_cpu_cid(unsigned int cid)
+{
+	return cid | MM_CID_ONCPU;
+}
+
+static __always_inline unsigned int cid_to_transit_cid(unsigned int cid)
+{
+	return cid | MM_CID_TRANSIT;
+}
+
+static __always_inline unsigned int cid_from_transit_cid(unsigned int cid)
+{
+	return cid & ~MM_CID_TRANSIT;
+}
+
+static __always_inline bool cid_on_task(unsigned int cid)
+{
+	/* True if none of the MM_CID_ONCPU, MM_CID_TRANSIT, MM_CID_UNSET bits is set */
+	return cid < MM_CID_TRANSIT;
+}
+
+static __always_inline void mm_drop_cid(struct mm_struct *mm, unsigned int cid)
+{
+	clear_bit(cid, mm_cidmask(mm));
+}
+
+static __always_inline void mm_unset_cid_on_task(struct task_struct *t)
+{
+	unsigned int cid = t->mm_cid.cid;
+
+	t->mm_cid.cid = MM_CID_UNSET;
+	if (cid_on_task(cid))
+		mm_drop_cid(t->mm, cid);
+}
+
+static __always_inline void mm_drop_cid_on_cpu(struct mm_struct *mm, struct mm_cid_pcpu *pcp)
+{
+	/* Clear the ONCPU bit, but do not set UNSET in the per CPU storage */
+	pcp->cid = cpu_cid_to_cid(pcp->cid);
+	mm_drop_cid(mm, pcp->cid);
+}
+
+/* Active implementation */
 static inline void init_sched_mm_cid(struct task_struct *t)
 {
 	struct mm_struct *mm = t->mm;


  parent reply	other threads:[~2025-10-29 13:09 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-29 13:08 [patch V3 00/20] sched: Rewrite MM CID management Thomas Gleixner
2025-10-29 13:08 ` [patch V3 01/20] sched/mmcid: Revert the complex " Thomas Gleixner
2025-10-29 13:08 ` [patch V3 02/20] sched/mmcid: Use proper data structures Thomas Gleixner
2025-10-29 15:31   ` Mathieu Desnoyers
2025-10-29 13:08 ` [patch V3 03/20] sched/mmcid: Cacheline align MM CID storage Thomas Gleixner
2025-10-29 15:39   ` Mathieu Desnoyers
2025-10-29 21:09     ` Thomas Gleixner
2025-10-30 14:15       ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 04/20] sched: Fixup whitespace damage Thomas Gleixner
2025-10-29 15:42   ` Mathieu Desnoyers
2025-10-29 21:11     ` Thomas Gleixner
2025-10-29 13:09 ` [patch V3 05/20] sched/mmcid: Move scheduler code out of global header Thomas Gleixner
2025-10-29 15:43   ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 06/20] sched/mmcid: Prevent pointless work in mm_update_cpus_allowed() Thomas Gleixner
2025-10-29 15:45   ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 07/20] cpumask: Introduce cpumask_weighted_or() Thomas Gleixner
2025-10-29 15:49   ` Mathieu Desnoyers
2025-11-03  9:15   ` Shrikanth Hegde
2025-11-03 13:29     ` Thomas Gleixner
2025-11-10 16:11       ` Peter Zijlstra
2025-11-10 16:42         ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 08/20] sched/mmcid: Use cpumask_weighted_or() Thomas Gleixner
2025-10-29 15:51   ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 09/20] cpumask: Cache num_possible_cpus() Thomas Gleixner
2025-10-29 15:54   ` Mathieu Desnoyers
2025-10-29 21:11     ` Thomas Gleixner
2025-11-01 22:59       ` Thomas Gleixner
2025-11-03 10:06   ` Shrikanth Hegde
2025-11-03 13:28     ` Thomas Gleixner
2025-10-29 13:09 ` [patch V3 10/20] sched/mmcid: Convert mm CID mask to a bitmap Thomas Gleixner
2025-10-30 13:59   ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 11/20] signal: Move MMCID exit out of sighand lock Thomas Gleixner
2025-10-29 13:09 ` [patch V3 12/20] sched/mmcid: Move initialization out of line Thomas Gleixner
2025-10-30 14:02   ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 13/20] sched/mmcid: Provide precomputed maximal value Thomas Gleixner
2025-10-30 14:23   ` Mathieu Desnoyers
2025-10-31 15:06     ` Thomas Gleixner
2025-10-31 15:14       ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 14/20] sched/mmcid: Serialize sched_mm_cid_fork()/exit() with a mutex Thomas Gleixner
2025-10-30 14:25   ` Mathieu Desnoyers
2025-10-29 13:09 ` Thomas Gleixner [this message]
2025-10-30 14:45   ` [patch V3 15/20] sched/mmcid: Introduce per task/CPU ownership infrastrcuture Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 16/20] sched/mmcid: Provide new scheduler CID mechanism Thomas Gleixner
2025-10-30 15:09   ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 17/20] sched/mmcid: Provide CID ownership mode fixup functions Thomas Gleixner
2025-10-30 15:51   ` Mathieu Desnoyers
2025-10-31 16:54     ` Thomas Gleixner
2025-10-31 19:15       ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 18/20] irqwork: Move data struct to a types header Thomas Gleixner
2025-10-30 15:52   ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 19/20] sched/mmcid: Implement deferred mode change Thomas Gleixner
2025-10-30 15:56   ` Mathieu Desnoyers
2025-10-29 13:09 ` [patch V3 20/20] sched/mmcid: Switch over to the new mechanism Thomas Gleixner
2025-10-30 16:07   ` Mathieu Desnoyers
2025-10-31 16:57     ` Thomas Gleixner
2025-10-31 19:17       ` Mathieu Desnoyers
2025-11-24 12:10   ` Mark Brown
2025-11-24 12:27     ` Florian Weimer
2025-11-24 13:28       ` Mark Brown
2025-10-30  5:00 ` [patch V3 00/20] sched: Rewrite MM CID management Shrikanth Hegde
2025-10-30  6:40   ` Shrikanth Hegde
2025-10-31 19:36     ` Thomas Gleixner
2025-11-01  7:56       ` Shrikanth Hegde
2025-11-01 12:27         ` Thomas Gleixner
2025-11-10 17:09 ` Gabriele Monaco

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=20251029124516.221091724@linutronix.de \
    --to=tglx@linutronix.de \
    --cc=axboe@kernel.dk \
    --cc=fweimer@redhat.com \
    --cc=gautham.shenoy@amd.com \
    --cc=gmonaco@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mjeanson@efficios.com \
    --cc=paulmck@kernel.org \
    --cc=peterz@infradead.org \
    --cc=sshegde@linux.ibm.com \
    --cc=tim.c.chen@intel.com \
    --cc=yury.norov@gmail.com \
    /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

Powered by JetHome