xref: /linux/tools/perf/tests/workloads/context_switch_loop.c (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
1 
2 // SPDX-License-Identifier: GPL-2.0
3 
4 #include <linux/compiler.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <sys/prctl.h>
8 #include <sys/wait.h>
9 #include <unistd.h>
10 
11 #include "../tests.h"
12 
13 static int loops = 100;
14 static char buf;
15 int context_switch_loop_work = 1234;
16 
17 #define write_block(fd) \
18 	do { \
19 		if (write(fd, &buf, 1) <= 0) \
20 			return 1; \
21 	} while (0)
22 
23 #define read_block(fd) \
24 	do { \
25 		if (read(fd, &buf, 1) <= 0) \
26 			return 1; \
27 	} while (0)
28 
29 /* Not static to avoid LTO clobbering the function name */
30 int context_switch_loop_proc1(int in_fd, int out_fd);
31 int context_switch_loop_proc1(int in_fd, int out_fd)
32 {
33 	for (int i = 0; i < loops; i++) {
34 		read_block(in_fd);
35 		context_switch_loop_work += i * 3;
36 		write_block(out_fd);
37 	}
38 	return 0;
39 }
40 
41 int context_switch_loop_proc2(int in_fd, int out_fd);
42 int context_switch_loop_proc2(int in_fd, int out_fd)
43 {
44 	for (int i = 0; i < loops; i++) {
45 		write_block(out_fd);
46 		context_switch_loop_work += i * 7;
47 		read_block(in_fd);
48 	}
49 	return 0;
50 }
51 
52 /*
53  * Launches two processes that take turns to execute a multiplication N times
54  */
55 static int context_switch_loop(int argc, const char **argv)
56 {
57 	int a_to_b[2], b_to_a[2];
58 	pid_t proc1_pid;
59 	int status;
60 	int ret;
61 
62 	if (argc > 0) {
63 		loops = atoi(argv[0]);
64 		if (loops < 0) {
65 			fprintf(stderr, "Invalid number of loops: %s\n", argv[0]);
66 			return 1;
67 		}
68 	}
69 
70 	if (pipe(a_to_b) || pipe(b_to_a)) {
71 		perror("Pipe error");
72 		return 1;
73 	}
74 
75 	proc1_pid = fork();
76 	if (proc1_pid < 0) {
77 		perror("Fork error");
78 		return 1;
79 	}
80 
81 	if (!proc1_pid) {
82 		close(a_to_b[0]);
83 		close(b_to_a[1]);
84 		prctl(PR_SET_NAME, "proc1", 0, 0, 0);
85 		ret = context_switch_loop_proc1(b_to_a[0], a_to_b[1]);
86 		close(a_to_b[1]);
87 		close(b_to_a[0]);
88 		exit(ret);
89 	}
90 
91 	close(a_to_b[1]);
92 	close(b_to_a[0]);
93 	prctl(PR_SET_NAME, "proc2", 0, 0, 0);
94 	ret = context_switch_loop_proc2(a_to_b[0], b_to_a[1]);
95 	close(a_to_b[0]);
96 	close(b_to_a[1]);
97 
98 	if (ret) {
99 		kill(proc1_pid, SIGKILL);
100 		return ret;
101 	}
102 
103 	if (waitpid(proc1_pid, &status, 0) != proc1_pid || !WIFEXITED(status) ||
104 	    WEXITSTATUS(status))
105 		return 1;
106 
107 	return 0;
108 }
109 
110 DEFINE_WORKLOAD(context_switch_loop);
111