[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