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