1 /* Copyright (c) 2016 Facebook 2 * 3 * This program is free software; you can redistribute it and/or 4 * modify it under the terms of version 2 of the GNU General Public 5 * License as published by the Free Software Foundation. 6 */ 7 #define _GNU_SOURCE 8 #include <sched.h> 9 #include <stdio.h> 10 #include <sys/types.h> 11 #include <asm/unistd.h> 12 #include <fcntl.h> 13 #include <unistd.h> 14 #include <assert.h> 15 #include <sys/wait.h> 16 #include <stdlib.h> 17 #include <signal.h> 18 #include <linux/bpf.h> 19 #include <string.h> 20 #include <time.h> 21 #include <sys/resource.h> 22 #include "libbpf.h" 23 #include "bpf_load.h" 24 25 #define MAX_CNT 1000000 26 27 static __u64 time_get_ns(void) 28 { 29 struct timespec ts; 30 31 clock_gettime(CLOCK_MONOTONIC, &ts); 32 return ts.tv_sec * 1000000000ull + ts.tv_nsec; 33 } 34 35 static void test_task_rename(int cpu) 36 { 37 __u64 start_time; 38 char buf[] = "test\n"; 39 int i, fd; 40 41 fd = open("/proc/self/comm", O_WRONLY|O_TRUNC); 42 if (fd < 0) { 43 printf("couldn't open /proc\n"); 44 exit(1); 45 } 46 start_time = time_get_ns(); 47 for (i = 0; i < MAX_CNT; i++) 48 write(fd, buf, sizeof(buf)); 49 printf("task_rename:%d: %lld events per sec\n", 50 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 51 close(fd); 52 } 53 54 static void test_urandom_read(int cpu) 55 { 56 __u64 start_time; 57 char buf[4]; 58 int i, fd; 59 60 fd = open("/dev/urandom", O_RDONLY); 61 if (fd < 0) { 62 printf("couldn't open /dev/urandom\n"); 63 exit(1); 64 } 65 start_time = time_get_ns(); 66 for (i = 0; i < MAX_CNT; i++) 67 read(fd, buf, sizeof(buf)); 68 printf("urandom_read:%d: %lld events per sec\n", 69 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 70 close(fd); 71 } 72 73 static void loop(int cpu, int flags) 74 { 75 cpu_set_t cpuset; 76 77 CPU_ZERO(&cpuset); 78 CPU_SET(cpu, &cpuset); 79 sched_setaffinity(0, sizeof(cpuset), &cpuset); 80 81 if (flags & 1) 82 test_task_rename(cpu); 83 if (flags & 2) 84 test_urandom_read(cpu); 85 } 86 87 static void run_perf_test(int tasks, int flags) 88 { 89 pid_t pid[tasks]; 90 int i; 91 92 for (i = 0; i < tasks; i++) { 93 pid[i] = fork(); 94 if (pid[i] == 0) { 95 loop(i, flags); 96 exit(0); 97 } else if (pid[i] == -1) { 98 printf("couldn't spawn #%d process\n", i); 99 exit(1); 100 } 101 } 102 for (i = 0; i < tasks; i++) { 103 int status; 104 105 assert(waitpid(pid[i], &status, 0) == pid[i]); 106 assert(status == 0); 107 } 108 } 109 110 static void unload_progs(void) 111 { 112 close(prog_fd[0]); 113 close(prog_fd[1]); 114 close(event_fd[0]); 115 close(event_fd[1]); 116 } 117 118 int main(int argc, char **argv) 119 { 120 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 121 char filename[256]; 122 int num_cpu = 8; 123 int test_flags = ~0; 124 125 setrlimit(RLIMIT_MEMLOCK, &r); 126 127 if (argc > 1) 128 test_flags = atoi(argv[1]) ? : test_flags; 129 if (argc > 2) 130 num_cpu = atoi(argv[2]) ? : num_cpu; 131 132 if (test_flags & 0x3) { 133 printf("BASE\n"); 134 run_perf_test(num_cpu, test_flags); 135 } 136 137 if (test_flags & 0xC) { 138 snprintf(filename, sizeof(filename), 139 "%s_kprobe_kern.o", argv[0]); 140 if (load_bpf_file(filename)) { 141 printf("%s", bpf_log_buf); 142 return 1; 143 } 144 printf("w/KPROBE\n"); 145 run_perf_test(num_cpu, test_flags >> 2); 146 unload_progs(); 147 } 148 149 if (test_flags & 0x30) { 150 snprintf(filename, sizeof(filename), 151 "%s_tp_kern.o", argv[0]); 152 if (load_bpf_file(filename)) { 153 printf("%s", bpf_log_buf); 154 return 1; 155 } 156 printf("w/TRACEPOINT\n"); 157 run_perf_test(num_cpu, test_flags >> 4); 158 unload_progs(); 159 } 160 161 return 0; 162 } 163