xref: /linux/tools/perf/bench/syscall.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1 /*
2  *
3  * syscall.c
4  *
5  * syscall: Benchmark for system call performance
6  */
7 #include "../perf.h"
8 #include "../util/util.h"
9 #include <subcmd/parse-options.h>
10 #include "../builtin.h"
11 #include "bench.h"
12 
13 #include <stdio.h>
14 #include <sys/time.h>
15 #include <sys/syscall.h>
16 #include <sys/types.h>
17 #include <sys/wait.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 
21 #ifndef __NR_fork
22 #define __NR_fork -1
23 #endif
24 
25 #define LOOPS_DEFAULT 10000000
26 static	int loops = LOOPS_DEFAULT;
27 
28 static const struct option options[] = {
29 	OPT_INTEGER('l', "loop",	&loops,		"Specify number of loops"),
30 	OPT_END()
31 };
32 
33 static const char * const bench_syscall_usage[] = {
34 	"perf bench syscall <options>",
35 	NULL
36 };
37 
test_fork(void)38 static void test_fork(void)
39 {
40 	pid_t pid = fork();
41 
42 	if (pid < 0) {
43 		fprintf(stderr, "fork failed\n");
44 		exit(1);
45 	} else if (pid == 0) {
46 		exit(0);
47 	} else {
48 		if (waitpid(pid, NULL, 0) < 0) {
49 			fprintf(stderr, "waitpid failed\n");
50 			exit(1);
51 		}
52 	}
53 }
54 
test_execve(void)55 static void test_execve(void)
56 {
57 	const char *pathname = "/bin/true";
58 	char *const argv[] = { (char *)pathname, NULL };
59 	pid_t pid = fork();
60 
61 	if (pid < 0) {
62 		fprintf(stderr, "fork failed\n");
63 		exit(1);
64 	} else if (pid == 0) {
65 		execve(pathname, argv, NULL);
66 		fprintf(stderr, "execve /bin/true failed\n");
67 		exit(1);
68 	} else {
69 		if (waitpid(pid, NULL, 0) < 0) {
70 			fprintf(stderr, "waitpid failed\n");
71 			exit(1);
72 		}
73 	}
74 }
75 
bench_syscall_common(int argc,const char ** argv,int syscall)76 static int bench_syscall_common(int argc, const char **argv, int syscall)
77 {
78 	struct timeval start, stop, diff;
79 	unsigned long long result_usec = 0;
80 	const char *name = NULL;
81 	int i;
82 
83 	argc = parse_options(argc, argv, options, bench_syscall_usage, 0);
84 
85 	gettimeofday(&start, NULL);
86 
87 	for (i = 0; i < loops; i++) {
88 		switch (syscall) {
89 		case __NR_getppid:
90 			getppid();
91 			break;
92 		case __NR_getpgid:
93 			getpgid(0);
94 			break;
95 		case __NR_fork:
96 			test_fork();
97 			/* Only loop 10000 times to save time */
98 			if (i == 10000)
99 				loops = 10000;
100 			break;
101 		case __NR_execve:
102 			test_execve();
103 			/* Only loop 10000 times to save time */
104 			if (i == 10000)
105 				loops = 10000;
106 			break;
107 		default:
108 			break;
109 		}
110 	}
111 
112 	gettimeofday(&stop, NULL);
113 	timersub(&stop, &start, &diff);
114 
115 	switch (syscall) {
116 	case __NR_getppid:
117 		name = "getppid()";
118 		break;
119 	case __NR_getpgid:
120 		name = "getpgid()";
121 		break;
122 	case __NR_fork:
123 		name = "fork()";
124 		break;
125 	case __NR_execve:
126 		name = "execve()";
127 		break;
128 	default:
129 		break;
130 	}
131 
132 	switch (bench_format) {
133 	case BENCH_FORMAT_DEFAULT:
134 		printf("# Executed %'d %s calls\n", loops, name);
135 
136 		result_usec = diff.tv_sec * 1000000;
137 		result_usec += diff.tv_usec;
138 
139 		printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
140 		       (unsigned long) diff.tv_sec,
141 		       (unsigned long) (diff.tv_usec/1000));
142 
143 		printf(" %14lf usecs/op\n",
144 		       (double)result_usec / (double)loops);
145 		printf(" %'14d ops/sec\n",
146 		       (int)((double)loops /
147 			     ((double)result_usec / (double)1000000)));
148 		break;
149 
150 	case BENCH_FORMAT_SIMPLE:
151 		printf("%lu.%03lu\n",
152 		       (unsigned long) diff.tv_sec,
153 		       (unsigned long) (diff.tv_usec / 1000));
154 		break;
155 
156 	default:
157 		/* reaching here is something disaster */
158 		fprintf(stderr, "Unknown format:%d\n", bench_format);
159 		exit(1);
160 		break;
161 	}
162 
163 	return 0;
164 }
165 
bench_syscall_basic(int argc,const char ** argv)166 int bench_syscall_basic(int argc, const char **argv)
167 {
168 	return bench_syscall_common(argc, argv, __NR_getppid);
169 }
170 
bench_syscall_getpgid(int argc,const char ** argv)171 int bench_syscall_getpgid(int argc, const char **argv)
172 {
173 	return bench_syscall_common(argc, argv, __NR_getpgid);
174 }
175 
bench_syscall_fork(int argc,const char ** argv)176 int bench_syscall_fork(int argc, const char **argv)
177 {
178 	return bench_syscall_common(argc, argv, __NR_fork);
179 }
180 
bench_syscall_execve(int argc,const char ** argv)181 int bench_syscall_execve(int argc, const char **argv)
182 {
183 	return bench_syscall_common(argc, argv, __NR_execve);
184 }
185