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 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 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 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 166 int bench_syscall_basic(int argc, const char **argv) 167 { 168 return bench_syscall_common(argc, argv, __NR_getppid); 169 } 170 171 int bench_syscall_getpgid(int argc, const char **argv) 172 { 173 return bench_syscall_common(argc, argv, __NR_getpgid); 174 } 175 176 int bench_syscall_fork(int argc, const char **argv) 177 { 178 return bench_syscall_common(argc, argv, __NR_fork); 179 } 180 181 int bench_syscall_execve(int argc, const char **argv) 182 { 183 return bench_syscall_common(argc, argv, __NR_execve); 184 } 185