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 <sys/socket.h> 15 #include <arpa/inet.h> 16 #include <stdlib.h> 17 #include <signal.h> 18 #include <linux/bpf.h> 19 #include <string.h> 20 #include <time.h> 21 #include <bpf/bpf.h> 22 #include <bpf/libbpf.h> 23 24 #define MAX_CNT 1000000 25 #define DUMMY_IP "127.0.0.1" 26 #define DUMMY_PORT 80 27 28 static struct bpf_link *links[2]; 29 static struct bpf_object *obj; 30 static int cnt; 31 32 static __u64 time_get_ns(void) 33 { 34 struct timespec ts; 35 36 clock_gettime(CLOCK_MONOTONIC, &ts); 37 return ts.tv_sec * 1000000000ull + ts.tv_nsec; 38 } 39 40 static void test_task_rename(int cpu) 41 { 42 char buf[] = "test\n"; 43 __u64 start_time; 44 int i, fd; 45 46 fd = open("/proc/self/comm", O_WRONLY|O_TRUNC); 47 if (fd < 0) { 48 printf("couldn't open /proc\n"); 49 exit(1); 50 } 51 start_time = time_get_ns(); 52 for (i = 0; i < MAX_CNT; i++) { 53 if (write(fd, buf, sizeof(buf)) < 0) { 54 printf("task rename failed: %s\n", strerror(errno)); 55 close(fd); 56 return; 57 } 58 } 59 printf("task_rename:%d: %lld events per sec\n", 60 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 61 close(fd); 62 } 63 64 static void test_fib_table_lookup(int cpu) 65 { 66 struct sockaddr_in addr; 67 char buf[] = "test\n"; 68 __u64 start_time; 69 int i, fd; 70 71 fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 72 if (fd < 0) { 73 printf("couldn't open socket\n"); 74 exit(1); 75 } 76 memset((char *)&addr, 0, sizeof(addr)); 77 addr.sin_addr.s_addr = inet_addr(DUMMY_IP); 78 addr.sin_port = htons(DUMMY_PORT); 79 addr.sin_family = AF_INET; 80 start_time = time_get_ns(); 81 for (i = 0; i < MAX_CNT; i++) { 82 if (sendto(fd, buf, strlen(buf), 0, 83 (struct sockaddr *)&addr, sizeof(addr)) < 0) { 84 printf("failed to start ping: %s\n", strerror(errno)); 85 close(fd); 86 return; 87 } 88 } 89 printf("fib_table_lookup:%d: %lld events per sec\n", 90 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 91 close(fd); 92 } 93 94 static void loop(int cpu, int flags) 95 { 96 cpu_set_t cpuset; 97 98 CPU_ZERO(&cpuset); 99 CPU_SET(cpu, &cpuset); 100 sched_setaffinity(0, sizeof(cpuset), &cpuset); 101 102 if (flags & 1) 103 test_task_rename(cpu); 104 if (flags & 2) 105 test_fib_table_lookup(cpu); 106 } 107 108 static void run_perf_test(int tasks, int flags) 109 { 110 pid_t pid[tasks]; 111 int i; 112 113 for (i = 0; i < tasks; i++) { 114 pid[i] = fork(); 115 if (pid[i] == 0) { 116 loop(i, flags); 117 exit(0); 118 } else if (pid[i] == -1) { 119 printf("couldn't spawn #%d process\n", i); 120 exit(1); 121 } 122 } 123 for (i = 0; i < tasks; i++) { 124 int status; 125 126 assert(waitpid(pid[i], &status, 0) == pid[i]); 127 assert(status == 0); 128 } 129 } 130 131 static int load_progs(char *filename) 132 { 133 struct bpf_program *prog; 134 int err = 0; 135 136 obj = bpf_object__open_file(filename, NULL); 137 err = libbpf_get_error(obj); 138 if (err < 0) { 139 fprintf(stderr, "ERROR: opening BPF object file failed\n"); 140 return err; 141 } 142 143 /* load BPF program */ 144 err = bpf_object__load(obj); 145 if (err < 0) { 146 fprintf(stderr, "ERROR: loading BPF object file failed\n"); 147 return err; 148 } 149 150 bpf_object__for_each_program(prog, obj) { 151 links[cnt] = bpf_program__attach(prog); 152 err = libbpf_get_error(links[cnt]); 153 if (err < 0) { 154 fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 155 links[cnt] = NULL; 156 return err; 157 } 158 cnt++; 159 } 160 161 return err; 162 } 163 164 static void unload_progs(void) 165 { 166 while (cnt) 167 bpf_link__destroy(links[--cnt]); 168 169 bpf_object__close(obj); 170 } 171 172 int main(int argc, char **argv) 173 { 174 int num_cpu = sysconf(_SC_NPROCESSORS_ONLN); 175 int test_flags = ~0; 176 char filename[256]; 177 int err = 0; 178 179 180 if (argc > 1) 181 test_flags = atoi(argv[1]) ? : test_flags; 182 if (argc > 2) 183 num_cpu = atoi(argv[2]) ? : num_cpu; 184 185 if (test_flags & 0x3) { 186 printf("BASE\n"); 187 run_perf_test(num_cpu, test_flags); 188 } 189 190 if (test_flags & 0xC) { 191 snprintf(filename, sizeof(filename), 192 "%s_kprobe.bpf.o", argv[0]); 193 194 printf("w/KPROBE\n"); 195 err = load_progs(filename); 196 if (!err) 197 run_perf_test(num_cpu, test_flags >> 2); 198 199 unload_progs(); 200 } 201 202 if (test_flags & 0x30) { 203 snprintf(filename, sizeof(filename), 204 "%s_tp.bpf.o", argv[0]); 205 printf("w/TRACEPOINT\n"); 206 err = load_progs(filename); 207 if (!err) 208 run_perf_test(num_cpu, test_flags >> 4); 209 210 unload_progs(); 211 } 212 213 if (test_flags & 0xC0) { 214 snprintf(filename, sizeof(filename), 215 "%s_raw_tp.bpf.o", argv[0]); 216 printf("w/RAW_TRACEPOINT\n"); 217 err = load_progs(filename); 218 if (!err) 219 run_perf_test(num_cpu, test_flags >> 6); 220 221 unload_progs(); 222 } 223 224 return err; 225 } 226