mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC PATCH] x86,resctrl: Read event counters with an IPI when the read cannot block
@ 2026-10-20 15:13 Shakeel Butt
  0 siblings, 0 replies; only message in thread
From: Shakeel Butt @ 2026-10-20 15:13 UTC (permalink / raw)
  To: Reinette Chatre, Tony Luck
  Cc: Dave Martin, James Morse, Babu Moger, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, Peter Newman,
	Meta kernel team, x86, linux-kernel

In the Meta fleet, readers of the resctrl mon_data files often sleep
while holding rdtgroup_mutex. Over several hours, a lock profiler on
several thousand hosts (almost all AMD) caught:

  - 96,368 reads that held rdtgroup_mutex and cpu_hotplug_lock for
    17 ms on average and up to several seconds, mostly sleeping.
  - Three different userspace applications [1, 2, 3] doing these reads.
  - Other readers and the MBM overflow worker waiting for the mutex.

These long stalls put gaps in the monitoring data for these
applications.

The read has to run on a CPU in the L3 domain. mon_event_read() uses
smp_call_on_cpu() for that. It queues work on that CPU and sleeps until
a kworker runs it. When that CPU is busy, this takes a long time, and
the mutex stays held all along.

Commit 09909e098113 ("x86/resctrl: Queue mon_event_read() instead of
sending an IPI") did this for MPAM, whose reads may sleep. On x86 a
read is just one WRMSR and one RDMSR and it don't need to sleep.

Add CONFIG_RESCTRL_MON_READ_IRQSAFE, which x86 selects. With it, read
the counter with interrupts off: on the current CPU if it is a
housekeeping (not nohz_full) CPU in the domain, otherwise with an IPI
to one. If every CPU in the domain is nohz_full, keep the existing
smp_call_function_any() fallback. MPAM and other architectures keep
the old path. Peter Newman posted a similar change in 2024 [4].

Results on a 316-CPU AMD EPYC with busy target CPUs, and readers that
copy the fleet agents, per 60 s run:

                                       before    after
  hold time per read, average          350 us    4 us
  hold time per read, worst            3.4 ms    109 us
  time off CPU while holding           9 s       0
  one pass over 750 files, average     360 ms    7.4 ms

The cost: interrupts are off on the reading CPU for about 0.5 us per
counter, and up to 131 us for a root group read with 128 MON groups.
A reader that runs every 100 ms used up to 29% more system time,
because it now spins for the IPI. A kernel with lockdep and
DEBUG_ATOMIC_SLEEP gave no warnings while groups were created and
removed and CPUs went offline under the readers.

Link: https://github.com/facebookincubator/below [1]
Link: https://github.com/sched-ext/scx [2]
Link: https://github.com/facebookincubator/dynolog [3]
Link: https://lore.kernel.org/20241106154306.2721688-2-peternewman@google.com [4]
Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
---
 arch/x86/Kconfig         |  1 +
 fs/resctrl/Kconfig       |  8 ++++++++
 fs/resctrl/ctrlmondata.c | 12 ++++++++++--
 include/linux/resctrl.h  |  5 +++++
 4 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 15fd9ec5ecac..8512b0980f6a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -523,6 +523,7 @@ config X86_CPU_RESCTRL
 	select ARCH_HAS_CPU_RESCTRL
 	select RESCTRL_FS
 	select RESCTRL_FS_PSEUDO_LOCK
+	select RESCTRL_MON_READ_IRQSAFE
 	help
 	  Enable x86 CPU resource control support.
 
diff --git a/fs/resctrl/Kconfig b/fs/resctrl/Kconfig
index 21671301bd8a..912626bb18f6 100644
--- a/fs/resctrl/Kconfig
+++ b/fs/resctrl/Kconfig
@@ -37,3 +37,11 @@ config RESCTRL_RMID_DEPENDS_ON_CLOSID
 	  Enabled by the architecture when the RMID values depend on the CLOSID.
 	  This causes the CLOSID allocator to search for CLOSID with clean
 	  RMID.
+
+config RESCTRL_MON_READ_IRQSAFE
+	bool
+	depends on RESCTRL_FS
+	help
+	  Enabled by the architecture when reading a monitoring counter
+	  never sleeps. resctrl then reads it with interrupts off, on the
+	  local CPU or by IPI, instead of sleeping with rdtgroup_mutex held.
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index cafebdff70dc..c6fea953e962 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -601,10 +601,18 @@ void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
 	 * MPAM's resctrl_arch_rmid_read() is unable to read the
 	 * counters on some platforms if its called in IRQ context.
 	 */
-	if (tick_nohz_full_cpu(cpu))
+	if (tick_nohz_full_cpu(cpu)) {
 		smp_call_function_any(cpumask, mon_event_count, rr, 1);
-	else
+	} else if (IS_ENABLED(CONFIG_RESCTRL_MON_READ_IRQSAFE)) {
+		int this_cpu = raw_smp_processor_id();
+
+		if (cpumask_test_cpu(this_cpu, cpumask) &&
+		    !tick_nohz_full_cpu(this_cpu))
+			cpu = this_cpu;
+		smp_call_function_single(cpu, mon_event_count, rr, true);
+	} else {
 		smp_call_on_cpu(cpu, smp_mon_event_count, rr, false);
+	}
 
 out_ctx_free:
 	if (rr->arch_mon_ctx)
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 10dfdca7f4bf..2c6a19263d98 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -570,6 +570,9 @@ void resctrl_arch_pre_mount(void);
  * a CPU that belongs to domain @d. e.g. use smp_call_on_cpu() or
  * schedule_work_on(). This function can be called with interrupts masked,
  * e.g. using smp_call_function_any(), but may consistently return an error.
+ * If the architecture selects CONFIG_RESCTRL_MON_READ_IRQSAFE, event file
+ * reads that must run in domain @d are done with interrupts masked. The
+ * overflow and limbo handlers still call it from process context.
  *
  * Return:
  * 0 on success, or -EIO, -EINVAL etc on error.
@@ -679,6 +682,8 @@ void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *
  * Called on a CPU that belongs to domain @d when "mbm_event" mode is enabled.
  * Called from a non-migrateable process context via smp_call_on_cpu() unless all
  * CPUs are nohz_full, in which case it is called via IPI (smp_call_function_any()).
+ * If the architecture selects CONFIG_RESCTRL_MON_READ_IRQSAFE, event file
+ * reads are instead done with interrupts masked, directly or via IPI.
  *
  * Return:
  * 0 on success, or -EIO, -EINVAL etc on error.
-- 
2.53.0-Meta


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-20 15:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-20 15:13 [RFC PATCH] x86,resctrl: Read event counters with an IPI when the read cannot block Shakeel Butt

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®