[LTP] [PATCH v4 1/2] lib: Add tst_ncpus_global()
Nirmoy Das
nirmoyd@nvidia.com
Mon Oct 5 15:18:06 CEST 2026
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
More information about the ltp
mailing list