[LTP] [PATCH v4 11/31] testcases: sysfs: Add sys_clockevents01
Cyril Hrubis
chrubis@suse.cz
Thu Aug 27 13:21:37 CEST 2026
A test for /sys/devices/system/clockevents/* files.
Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
include/tst_path_defs.h | 1 +
runtest/sysfs | 1 +
.../devices/system/clockevents/.gitignore | 1 +
.../sysfs/devices/system/clockevents/Makefile | 7 +
.../system/clockevents/sys_clockevents01.c | 138 ++++++++++++++++++
5 files changed, 148 insertions(+)
create mode 100644 testcases/kernel/sysfs/devices/system/clockevents/.gitignore
create mode 100644 testcases/kernel/sysfs/devices/system/clockevents/Makefile
create mode 100644 testcases/kernel/sysfs/devices/system/clockevents/sys_clockevents01.c
diff --git a/include/tst_path_defs.h b/include/tst_path_defs.h
index 6bc0d65e1..4c25c796a 100644
--- a/include/tst_path_defs.h
+++ b/include/tst_path_defs.h
@@ -93,6 +93,7 @@
#define MEMINFO_HPAGE_SIZE "Hugepagesize:"
/* SYSFS DEVICES */
+#define PATH_SYS_CLOCKEVENTS "/sys/devices/system/clockevents"
#define PATH_SYS_CLOCKSOURCE "/sys/devices/system/clocksource"
#define PATH_SYS_CPU "/sys/devices/system/cpu"
#define PATH_SYS_CPU_SMT "/sys/devices/system/cpu/smt"
diff --git a/runtest/sysfs b/runtest/sysfs
index 928b85928..3015c03f5 100644
--- a/runtest/sysfs
+++ b/runtest/sysfs
@@ -7,3 +7,4 @@ sys_cpu_topology02 sys_cpu_topology02
sys_cpu_vulnerabilities01 sys_cpu_vulnerabilities01
sys_cpu_smt01 sys_cpu_smt01
sys_cpu_cache01 sys_cpu_cache01
+sys_clockevents01 sys_clockevents01
diff --git a/testcases/kernel/sysfs/devices/system/clockevents/.gitignore b/testcases/kernel/sysfs/devices/system/clockevents/.gitignore
new file mode 100644
index 000000000..9379d10dd
--- /dev/null
+++ b/testcases/kernel/sysfs/devices/system/clockevents/.gitignore
@@ -0,0 +1 @@
+/sys_clockevents01
diff --git a/testcases/kernel/sysfs/devices/system/clockevents/Makefile b/testcases/kernel/sysfs/devices/system/clockevents/Makefile
new file mode 100644
index 000000000..781865569
--- /dev/null
+++ b/testcases/kernel/sysfs/devices/system/clockevents/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026 Cyril Hrubis <chrubis@suse.cz>
+
+top_srcdir ?= ../../../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/sysfs/devices/system/clockevents/sys_clockevents01.c b/testcases/kernel/sysfs/devices/system/clockevents/sys_clockevents01.c
new file mode 100644
index 000000000..661af03a7
--- /dev/null
+++ b/testcases/kernel/sysfs/devices/system/clockevents/sys_clockevents01.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/*\
+ * Sanity checks for the per-CPU clock event devices exported under
+ * /sys/devices/system/clockevents/clockeventN/.
+ *
+ * The kernel's tick_init_sysfs() creates one clockeventN directory for every
+ * *possible* CPU (for_each_possible_cpu()), not just the online ones, and N
+ * is the CPU id the directory belongs to (broadcast is a separate, extra
+ * entry used for CPUs whose local timer stops in idle). These directories
+ * are never removed on CPU hotplug, so a clockeventN directory exists
+ * regardless of whether cpuN is currently online.
+ *
+ * However current_device only names a device while the CPU is online:
+ * tick_shutdown(), called while taking a CPU offline, clears the per-CPU
+ * evtdev pointer, which makes current_device_show() emit an empty string.
+ * So current_device is expected to be non-empty only for online CPUs, it is
+ * legitimately empty for offline (or not-present) ones.
+ *
+ * On platforms without a per-CPU timer, secondary CPUs may instead rely
+ * entirely on a broadcast IPI from a single shared timer without ever
+ * getting their own clockeventN entry, so the number of clockeventN
+ * directories is only asserted not to exceed the number of possible CPUs
+ * rather than to match it exactly. The test verifies that:
+ *
+ * - there is at least one clockeventN directory
+ * - the number of clockeventN directories does not exceed the number of
+ * possible CPUs
+ * - each clockeventN/current_device names a non-empty clock event device
+ * while cpuN is online, and is not checked while cpuN is offline or not
+ * present
+ *
+ * The test skips with TCONF when no clockevents directory is present.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include "tst_test.h"
+#include "tst_sysfs_assert.h"
+#include "tst_path_defs.h"
+
+static int cpu_is_online(int cpu_id)
+{
+ char online[8];
+
+ /* CPU not present at all, e.g. possible but never plugged in. */
+ if (!tst_sysfs_exists(PATH_SYS_CPU "/cpu%d", cpu_id))
+ return 0;
+
+ /*
+ * Some CPUs, e.g. the boot CPU on some arches, cannot be offlined
+ * and therefore have no "online" file. Such a CPU is always online.
+ */
+ if (!TST_SYSFS_READ_STR(online, sizeof(online),
+ PATH_SYS_CPU "/cpu%d/online", cpu_id))
+ return 1;
+
+ return atoi(online) == 1;
+}
+
+static void check_clockevent(const char *name)
+{
+ char device[64] = "";
+ int cpu_id, online;
+
+ if (sscanf(name, "clockevent%d", &cpu_id) != 1) {
+ tst_res(TWARN, "Cannot parse CPU id out of '%s'", name);
+ return;
+ }
+
+ online = cpu_is_online(cpu_id);
+
+ TST_SYSFS_READ_STR(device, sizeof(device),
+ PATH_SYS_CLOCKEVENTS "/%s/current_device", name);
+
+ if (device[0] != '\0') {
+ tst_res(TPASS, "%s/current_device = '%s'", name, device);
+ return;
+ }
+
+ if (online) {
+ tst_res(TFAIL,
+ "%s/current_device is empty while cpu%d is online",
+ name, cpu_id);
+ } else {
+ tst_res(TPASS,
+ "%s/current_device is empty while cpu%d is offline",
+ name, cpu_id);
+ }
+}
+
+static void do_test(void)
+{
+ DIR *d;
+ struct dirent *ent;
+ int nclockevents = 0;
+ int possible_count, max_id;
+
+ d = TST_SYSFS_TRY_OPENDIR(PATH_SYS_CLOCKEVENTS);
+
+ while ((ent = SAFE_READDIR(d))) {
+ if (strncmp(ent->d_name, "clockevent", 10))
+ continue;
+
+ nclockevents++;
+ check_clockevent(ent->d_name);
+ }
+
+ SAFE_CLOSEDIR(d);
+
+ if (!nclockevents) {
+ tst_res(TCONF, "No clockevent directory found");
+ return;
+ }
+
+ if (TST_SYSFS_ASSERT_PARSE_LIST(&possible_count, &max_id,
+ PATH_SYS_CPU "/possible"))
+ return;
+
+ if (nclockevents <= possible_count) {
+ tst_res(TPASS,
+ "number of clockevent devices (%d) does not exceed possible CPUs (%d)",
+ nclockevents, possible_count);
+ } else {
+ tst_res(TFAIL,
+ "number of clockevent devices (%d) exceeds possible CPUs (%d)",
+ nclockevents, possible_count);
+ }
+}
+
+static struct tst_test test = {
+ .test_all = do_test,
+};
--
2.54.0
More information about the ltp
mailing list