162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * syscall.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * syscall: Benchmark for system call performance 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include "../perf.h" 862306a36Sopenharmony_ci#include "../util/util.h" 962306a36Sopenharmony_ci#include <subcmd/parse-options.h> 1062306a36Sopenharmony_ci#include "../builtin.h" 1162306a36Sopenharmony_ci#include "bench.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <stdio.h> 1462306a36Sopenharmony_ci#include <sys/time.h> 1562306a36Sopenharmony_ci#include <sys/syscall.h> 1662306a36Sopenharmony_ci#include <sys/types.h> 1762306a36Sopenharmony_ci#include <sys/wait.h> 1862306a36Sopenharmony_ci#include <unistd.h> 1962306a36Sopenharmony_ci#include <stdlib.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#ifndef __NR_fork 2262306a36Sopenharmony_ci#define __NR_fork -1 2362306a36Sopenharmony_ci#endif 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define LOOPS_DEFAULT 10000000 2662306a36Sopenharmony_cistatic int loops = LOOPS_DEFAULT; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const struct option options[] = { 2962306a36Sopenharmony_ci OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), 3062306a36Sopenharmony_ci OPT_END() 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic const char * const bench_syscall_usage[] = { 3462306a36Sopenharmony_ci "perf bench syscall <options>", 3562306a36Sopenharmony_ci NULL 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void test_fork(void) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci pid_t pid = fork(); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (pid < 0) { 4362306a36Sopenharmony_ci fprintf(stderr, "fork failed\n"); 4462306a36Sopenharmony_ci exit(1); 4562306a36Sopenharmony_ci } else if (pid == 0) { 4662306a36Sopenharmony_ci exit(0); 4762306a36Sopenharmony_ci } else { 4862306a36Sopenharmony_ci if (waitpid(pid, NULL, 0) < 0) { 4962306a36Sopenharmony_ci fprintf(stderr, "waitpid failed\n"); 5062306a36Sopenharmony_ci exit(1); 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void test_execve(void) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci const char *pathname = "/bin/true"; 5862306a36Sopenharmony_ci char *const argv[] = { (char *)pathname, NULL }; 5962306a36Sopenharmony_ci pid_t pid = fork(); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (pid < 0) { 6262306a36Sopenharmony_ci fprintf(stderr, "fork failed\n"); 6362306a36Sopenharmony_ci exit(1); 6462306a36Sopenharmony_ci } else if (pid == 0) { 6562306a36Sopenharmony_ci execve(pathname, argv, NULL); 6662306a36Sopenharmony_ci fprintf(stderr, "execve /bin/true failed\n"); 6762306a36Sopenharmony_ci exit(1); 6862306a36Sopenharmony_ci } else { 6962306a36Sopenharmony_ci if (waitpid(pid, NULL, 0) < 0) { 7062306a36Sopenharmony_ci fprintf(stderr, "waitpid failed\n"); 7162306a36Sopenharmony_ci exit(1); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int bench_syscall_common(int argc, const char **argv, int syscall) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct timeval start, stop, diff; 7962306a36Sopenharmony_ci unsigned long long result_usec = 0; 8062306a36Sopenharmony_ci const char *name = NULL; 8162306a36Sopenharmony_ci int i; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci argc = parse_options(argc, argv, options, bench_syscall_usage, 0); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci gettimeofday(&start, NULL); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci for (i = 0; i < loops; i++) { 8862306a36Sopenharmony_ci switch (syscall) { 8962306a36Sopenharmony_ci case __NR_getppid: 9062306a36Sopenharmony_ci getppid(); 9162306a36Sopenharmony_ci break; 9262306a36Sopenharmony_ci case __NR_getpgid: 9362306a36Sopenharmony_ci getpgid(0); 9462306a36Sopenharmony_ci break; 9562306a36Sopenharmony_ci case __NR_fork: 9662306a36Sopenharmony_ci test_fork(); 9762306a36Sopenharmony_ci /* Only loop 10000 times to save time */ 9862306a36Sopenharmony_ci if (i == 10000) 9962306a36Sopenharmony_ci loops = 10000; 10062306a36Sopenharmony_ci break; 10162306a36Sopenharmony_ci case __NR_execve: 10262306a36Sopenharmony_ci test_execve(); 10362306a36Sopenharmony_ci /* Only loop 10000 times to save time */ 10462306a36Sopenharmony_ci if (i == 10000) 10562306a36Sopenharmony_ci loops = 10000; 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci default: 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci gettimeofday(&stop, NULL); 11362306a36Sopenharmony_ci timersub(&stop, &start, &diff); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci switch (syscall) { 11662306a36Sopenharmony_ci case __NR_getppid: 11762306a36Sopenharmony_ci name = "getppid()"; 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci case __NR_getpgid: 12062306a36Sopenharmony_ci name = "getpgid()"; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci case __NR_fork: 12362306a36Sopenharmony_ci name = "fork()"; 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci case __NR_execve: 12662306a36Sopenharmony_ci name = "execve()"; 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci default: 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci switch (bench_format) { 13362306a36Sopenharmony_ci case BENCH_FORMAT_DEFAULT: 13462306a36Sopenharmony_ci printf("# Executed %'d %s calls\n", loops, name); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci result_usec = diff.tv_sec * 1000000; 13762306a36Sopenharmony_ci result_usec += diff.tv_usec; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", 14062306a36Sopenharmony_ci (unsigned long) diff.tv_sec, 14162306a36Sopenharmony_ci (unsigned long) (diff.tv_usec/1000)); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci printf(" %14lf usecs/op\n", 14462306a36Sopenharmony_ci (double)result_usec / (double)loops); 14562306a36Sopenharmony_ci printf(" %'14d ops/sec\n", 14662306a36Sopenharmony_ci (int)((double)loops / 14762306a36Sopenharmony_ci ((double)result_usec / (double)1000000))); 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci case BENCH_FORMAT_SIMPLE: 15162306a36Sopenharmony_ci printf("%lu.%03lu\n", 15262306a36Sopenharmony_ci (unsigned long) diff.tv_sec, 15362306a36Sopenharmony_ci (unsigned long) (diff.tv_usec / 1000)); 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci default: 15762306a36Sopenharmony_ci /* reaching here is something disaster */ 15862306a36Sopenharmony_ci fprintf(stderr, "Unknown format:%d\n", bench_format); 15962306a36Sopenharmony_ci exit(1); 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciint bench_syscall_basic(int argc, const char **argv) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci return bench_syscall_common(argc, argv, __NR_getppid); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ciint bench_syscall_getpgid(int argc, const char **argv) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci return bench_syscall_common(argc, argv, __NR_getpgid); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciint bench_syscall_fork(int argc, const char **argv) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci return bench_syscall_common(argc, argv, __NR_fork); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ciint bench_syscall_execve(int argc, const char **argv) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci return bench_syscall_common(argc, argv, __NR_execve); 18462306a36Sopenharmony_ci} 185