]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf test: Add a workload that forces context switches
authorJames Clark <james.clark@linaro.org>
Tue, 9 Jun 2026 14:40:08 +0000 (15:40 +0100)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 10 Jun 2026 21:55:48 +0000 (18:55 -0300)
This workload launches two processes that block when reading and writing
to each other forcing the other process to be scheduled for each
read/write pair.

Signed-off-by: James Clark <james.clark@linaro.org>
Cc: Amir Ayupov <aaupov@meta.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Mike Leach <mike.leach@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paschalis Mpeis <Paschalis.Mpeis@arm.com>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-test.txt
tools/perf/tests/builtin-test.c
tools/perf/tests/tests.h
tools/perf/tests/workloads/Build
tools/perf/tests/workloads/context_switch_loop.c [new file with mode: 0644]

index 2f4a91f5b9dc6466707c6f4ff5c0f8686a49051a..213eb62603ebefae527a53bca014ae886bee84de 100644 (file)
@@ -55,15 +55,16 @@ OPTIONS
 
 -w::
 --workload=::
-       Run a built-in workload, to list them use '--list-workloads', current ones include:
-       noploop, thloop, leafloop, sqrtloop, brstack, datasym and landlock.
+       Run a built-in workload, to list them use '--list-workloads', current
+       ones include: noploop, thloop, leafloop, sqrtloop, brstack, datasym,
+       context_switch_loop and landlock.
 
        Used with the shell script regression tests.
 
        Some accept an extra parameter:
 
                seconds: leafloop, noploop, sqrtloop, thloop
-               nrloops: brstack
+               nrloops: brstack, context_switch_loop
 
        The datasym and landlock workloads don't accept any.
 
index 86ea427eb0aa8f500db9fd044c3a2a3b156f0ea8..9284f897de3c7cced25dc56c3aafec6b2dcaeecd 100644 (file)
@@ -163,6 +163,7 @@ static struct test_workload *workloads[] = {
        &workload__traploop,
        &workload__inlineloop,
        &workload__jitdump,
+       &workload__context_switch_loop,
 
 #ifdef HAVE_RUST_SUPPORT
        &workload__code_with_type,
index bf8ff7d54727a1c6da1cc163fdccc06ec19d1827..7cd4da4e96d33adbfa768ed82dc0b557e34bc287 100644 (file)
@@ -245,6 +245,7 @@ DECLARE_WORKLOAD(landlock);
 DECLARE_WORKLOAD(traploop);
 DECLARE_WORKLOAD(inlineloop);
 DECLARE_WORKLOAD(jitdump);
+DECLARE_WORKLOAD(context_switch_loop);
 
 #ifdef HAVE_RUST_SUPPORT
 DECLARE_WORKLOAD(code_with_type);
index 0eb6d99528eb924f40e2717d5fb4610812c215f2..7134a031cb7c112cf0a64d70950265f4cba5e626 100644 (file)
@@ -10,6 +10,7 @@ perf-test-y += landlock.o
 perf-test-y += traploop.o
 perf-test-y += inlineloop.o
 perf-test-y += jitdump.o
+perf-test-y += context_switch_loop.o
 
 ifeq ($(CONFIG_RUST_SUPPORT),y)
     perf-test-y += code_with_type.o
diff --git a/tools/perf/tests/workloads/context_switch_loop.c b/tools/perf/tests/workloads/context_switch_loop.c
new file mode 100644 (file)
index 0000000..5431af6
--- /dev/null
@@ -0,0 +1,110 @@
+
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/compiler.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "../tests.h"
+
+static int loops = 100;
+static char buf;
+int context_switch_loop_work = 1234;
+
+#define write_block(fd) \
+       do { \
+               if (write(fd, &buf, 1) <= 0) \
+                       return 1; \
+       } while (0)
+
+#define read_block(fd) \
+       do { \
+               if (read(fd, &buf, 1) <= 0) \
+                       return 1; \
+       } while (0)
+
+/* Not static to avoid LTO clobbering the function name */
+int context_switch_loop_proc1(int in_fd, int out_fd);
+int context_switch_loop_proc1(int in_fd, int out_fd)
+{
+       for (int i = 0; i < loops; i++) {
+               read_block(in_fd);
+               context_switch_loop_work += i * 3;
+               write_block(out_fd);
+       }
+       return 0;
+}
+
+int context_switch_loop_proc2(int in_fd, int out_fd);
+int context_switch_loop_proc2(int in_fd, int out_fd)
+{
+       for (int i = 0; i < loops; i++) {
+               write_block(out_fd);
+               context_switch_loop_work += i * 7;
+               read_block(in_fd);
+       }
+       return 0;
+}
+
+/*
+ * Launches two processes that take turns to execute a multiplication N times
+ */
+static int context_switch_loop(int argc, const char **argv)
+{
+       int a_to_b[2], b_to_a[2];
+       pid_t proc1_pid;
+       int status;
+       int ret;
+
+       if (argc > 0) {
+               loops = atoi(argv[0]);
+               if (loops < 0) {
+                       fprintf(stderr, "Invalid number of loops: %s\n", argv[0]);
+                       return 1;
+               }
+       }
+
+       if (pipe(a_to_b) || pipe(b_to_a)) {
+               perror("Pipe error");
+               return 1;
+       }
+
+       proc1_pid = fork();
+       if (proc1_pid < 0) {
+               perror("Fork error");
+               return 1;
+       }
+
+       if (!proc1_pid) {
+               close(a_to_b[0]);
+               close(b_to_a[1]);
+               prctl(PR_SET_NAME, "proc1", 0, 0, 0);
+               ret = context_switch_loop_proc1(b_to_a[0], a_to_b[1]);
+               close(a_to_b[1]);
+               close(b_to_a[0]);
+               exit(ret);
+       }
+
+       close(a_to_b[1]);
+       close(b_to_a[0]);
+       prctl(PR_SET_NAME, "proc2", 0, 0, 0);
+       ret = context_switch_loop_proc2(a_to_b[0], b_to_a[1]);
+       close(a_to_b[0]);
+       close(b_to_a[1]);
+
+       if (ret) {
+               kill(proc1_pid, SIGKILL);
+               return ret;
+       }
+
+       if (waitpid(proc1_pid, &status, 0) != proc1_pid || !WIFEXITED(status) ||
+           WEXITSTATUS(status))
+               return 1;
+
+       return 0;
+}
+
+DEFINE_WORKLOAD(context_switch_loop);