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