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