xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/powerpc/benchmarks/fork.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun /*
4*4882a593Smuzhiyun  * Context switch microbenchmark.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright 2018, Anton Blanchard, IBM Corp.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #define _GNU_SOURCE
10*4882a593Smuzhiyun #include <assert.h>
11*4882a593Smuzhiyun #include <errno.h>
12*4882a593Smuzhiyun #include <getopt.h>
13*4882a593Smuzhiyun #include <limits.h>
14*4882a593Smuzhiyun #include <linux/futex.h>
15*4882a593Smuzhiyun #include <pthread.h>
16*4882a593Smuzhiyun #include <sched.h>
17*4882a593Smuzhiyun #include <signal.h>
18*4882a593Smuzhiyun #include <stdio.h>
19*4882a593Smuzhiyun #include <stdlib.h>
20*4882a593Smuzhiyun #include <string.h>
21*4882a593Smuzhiyun #include <sys/shm.h>
22*4882a593Smuzhiyun #include <sys/syscall.h>
23*4882a593Smuzhiyun #include <sys/time.h>
24*4882a593Smuzhiyun #include <sys/types.h>
25*4882a593Smuzhiyun #include <sys/wait.h>
26*4882a593Smuzhiyun #include <unistd.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static unsigned int timeout = 30;
29*4882a593Smuzhiyun 
set_cpu(int cpu)30*4882a593Smuzhiyun static void set_cpu(int cpu)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	cpu_set_t cpuset;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	if (cpu == -1)
35*4882a593Smuzhiyun 		return;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	CPU_ZERO(&cpuset);
38*4882a593Smuzhiyun 	CPU_SET(cpu, &cpuset);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) {
41*4882a593Smuzhiyun 		perror("sched_setaffinity");
42*4882a593Smuzhiyun 		exit(1);
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun 
start_process_on(void * (* fn)(void *),void * arg,int cpu)46*4882a593Smuzhiyun static void start_process_on(void *(*fn)(void *), void *arg, int cpu)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	int pid;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	pid = fork();
51*4882a593Smuzhiyun 	if (pid == -1) {
52*4882a593Smuzhiyun 		perror("fork");
53*4882a593Smuzhiyun 		exit(1);
54*4882a593Smuzhiyun 	}
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	if (pid)
57*4882a593Smuzhiyun 		return;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	set_cpu(cpu);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	fn(arg);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	exit(0);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun static int cpu;
67*4882a593Smuzhiyun static int do_fork = 0;
68*4882a593Smuzhiyun static int do_vfork = 0;
69*4882a593Smuzhiyun static int do_exec = 0;
70*4882a593Smuzhiyun static char *exec_file;
71*4882a593Smuzhiyun static int exec_target = 0;
72*4882a593Smuzhiyun static unsigned long iterations;
73*4882a593Smuzhiyun static unsigned long iterations_prev;
74*4882a593Smuzhiyun 
run_exec(void)75*4882a593Smuzhiyun static void run_exec(void)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	char *const argv[] = { "./exec_target", NULL };
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	if (execve("./exec_target", argv, NULL) == -1) {
80*4882a593Smuzhiyun 		perror("execve");
81*4882a593Smuzhiyun 		exit(1);
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
bench_fork(void)85*4882a593Smuzhiyun static void bench_fork(void)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	while (1) {
88*4882a593Smuzhiyun 		pid_t pid = fork();
89*4882a593Smuzhiyun 		if (pid == -1) {
90*4882a593Smuzhiyun 			perror("fork");
91*4882a593Smuzhiyun 			exit(1);
92*4882a593Smuzhiyun 		}
93*4882a593Smuzhiyun 		if (pid == 0) {
94*4882a593Smuzhiyun 			if (do_exec)
95*4882a593Smuzhiyun 				run_exec();
96*4882a593Smuzhiyun 			_exit(0);
97*4882a593Smuzhiyun 		}
98*4882a593Smuzhiyun 		pid = waitpid(pid, NULL, 0);
99*4882a593Smuzhiyun 		if (pid == -1) {
100*4882a593Smuzhiyun 			perror("waitpid");
101*4882a593Smuzhiyun 			exit(1);
102*4882a593Smuzhiyun 		}
103*4882a593Smuzhiyun 		iterations++;
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
bench_vfork(void)107*4882a593Smuzhiyun static void bench_vfork(void)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	while (1) {
110*4882a593Smuzhiyun 		pid_t pid = vfork();
111*4882a593Smuzhiyun 		if (pid == -1) {
112*4882a593Smuzhiyun 			perror("fork");
113*4882a593Smuzhiyun 			exit(1);
114*4882a593Smuzhiyun 		}
115*4882a593Smuzhiyun 		if (pid == 0) {
116*4882a593Smuzhiyun 			if (do_exec)
117*4882a593Smuzhiyun 				run_exec();
118*4882a593Smuzhiyun 			_exit(0);
119*4882a593Smuzhiyun 		}
120*4882a593Smuzhiyun 		pid = waitpid(pid, NULL, 0);
121*4882a593Smuzhiyun 		if (pid == -1) {
122*4882a593Smuzhiyun 			perror("waitpid");
123*4882a593Smuzhiyun 			exit(1);
124*4882a593Smuzhiyun 		}
125*4882a593Smuzhiyun 		iterations++;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
null_fn(void * arg)129*4882a593Smuzhiyun static void *null_fn(void *arg)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	pthread_exit(NULL);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
bench_thread(void)134*4882a593Smuzhiyun static void bench_thread(void)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	pthread_t tid;
137*4882a593Smuzhiyun 	cpu_set_t cpuset;
138*4882a593Smuzhiyun 	pthread_attr_t attr;
139*4882a593Smuzhiyun 	int rc;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	rc = pthread_attr_init(&attr);
142*4882a593Smuzhiyun 	if (rc) {
143*4882a593Smuzhiyun 		errno = rc;
144*4882a593Smuzhiyun 		perror("pthread_attr_init");
145*4882a593Smuzhiyun 		exit(1);
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (cpu != -1) {
149*4882a593Smuzhiyun 		CPU_ZERO(&cpuset);
150*4882a593Smuzhiyun 		CPU_SET(cpu, &cpuset);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
153*4882a593Smuzhiyun 		if (rc) {
154*4882a593Smuzhiyun 			errno = rc;
155*4882a593Smuzhiyun 			perror("pthread_attr_setaffinity_np");
156*4882a593Smuzhiyun 			exit(1);
157*4882a593Smuzhiyun 		}
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	while (1) {
161*4882a593Smuzhiyun 		rc = pthread_create(&tid, &attr, null_fn, NULL);
162*4882a593Smuzhiyun 		if (rc) {
163*4882a593Smuzhiyun 			errno = rc;
164*4882a593Smuzhiyun 			perror("pthread_create");
165*4882a593Smuzhiyun 			exit(1);
166*4882a593Smuzhiyun 		}
167*4882a593Smuzhiyun 		rc = pthread_join(tid, NULL);
168*4882a593Smuzhiyun 		if (rc) {
169*4882a593Smuzhiyun 			errno = rc;
170*4882a593Smuzhiyun 			perror("pthread_join");
171*4882a593Smuzhiyun 			exit(1);
172*4882a593Smuzhiyun 		}
173*4882a593Smuzhiyun 		iterations++;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun 
sigalrm_handler(int junk)177*4882a593Smuzhiyun static void sigalrm_handler(int junk)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	unsigned long i = iterations;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	printf("%ld\n", i - iterations_prev);
182*4882a593Smuzhiyun 	iterations_prev = i;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (--timeout == 0)
185*4882a593Smuzhiyun 		kill(0, SIGUSR1);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	alarm(1);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
sigusr1_handler(int junk)190*4882a593Smuzhiyun static void sigusr1_handler(int junk)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	exit(0);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
bench_proc(void * arg)195*4882a593Smuzhiyun static void *bench_proc(void *arg)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	signal(SIGALRM, sigalrm_handler);
198*4882a593Smuzhiyun 	alarm(1);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (do_fork)
201*4882a593Smuzhiyun 		bench_fork();
202*4882a593Smuzhiyun 	else if (do_vfork)
203*4882a593Smuzhiyun 		bench_vfork();
204*4882a593Smuzhiyun 	else
205*4882a593Smuzhiyun 		bench_thread();
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	return NULL;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun static struct option options[] = {
211*4882a593Smuzhiyun 	{ "fork", no_argument, &do_fork, 1 },
212*4882a593Smuzhiyun 	{ "vfork", no_argument, &do_vfork, 1 },
213*4882a593Smuzhiyun 	{ "exec", no_argument, &do_exec, 1 },
214*4882a593Smuzhiyun 	{ "timeout", required_argument, 0, 's' },
215*4882a593Smuzhiyun 	{ "exec-target", no_argument, &exec_target, 1 },
216*4882a593Smuzhiyun 	{ NULL },
217*4882a593Smuzhiyun };
218*4882a593Smuzhiyun 
usage(void)219*4882a593Smuzhiyun static void usage(void)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	fprintf(stderr, "Usage: fork <options> CPU\n\n");
222*4882a593Smuzhiyun 	fprintf(stderr, "\t\t--fork\tUse fork() (default threads)\n");
223*4882a593Smuzhiyun 	fprintf(stderr, "\t\t--vfork\tUse vfork() (default threads)\n");
224*4882a593Smuzhiyun 	fprintf(stderr, "\t\t--exec\tAlso exec() (default no exec)\n");
225*4882a593Smuzhiyun 	fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n");
226*4882a593Smuzhiyun 	fprintf(stderr, "\t\t--exec-target\tInternal option for exec workload\n");
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
main(int argc,char * argv[])229*4882a593Smuzhiyun int main(int argc, char *argv[])
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	signed char c;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	while (1) {
234*4882a593Smuzhiyun 		int option_index = 0;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 		c = getopt_long(argc, argv, "", options, &option_index);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 		if (c == -1)
239*4882a593Smuzhiyun 			break;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 		switch (c) {
242*4882a593Smuzhiyun 		case 0:
243*4882a593Smuzhiyun 			if (options[option_index].flag != 0)
244*4882a593Smuzhiyun 				break;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 			usage();
247*4882a593Smuzhiyun 			exit(1);
248*4882a593Smuzhiyun 			break;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 		case 's':
251*4882a593Smuzhiyun 			timeout = atoi(optarg);
252*4882a593Smuzhiyun 			break;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 		default:
255*4882a593Smuzhiyun 			usage();
256*4882a593Smuzhiyun 			exit(1);
257*4882a593Smuzhiyun 		}
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	if (do_fork && do_vfork) {
261*4882a593Smuzhiyun 		usage();
262*4882a593Smuzhiyun 		exit(1);
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 	if (do_exec && !do_fork && !do_vfork) {
265*4882a593Smuzhiyun 		usage();
266*4882a593Smuzhiyun 		exit(1);
267*4882a593Smuzhiyun 	}
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	if (do_exec) {
270*4882a593Smuzhiyun 		char *dirname = strdup(argv[0]);
271*4882a593Smuzhiyun 		int i;
272*4882a593Smuzhiyun 		i = strlen(dirname) - 1;
273*4882a593Smuzhiyun 		while (i) {
274*4882a593Smuzhiyun 			if (dirname[i] == '/') {
275*4882a593Smuzhiyun 				dirname[i] = '\0';
276*4882a593Smuzhiyun 				if (chdir(dirname) == -1) {
277*4882a593Smuzhiyun 					perror("chdir");
278*4882a593Smuzhiyun 					exit(1);
279*4882a593Smuzhiyun 				}
280*4882a593Smuzhiyun 				break;
281*4882a593Smuzhiyun 			}
282*4882a593Smuzhiyun 			i--;
283*4882a593Smuzhiyun 		}
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	if (exec_target) {
287*4882a593Smuzhiyun 		exit(0);
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	if (((argc - optind) != 1)) {
291*4882a593Smuzhiyun 		cpu = -1;
292*4882a593Smuzhiyun 	} else {
293*4882a593Smuzhiyun 		cpu = atoi(argv[optind++]);
294*4882a593Smuzhiyun 	}
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	if (do_exec)
297*4882a593Smuzhiyun 		exec_file = argv[0];
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	set_cpu(cpu);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	printf("Using ");
302*4882a593Smuzhiyun 	if (do_fork)
303*4882a593Smuzhiyun 		printf("fork");
304*4882a593Smuzhiyun 	else if (do_vfork)
305*4882a593Smuzhiyun 		printf("vfork");
306*4882a593Smuzhiyun 	else
307*4882a593Smuzhiyun 		printf("clone");
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	if (do_exec)
310*4882a593Smuzhiyun 		printf(" + exec");
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	printf(" on cpu %d\n", cpu);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	/* Create a new process group so we can signal everyone for exit */
315*4882a593Smuzhiyun 	setpgid(getpid(), getpid());
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	signal(SIGUSR1, sigusr1_handler);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	start_process_on(bench_proc, NULL, cpu);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	while (1)
322*4882a593Smuzhiyun 		sleep(3600);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	return 0;
325*4882a593Smuzhiyun }
326