xref: /OK3568_Linux_fs/kernel/tools/perf/bench/sched-pipe.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * sched-pipe.c
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * pipe: Benchmark for pipe()
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
9*4882a593Smuzhiyun  *  http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
10*4882a593Smuzhiyun  * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun #include <subcmd/parse-options.h>
13*4882a593Smuzhiyun #include "bench.h"
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <unistd.h>
16*4882a593Smuzhiyun #include <stdio.h>
17*4882a593Smuzhiyun #include <stdlib.h>
18*4882a593Smuzhiyun #include <signal.h>
19*4882a593Smuzhiyun #include <sys/wait.h>
20*4882a593Smuzhiyun #include <string.h>
21*4882a593Smuzhiyun #include <errno.h>
22*4882a593Smuzhiyun #include <assert.h>
23*4882a593Smuzhiyun #include <sys/time.h>
24*4882a593Smuzhiyun #include <sys/types.h>
25*4882a593Smuzhiyun #include <sys/syscall.h>
26*4882a593Smuzhiyun #include <linux/time64.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <pthread.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun struct thread_data {
31*4882a593Smuzhiyun 	int			nr;
32*4882a593Smuzhiyun 	int			pipe_read;
33*4882a593Smuzhiyun 	int			pipe_write;
34*4882a593Smuzhiyun 	pthread_t		pthread;
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #define LOOPS_DEFAULT 1000000
38*4882a593Smuzhiyun static	int			loops = LOOPS_DEFAULT;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* Use processes by default: */
41*4882a593Smuzhiyun static bool			threaded;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static const struct option options[] = {
44*4882a593Smuzhiyun 	OPT_INTEGER('l', "loop",	&loops,		"Specify number of loops"),
45*4882a593Smuzhiyun 	OPT_BOOLEAN('T', "threaded",	&threaded,	"Specify threads/process based task setup"),
46*4882a593Smuzhiyun 	OPT_END()
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun static const char * const bench_sched_pipe_usage[] = {
50*4882a593Smuzhiyun 	"perf bench sched pipe <options>",
51*4882a593Smuzhiyun 	NULL
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun 
worker_thread(void * __tdata)54*4882a593Smuzhiyun static void *worker_thread(void *__tdata)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	struct thread_data *td = __tdata;
57*4882a593Smuzhiyun 	int m = 0, i;
58*4882a593Smuzhiyun 	int ret;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	for (i = 0; i < loops; i++) {
61*4882a593Smuzhiyun 		if (!td->nr) {
62*4882a593Smuzhiyun 			ret = read(td->pipe_read, &m, sizeof(int));
63*4882a593Smuzhiyun 			BUG_ON(ret != sizeof(int));
64*4882a593Smuzhiyun 			ret = write(td->pipe_write, &m, sizeof(int));
65*4882a593Smuzhiyun 			BUG_ON(ret != sizeof(int));
66*4882a593Smuzhiyun 		} else {
67*4882a593Smuzhiyun 			ret = write(td->pipe_write, &m, sizeof(int));
68*4882a593Smuzhiyun 			BUG_ON(ret != sizeof(int));
69*4882a593Smuzhiyun 			ret = read(td->pipe_read, &m, sizeof(int));
70*4882a593Smuzhiyun 			BUG_ON(ret != sizeof(int));
71*4882a593Smuzhiyun 		}
72*4882a593Smuzhiyun 	}
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	return NULL;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
bench_sched_pipe(int argc,const char ** argv)77*4882a593Smuzhiyun int bench_sched_pipe(int argc, const char **argv)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	struct thread_data threads[2], *td;
80*4882a593Smuzhiyun 	int pipe_1[2], pipe_2[2];
81*4882a593Smuzhiyun 	struct timeval start, stop, diff;
82*4882a593Smuzhiyun 	unsigned long long result_usec = 0;
83*4882a593Smuzhiyun 	int nr_threads = 2;
84*4882a593Smuzhiyun 	int t;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	/*
87*4882a593Smuzhiyun 	 * why does "ret" exist?
88*4882a593Smuzhiyun 	 * discarding returned value of read(), write()
89*4882a593Smuzhiyun 	 * causes error in building environment for perf
90*4882a593Smuzhiyun 	 */
91*4882a593Smuzhiyun 	int __maybe_unused ret, wait_stat;
92*4882a593Smuzhiyun 	pid_t pid, retpid __maybe_unused;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	BUG_ON(pipe(pipe_1));
97*4882a593Smuzhiyun 	BUG_ON(pipe(pipe_2));
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	gettimeofday(&start, NULL);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	for (t = 0; t < nr_threads; t++) {
102*4882a593Smuzhiyun 		td = threads + t;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 		td->nr = t;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 		if (t == 0) {
107*4882a593Smuzhiyun 			td->pipe_read = pipe_1[0];
108*4882a593Smuzhiyun 			td->pipe_write = pipe_2[1];
109*4882a593Smuzhiyun 		} else {
110*4882a593Smuzhiyun 			td->pipe_write = pipe_1[1];
111*4882a593Smuzhiyun 			td->pipe_read = pipe_2[0];
112*4882a593Smuzhiyun 		}
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (threaded) {
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 		for (t = 0; t < nr_threads; t++) {
119*4882a593Smuzhiyun 			td = threads + t;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 			ret = pthread_create(&td->pthread, NULL, worker_thread, td);
122*4882a593Smuzhiyun 			BUG_ON(ret);
123*4882a593Smuzhiyun 		}
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 		for (t = 0; t < nr_threads; t++) {
126*4882a593Smuzhiyun 			td = threads + t;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 			ret = pthread_join(td->pthread, NULL);
129*4882a593Smuzhiyun 			BUG_ON(ret);
130*4882a593Smuzhiyun 		}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	} else {
133*4882a593Smuzhiyun 		pid = fork();
134*4882a593Smuzhiyun 		assert(pid >= 0);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 		if (!pid) {
137*4882a593Smuzhiyun 			worker_thread(threads + 0);
138*4882a593Smuzhiyun 			exit(0);
139*4882a593Smuzhiyun 		} else {
140*4882a593Smuzhiyun 			worker_thread(threads + 1);
141*4882a593Smuzhiyun 		}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 		retpid = waitpid(pid, &wait_stat, 0);
144*4882a593Smuzhiyun 		assert((retpid == pid) && WIFEXITED(wait_stat));
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	gettimeofday(&stop, NULL);
148*4882a593Smuzhiyun 	timersub(&stop, &start, &diff);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	switch (bench_format) {
151*4882a593Smuzhiyun 	case BENCH_FORMAT_DEFAULT:
152*4882a593Smuzhiyun 		printf("# Executed %d pipe operations between two %s\n\n",
153*4882a593Smuzhiyun 			loops, threaded ? "threads" : "processes");
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		result_usec = diff.tv_sec * USEC_PER_SEC;
156*4882a593Smuzhiyun 		result_usec += diff.tv_usec;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 		printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
159*4882a593Smuzhiyun 		       diff.tv_sec,
160*4882a593Smuzhiyun 		       (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 		printf(" %14lf usecs/op\n",
163*4882a593Smuzhiyun 		       (double)result_usec / (double)loops);
164*4882a593Smuzhiyun 		printf(" %14d ops/sec\n",
165*4882a593Smuzhiyun 		       (int)((double)loops /
166*4882a593Smuzhiyun 			     ((double)result_usec / (double)USEC_PER_SEC)));
167*4882a593Smuzhiyun 		break;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	case BENCH_FORMAT_SIMPLE:
170*4882a593Smuzhiyun 		printf("%lu.%03lu\n",
171*4882a593Smuzhiyun 		       diff.tv_sec,
172*4882a593Smuzhiyun 		       (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
173*4882a593Smuzhiyun 		break;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	default:
176*4882a593Smuzhiyun 		/* reaching here is something disaster */
177*4882a593Smuzhiyun 		fprintf(stderr, "Unknown format:%d\n", bench_format);
178*4882a593Smuzhiyun 		exit(1);
179*4882a593Smuzhiyun 		break;
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	return 0;
183*4882a593Smuzhiyun }
184