[LTP] [LTP PATCH 4/5] ftrace: Add C implementation of ftrace_stress_test and update build
Praveen K Pandey
praveen@linux.ibm.com
Sat Jun 6 16:31:32 CEST 2026
Convert ftrace_stress_test.sh to C with multi-threaded implementation.
Update Makefile to build C tests with pthread support.
The C stress test spawns multiple threads to exercise different
ftrace features concurrently, providing better stress testing
than the shell version.
Shell scripts are retained for backward compatibility during
the transition period.
Fixes: #1282
Signed-off-by: Praveen K Pandey <praveen@linux.ibm.com>
---
testcases/kernel/tracing/ftrace_test/Makefile | 18 +-
.../tracing/ftrace_test/ftrace_stress_test.c | 324 ++++++++++++++++++
2 files changed, 340 insertions(+), 2 deletions(-)
create mode 100644 testcases/kernel/tracing/ftrace_test/ftrace_stress_test.c
diff --git a/testcases/kernel/tracing/ftrace_test/Makefile b/testcases/kernel/tracing/ftrace_test/Makefile
index e4a913a56..b08a3e6fe 100644
--- a/testcases/kernel/tracing/ftrace_test/Makefile
+++ b/testcases/kernel/tracing/ftrace_test/Makefile
@@ -1,7 +1,21 @@
-top_srcdir ?= ../../../..
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2010 FUJITSU LIMITED
+# Copyright (c) 2024 Linux Test Project
+# Copyright (c) IBM, 2026
+# Converted to C by: Praveen K Pandey <praveen@linux.ibm.com>
+
+top_srcdir ?= ../../../..
include $(top_srcdir)/include/mk/testcases.mk
-INSTALL_TARGETS := *.sh ftrace_stress/*
+# Shell scripts (kept for backward compatibility during transition)
+INSTALL_TARGETS := *.sh ftrace_stress/*
+
+# C test binaries
+ftrace_regression01: ftrace_lib.o
+ftrace_regression02: ftrace_lib.o
+ftrace_stress_test: ftrace_lib.o
+
+LDLIBS += -lpthread
include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/tracing/ftrace_test/ftrace_stress_test.c b/testcases/kernel/tracing/ftrace_test/ftrace_stress_test.c
new file mode 100644
index 000000000..cdd167436
--- /dev/null
+++ b/testcases/kernel/tracing/ftrace_test/ftrace_stress_test.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2010 FUJITSU LIMITED
+ * Copyright (c) 2024 Linux Test Project
+ * Copyright (c) IBM, 2026
+ *
+ * Author: Li Zefan <lizf@cn.fujitsu.com>
+ * Converted to C by: Praveen K Pandey <praveen@linux.ibm.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * Stress test for ftrace subsystem.
+ *
+ * This test exercises various ftrace features concurrently to detect
+ * race conditions, memory leaks, and other issues in the ftrace subsystem.
+ *
+ * [Algorithm]
+ *
+ * The test spawns multiple threads, each exercising a different ftrace
+ * feature:
+ * - Switching between different tracers
+ * - Reading from trace_pipe
+ * - Enabling/disabling events
+ * - Modifying buffer size
+ * - Setting trace filters
+ * - Modifying trace options
+ * - And more...
+ *
+ * All threads run concurrently for a specified duration, then the test
+ * verifies the system is still stable.
+ */
+
+#include <pthread.h>
+#include <signal.h>
+#include "ftrace_lib.h"
+
+#define DEFAULT_TEST_DURATION 60 /* seconds */
+#define MAX_THREADS 20
+
+static volatile int stop_testing = 0;
+static int test_duration = DEFAULT_TEST_DURATION;
+static pthread_t threads[MAX_THREADS];
+static int thread_count = 0;
+
+struct stress_test {
+ const char *name;
+ const char *file;
+ void *(*func)(void *);
+ int enabled;
+};
+
+/* Thread function for current_tracer stress test */
+static void *stress_current_tracer(void *arg)
+{
+ int count;
+ char **tracers;
+ int i, loop;
+
+ (void)arg;
+
+ tracers = ftrace_get_available_tracers(&count);
+ if (!tracers || count == 0) {
+ tst_res(TINFO, "No tracers available");
+ return NULL;
+ }
+
+ loop = 0;
+ while (!stop_testing) {
+ for (i = 0; i < count && !stop_testing; i++) {
+ /* Skip mmiotrace as it can cause issues */
+ if (strcmp(tracers[i], "mmiotrace") == 0)
+ continue;
+
+ ftrace_set_tracer(tracers[i]);
+ }
+ loop++;
+ if (loop >= 200)
+ usleep(1000000); /* Sleep 1 second after 200 loops */
+ }
+
+ for (i = 0; i < count; i++)
+ free(tracers[i]);
+ free(tracers);
+
+ return NULL;
+}
+
+/* Thread function for trace_pipe stress test */
+static void *stress_trace_pipe(void *arg)
+{
+ char *path;
+ FILE *fp;
+ char buf[4096];
+ int loop = 0;
+
+ (void)arg;
+
+ path = ftrace_get_path("trace_pipe");
+ if (!path)
+ return NULL;
+
+ while (!stop_testing) {
+ fp = fopen(path, "r");
+ if (fp) {
+ /* Read for a short time */
+ usleep(200000); /* 200ms */
+ fclose(fp);
+ }
+
+ usleep(200000); /* 200ms */
+ loop++;
+ if (loop >= 20) {
+ sleep(2);
+ loop = 0;
+ }
+ }
+
+ free(path);
+ return NULL;
+}
+
+/* Thread function for set_event stress test */
+static void *stress_set_event(void *arg)
+{
+ int i;
+
+ (void)arg;
+
+ while (!stop_testing) {
+ /* Enable/disable all events */
+ for (i = 0; i < 100 && !stop_testing; i++) {
+ ftrace_write_file("events/enable", "1\n");
+ ftrace_write_file("events/enable", "0\n");
+ }
+
+ sleep(1);
+ }
+
+ return NULL;
+}
+
+/* Thread function for buffer_size_kb stress test */
+static void *stress_buffer_size(void *arg)
+{
+ const char *sizes[] = {"1024", "2048", "4096", "8192"};
+ int i;
+
+ (void)arg;
+
+ while (!stop_testing) {
+ for (i = 0; i < 4 && !stop_testing; i++) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%s\n", sizes[i]);
+ ftrace_write_file("buffer_size_kb", buf);
+ usleep(100000);
+ }
+ sleep(1);
+ }
+
+ return NULL;
+}
+
+/* Thread function for tracing_on stress test */
+static void *stress_tracing_on(void *arg)
+{
+ int i;
+
+ (void)arg;
+
+ while (!stop_testing) {
+ for (i = 0; i < 100 && !stop_testing; i++) {
+ ftrace_enable_tracing();
+ ftrace_disable_tracing();
+ }
+ sleep(1);
+ }
+
+ return NULL;
+}
+
+/* Thread function for trace_options stress test */
+static void *stress_trace_options(void *arg)
+{
+ const char *options[] = {
+ "print-parent", "sym-offset", "sym-addr",
+ "verbose", "raw", "hex", "bin", "block"
+ };
+ int i;
+
+ (void)arg;
+
+ while (!stop_testing) {
+ for (i = 0; i < 8 && !stop_testing; i++) {
+ char buf[64];
+ snprintf(buf, sizeof(buf), "%s\n", options[i]);
+ ftrace_write_file("trace_options", buf);
+ snprintf(buf, sizeof(buf), "no%s\n", options[i]);
+ ftrace_write_file("trace_options", buf);
+ }
+ sleep(1);
+ }
+
+ return NULL;
+}
+
+/* Thread function for set_ftrace_filter stress test */
+static void *stress_set_ftrace_filter(void *arg)
+{
+ (void)arg;
+
+ if (!ftrace_file_exists("set_ftrace_filter"))
+ return NULL;
+
+ while (!stop_testing) {
+ ftrace_write_file("set_ftrace_filter", "schedule\n");
+ ftrace_write_file("set_ftrace_filter", "\n");
+ usleep(500000);
+ }
+
+ return NULL;
+}
+
+static struct stress_test stress_tests[] = {
+ {"current_tracer", "current_tracer", stress_current_tracer, 0},
+ {"trace_pipe", "trace_pipe", stress_trace_pipe, 0},
+ {"set_event", "events/enable", stress_set_event, 0},
+ {"buffer_size_kb", "buffer_size_kb", stress_buffer_size, 0},
+ {"tracing_on", "tracing_on", stress_tracing_on, 0},
+ {"trace_options", "trace_options", stress_trace_options, 0},
+ {"set_ftrace_filter", "set_ftrace_filter", stress_set_ftrace_filter, 0},
+ {NULL, NULL, NULL, 0}
+};
+
+static void check_available_tests(void)
+{
+ int i;
+
+ for (i = 0; stress_tests[i].name; i++) {
+ if (ftrace_file_exists(stress_tests[i].file) ||
+ access(stress_tests[i].file, F_OK) == 0) {
+ stress_tests[i].enabled = 1;
+ tst_res(TINFO, "Test target available: %s", stress_tests[i].name);
+ } else {
+ tst_res(TINFO, "Test target not available: %s", stress_tests[i].name);
+ }
+ }
+}
+
+static void start_stress_tests(void)
+{
+ int i;
+
+ thread_count = 0;
+ for (i = 0; stress_tests[i].name; i++) {
+ if (!stress_tests[i].enabled)
+ continue;
+
+ if (pthread_create(&threads[thread_count], NULL,
+ stress_tests[i].func, NULL) != 0) {
+ tst_res(TWARN, "Failed to create thread for %s",
+ stress_tests[i].name);
+ } else {
+ tst_res(TINFO, "Started stress test: %s", stress_tests[i].name);
+ thread_count++;
+ }
+ }
+
+ tst_res(TINFO, "Started %d stress test threads", thread_count);
+}
+
+static void stop_stress_tests(void)
+{
+ int i;
+
+ stop_testing = 1;
+
+ for (i = 0; i < thread_count; i++) {
+ pthread_join(threads[i], NULL);
+ }
+
+ tst_res(TINFO, "All stress test threads stopped");
+}
+
+static void run_test(void)
+{
+ tst_res(TINFO, "Starting ftrace stress test for %d seconds", test_duration);
+
+ check_available_tests();
+ start_stress_tests();
+
+ /* Run for specified duration */
+ sleep(test_duration);
+
+ stop_stress_tests();
+
+ tst_res(TPASS, "Ftrace stress test completed successfully");
+ tst_res(TINFO, "Check dmesg for any kernel warnings or errors");
+}
+
+static void setup(void)
+{
+ ftrace_initialize();
+
+ /* Check for test duration parameter */
+ if (tst_parse_int(getenv("LTP_TIMEOUT_MUL"), &test_duration, 1, INT_MAX))
+ test_duration = DEFAULT_TEST_DURATION;
+}
+
+static void cleanup(void)
+{
+ stop_testing = 1;
+ ftrace_cleanup();
+}
+
+static struct tst_test test = {
+ .test_all = run_test,
+ .setup = setup,
+ .cleanup = cleanup,
+ .needs_root = 1,
+ .max_runtime = DEFAULT_TEST_DURATION + 30,
+};
+
--
2.50.1 (Apple Git-155)
More information about the ltp
mailing list