* [LTP] [PATCH v4 1/2] lib: Add tst_ncpus_global()
@ 2026-10-05 13:18 Nirmoy Das via ltp
2026-10-05 13:18 ` [LTP] [PATCH v4 2/2] getrusage03: account for percpu RSS counter batching Nirmoy Das via ltp
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Nirmoy Das via ltp @ 2026-10-05 13:18 UTC (permalink / raw)
To: ltp
Some CPU-count interfaces follow the calling thread's affinity, which makes
them unsuitable for calculating kernel thresholds that depend on all online
CPUs.
Add tst_ncpus_global(), which counts CPUs in /proc/stat independently of
affinity. Cover it with a self-test that checks the result before and after
pinning to one allowed CPU.
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Nirmoy Das <nirmoyd@nvidia.com>
---
include/tst_cpu.h | 8 +++
lib/newlib_tests/runtest.sh | 1 +
lib/newlib_tests/tst_ncpus_global.c | 86 +++++++++++++++++++++++++++++
lib/tst_cpu.c | 24 ++++++++
4 files changed, 119 insertions(+)
create mode 100644 lib/newlib_tests/tst_ncpus_global.c
diff --git a/include/tst_cpu.h b/include/tst_cpu.h
index dfb155c58..340d0f3c7 100644
--- a/include/tst_cpu.h
+++ b/include/tst_cpu.h
@@ -10,6 +10,14 @@ long tst_ncpus_conf(void);
long tst_ncpus_max(void);
long tst_ncpus_available(void);
+/**
+ * tst_ncpus_global() - Returns the global online CPU count.
+ *
+ * Return: The global online CPU count reported by /proc/stat, independent of
+ * the calling thread's affinity.
+ */
+long tst_ncpus_global(void);
+
/**
* tst_cpu_vendor() - Returns CPU vendor.
*
diff --git a/lib/newlib_tests/runtest.sh b/lib/newlib_tests/runtest.sh
index 71808ef8b..f53a4fbfc 100755
--- a/lib/newlib_tests/runtest.sh
+++ b/lib/newlib_tests/runtest.sh
@@ -27,6 +27,7 @@ tst_expiration_timer
tst_filesystems01
tst_fuzzy_sync0[1-3]
tst_needs_cmds0[1-36-8]
+tst_ncpus_global
tst_res_hexd
tst_safe_sscanf
tst_strstatus}"
diff --git a/lib/newlib_tests/tst_ncpus_global.c b/lib/newlib_tests/tst_ncpus_global.c
new file mode 100644
index 000000000..d27c7c7d4
--- /dev/null
+++ b/lib/newlib_tests/tst_ncpus_global.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 NVIDIA Corporation
+ */
+
+#define _GNU_SOURCE
+
+#include "tst_test.h"
+#include "tst_cpu.h"
+#include "tst_sysfs_assert.h"
+#include "lapi/cpuset.h"
+
+static cpu_set_t *saved_mask, *single_mask;
+static size_t mask_size;
+static int saved_mask_valid;
+
+static void cleanup(void)
+{
+ if (saved_mask_valid && sched_setaffinity(0, mask_size, saved_mask))
+ tst_res(TWARN | TERRNO, "sched_setaffinity() restore failed");
+
+ if (saved_mask)
+ CPU_FREE(saved_mask);
+
+ if (single_mask)
+ CPU_FREE(single_mask);
+}
+
+static void setup(void)
+{
+ long ncpus = tst_ncpus_max();
+ long cpu;
+
+ saved_mask = CPU_ALLOC(ncpus);
+ single_mask = CPU_ALLOC(ncpus);
+ if (!saved_mask || !single_mask)
+ tst_brk(TBROK | TERRNO, "CPU_ALLOC() failed");
+
+ mask_size = CPU_ALLOC_SIZE(ncpus);
+ if (sched_getaffinity(0, mask_size, saved_mask))
+ tst_brk(TBROK | TERRNO, "sched_getaffinity() failed");
+ saved_mask_valid = 1;
+
+ for (cpu = 0; cpu < ncpus; cpu++) {
+ if (CPU_ISSET_S(cpu, mask_size, saved_mask))
+ break;
+ }
+
+ if (cpu == ncpus)
+ tst_brk(TBROK, "Affinity mask contains no CPUs");
+
+ CPU_ZERO_S(mask_size, single_mask);
+ CPU_SET_S(cpu, mask_size, single_mask);
+}
+
+static void run(void)
+{
+ long before, after;
+ int expected;
+
+ if (TST_SYSFS_ASSERT_PARSE_LIST(&expected, NULL,
+ "/sys/devices/system/cpu/online"))
+ return;
+
+ if (!expected)
+ tst_brk(TBROK, "No online CPUs found in sysfs");
+
+ if (sched_setaffinity(0, mask_size, saved_mask))
+ tst_brk(TBROK | TERRNO, "sched_setaffinity() restore failed");
+
+ before = tst_ncpus_global();
+
+ if (sched_setaffinity(0, mask_size, single_mask))
+ tst_brk(TBROK | TERRNO, "sched_setaffinity() failed");
+
+ after = tst_ncpus_global();
+
+ TST_EXP_EQ_LI(before, expected);
+ TST_EXP_EQ_LI(after, expected);
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ .setup = setup,
+ .cleanup = cleanup,
+};
diff --git a/lib/tst_cpu.c b/lib/tst_cpu.c
index 776801291..241bd3347 100644
--- a/lib/tst_cpu.c
+++ b/lib/tst_cpu.c
@@ -24,6 +24,7 @@
#include "test.h"
#include "tso_safe_macros.h"
#include "tso_safe_file_ops.h"
+#include "tso_safe_stdio.h"
long tst_ncpus(void)
{
@@ -99,6 +100,29 @@ long tst_ncpus_available(void)
#endif
}
+long tst_ncpus_global(void)
+{
+ FILE *fp = SAFE_FOPEN(NULL, "/proc/stat", "r");
+ char line[BUFSIZ];
+ long count = 0;
+
+ while (fgets(line, sizeof(line), fp)) {
+ if (line[0] == 'c' && line[1] == 'p' && line[2] == 'u' &&
+ line[3] >= '0' && line[3] <= '9')
+ count++;
+ }
+
+ if (ferror(fp))
+ tst_brkm(TBROK | TERRNO, NULL, "fgets(/proc/stat)");
+
+ SAFE_FCLOSE(NULL, fp);
+
+ if (!count)
+ tst_brkm(TBROK, NULL, "No online CPUs found in /proc/stat");
+
+ return count;
+}
+
const char *tst_cpu_vendor(void)
{
static char cpu_vendor[16];
base-commit: dca9f0d272b2923256852fc37abd222b533d91e0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [LTP] [PATCH v4 2/2] getrusage03: account for percpu RSS counter batching
2026-10-05 13:18 [LTP] [PATCH v4 1/2] lib: Add tst_ncpus_global() Nirmoy Das via ltp
@ 2026-10-05 13:18 ` Nirmoy Das via ltp
2026-11-03 16:05 ` Cyril Hrubis
2026-10-05 18:01 ` [LTP] lib: Add tst_ncpus_global() linuxtestproject.agent
2026-11-03 15:53 ` [LTP] [PATCH v4 1/2] " Cyril Hrubis
2 siblings, 1 reply; 6+ messages in thread
From: Nirmoy Das via ltp @ 2026-10-05 13:18 UTC (permalink / raw)
To: ltp
After f1a7941243c1 ("mm: convert mm's rss stats into percpu_counter"),
the fixed 20 MiB tolerance can be too small on large systems. Pinning
limits pending RSS updates to one CPU, but that CPU can still hold one
batch outside the fast RSS read.
Pin the test to its current CPU and allow one batch of lower-side slack
for the 100, 300 and 400 MiB allocation checks. Keep the existing upper
and inheritance tolerances, and skip if one batch is at least 100 MiB.
Use tst_ncpus_global() because the kernel batch size is independent of task
affinity, while some libc CPU-count interfaces follow it.
On a 352-CPU system with 64 KiB pages, one batch is 44 MiB. Pinning alone
reported 270336 KiB for the 300 MiB check, outside the 20 MiB tolerance.
Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Co-developed-by: Jan Stancek <jstancek@redhat.com>
Signed-off-by: Jan Stancek <jstancek@redhat.com>
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Nirmoy Das <nirmoyd@nvidia.com>
---
.../kernel/syscalls/getrusage/getrusage03.c | 87 +++++++++++++++----
1 file changed, 71 insertions(+), 16 deletions(-)
diff --git a/testcases/kernel/syscalls/getrusage/getrusage03.c b/testcases/kernel/syscalls/getrusage/getrusage03.c
index a2cdd6158..52540a919 100644
--- a/testcases/kernel/syscalls/getrusage/getrusage03.c
+++ b/testcases/kernel/syscalls/getrusage/getrusage03.c
@@ -13,22 +13,88 @@
* this program.
*/
-#include <stdlib.h>
+#define _GNU_SOURCE
#include <stdio.h>
+#include <stdlib.h>
#include "tst_test.h"
+#include "lapi/cpuset.h"
+#include "lapi/sched.h"
#include "getrusage03.h"
#define TESTBIN "getrusage03_child"
static struct rusage ru;
static long maxrss_init;
+static long lower_allowance;
static const char *const resource[] = {
TESTBIN,
NULL,
};
+/*
+ * Pin the test to the CPU it runs on. Every forked or exec'd child inherits
+ * the affinity, so only that CPU can hold RSS counter updates outside the
+ * fast percpu_counter read.
+ */
+static void pin_to_current_cpu(void)
+{
+ unsigned int cpu;
+ cpu_set_t *set;
+ size_t size;
+
+ if (getcpu(&cpu, NULL))
+ tst_brk(TBROK | TERRNO, "getcpu() failed");
+
+ set = CPU_ALLOC(cpu + 1);
+ if (!set)
+ tst_brk(TBROK | TERRNO, "CPU_ALLOC() failed");
+
+ size = CPU_ALLOC_SIZE(cpu + 1);
+ CPU_ZERO_S(size, set);
+ CPU_SET_S(cpu, size, set);
+ if (sched_setaffinity(0, size, set))
+ tst_brk(TBROK | TERRNO, "sched_setaffinity() failed");
+
+ CPU_FREE(set);
+ tst_res(TINFO, "Pinned to CPU %u", cpu);
+}
+
+/*
+ * The pinned CPU can still hold up to one percpu_counter batch,
+ * max(32, 2 * online CPUs) pages, outside the fast RSS read. The kernel uses
+ * the global online CPU count regardless of task affinity, while musl's
+ * sysconf(_SC_NPROCESSORS_ONLN) follows the task affinity mask.
+ */
+static void setup(void)
+{
+ long online_cpus = tst_ncpus_global();
+ long batch = MAX(32L, online_cpus * 2);
+ long page_size = SAFE_SYSCONF(_SC_PAGESIZE);
+ long batch_kib = batch * page_size / 1024;
+
+ lower_allowance = MAX(20 * 1024L, batch_kib);
+ if (lower_allowance >= 102400L)
+ tst_brk(TCONF, "Per-CPU RSS allowance is too large: %li KiB",
+ lower_allowance);
+
+ tst_res(TINFO, "%li online CPUs, lower RSS allowance %li KiB",
+ online_cpus, lower_allowance);
+
+ pin_to_current_cpu();
+}
+
+static void check_maxrss(long actual, long expected, const char *name,
+ const char *size)
+{
+ if (actual >= expected - lower_allowance &&
+ actual <= expected + DELTA_MAX)
+ tst_res(TPASS, "%s ~= %s", name, size);
+ else
+ tst_res(TFAIL, "%s = %li, expected %li", name, actual, expected);
+}
+
static void inherit_fork1(void)
{
SAFE_GETRUSAGE(RUSAGE_SELF, &ru);
@@ -51,11 +117,7 @@ static void inherit_fork2(void)
{
SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
- if (is_in_delta(ru.ru_maxrss - 102400))
- tst_res(TPASS, "initial.children ~= 100MB");
- else
- tst_res(TFAIL, "initial.children = %li, expected %i",
- ru.ru_maxrss, 102400);
+ check_maxrss(ru.ru_maxrss, 102400, "initial.children", "100MB");
if (!SAFE_FORK()) {
SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
@@ -78,11 +140,7 @@ static void grandchild_maxrss(void)
tst_reap_children();
SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
- if (is_in_delta(ru.ru_maxrss - 307200))
- tst_res(TPASS, "child.children ~= 300MB");
- else
- tst_res(TFAIL, "child.children = %li, expected %i",
- ru.ru_maxrss, 307200);
+ check_maxrss(ru.ru_maxrss, 307200, "child.children", "300MB");
}
static void zombie(void)
@@ -106,11 +164,7 @@ static void zombie(void)
tst_reap_children();
SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
- if (is_in_delta(ru.ru_maxrss - 409600))
- tst_res(TPASS, "post_wait.children ~= 400MB");
- else
- tst_res(TFAIL, "post_wait.children = %li, expected %i",
- ru.ru_maxrss, 409600);
+ check_maxrss(ru.ru_maxrss, 409600, "post_wait.children", "400MB");
}
static void sig_ign(void)
@@ -174,6 +228,7 @@ static void run(unsigned int i)
static struct tst_test test = {
.forks_child = 1,
.child_needs_reinit = 1,
+ .setup = setup,
.resource_files = resource,
.min_mem_avail = 512,
.tags = (const struct tst_tag[]) {
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [LTP] lib: Add tst_ncpus_global()
2026-10-05 13:18 [LTP] [PATCH v4 1/2] lib: Add tst_ncpus_global() Nirmoy Das via ltp
2026-10-05 13:18 ` [LTP] [PATCH v4 2/2] getrusage03: account for percpu RSS counter batching Nirmoy Das via ltp
@ 2026-10-05 18:01 ` linuxtestproject.agent
2026-11-03 15:53 ` [LTP] [PATCH v4 1/2] " Cyril Hrubis
2 siblings, 0 replies; 6+ messages in thread
From: linuxtestproject.agent @ 2026-10-05 18:01 UTC (permalink / raw)
To: Nirmoy Das; +Cc: ltp
Hi Nirmoy,
On Oct 5, 2026, Nirmoy Das wrote:
> lib: Add tst_ncpus_global()
--- [PATCH 1/2] ---
> diff --git a/lib/newlib_tests/tst_ncpus_global.c b/lib/newlib_tests/tst_ncpus_global.c
> new file mode 100644
Low severity: Add tst_ncpus_global to lib/newlib_tests/.gitignore.
Building the new self-test leaves its executable untracked; git status
reports "?? lib/newlib_tests/tst_ncpus_global".
Verdict - Needs revision
Runtime review limitation: getrusage03 exited with TCONF because this
environment lacks CAP_IPC_LOCK, so its allocation checks were not exercised.
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [LTP] [PATCH v4 1/2] lib: Add tst_ncpus_global()
2026-10-05 13:18 [LTP] [PATCH v4 1/2] lib: Add tst_ncpus_global() Nirmoy Das via ltp
2026-10-05 13:18 ` [LTP] [PATCH v4 2/2] getrusage03: account for percpu RSS counter batching Nirmoy Das via ltp
2026-10-05 18:01 ` [LTP] lib: Add tst_ncpus_global() linuxtestproject.agent
@ 2026-11-03 15:53 ` Cyril Hrubis
2 siblings, 0 replies; 6+ messages in thread
From: Cyril Hrubis @ 2026-11-03 15:53 UTC (permalink / raw)
To: Nirmoy Das; +Cc: ltp
Hi!
> diff --git a/lib/newlib_tests/runtest.sh b/lib/newlib_tests/runtest.sh
I've removed the test from the commit, since rather than the newly added
function it checks that kernel virtual filesystems are consistent. And
we have the exact same test in sys_cpu_topology01.c.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [LTP] [PATCH v4 2/2] getrusage03: account for percpu RSS counter batching
2026-10-05 13:18 ` [LTP] [PATCH v4 2/2] getrusage03: account for percpu RSS counter batching Nirmoy Das via ltp
@ 2026-11-03 16:05 ` Cyril Hrubis
2026-11-03 16:11 ` Nirmoy Das via ltp
0 siblings, 1 reply; 6+ messages in thread
From: Cyril Hrubis @ 2026-11-03 16:05 UTC (permalink / raw)
To: Nirmoy Das; +Cc: ltp
Hi!
Pushed with minor adjustenment to the comment, thanks.
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [LTP] [PATCH v4 2/2] getrusage03: account for percpu RSS counter batching
2026-11-03 16:05 ` Cyril Hrubis
@ 2026-11-03 16:11 ` Nirmoy Das via ltp
0 siblings, 0 replies; 6+ messages in thread
From: Nirmoy Das via ltp @ 2026-11-03 16:11 UTC (permalink / raw)
To: Cyril Hrubis; +Cc: ltp
Thanks, Cyril!
On 03.11.26 17:05, Cyril Hrubis wrote:
> Hi!
> Pushed with minor adjustenment to the comment, thanks.
>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-03 16:12 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-05 13:18 [LTP] [PATCH v4 1/2] lib: Add tst_ncpus_global() Nirmoy Das via ltp
2026-10-05 13:18 ` [LTP] [PATCH v4 2/2] getrusage03: account for percpu RSS counter batching Nirmoy Das via ltp
2026-11-03 16:05 ` Cyril Hrubis
2026-11-03 16:11 ` Nirmoy Das via ltp
2026-10-05 18:01 ` [LTP] lib: Add tst_ncpus_global() linuxtestproject.agent
2026-11-03 15:53 ` [LTP] [PATCH v4 1/2] " Cyril Hrubis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox