162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright (c) 2016 Facebook 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci#define _GNU_SOURCE 562306a36Sopenharmony_ci#include <sched.h> 662306a36Sopenharmony_ci#include <errno.h> 762306a36Sopenharmony_ci#include <stdio.h> 862306a36Sopenharmony_ci#include <sys/types.h> 962306a36Sopenharmony_ci#include <asm/unistd.h> 1062306a36Sopenharmony_ci#include <fcntl.h> 1162306a36Sopenharmony_ci#include <unistd.h> 1262306a36Sopenharmony_ci#include <assert.h> 1362306a36Sopenharmony_ci#include <sys/wait.h> 1462306a36Sopenharmony_ci#include <sys/socket.h> 1562306a36Sopenharmony_ci#include <arpa/inet.h> 1662306a36Sopenharmony_ci#include <stdlib.h> 1762306a36Sopenharmony_ci#include <signal.h> 1862306a36Sopenharmony_ci#include <linux/bpf.h> 1962306a36Sopenharmony_ci#include <string.h> 2062306a36Sopenharmony_ci#include <time.h> 2162306a36Sopenharmony_ci#include <bpf/bpf.h> 2262306a36Sopenharmony_ci#include <bpf/libbpf.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define MAX_CNT 1000000 2562306a36Sopenharmony_ci#define DUMMY_IP "127.0.0.1" 2662306a36Sopenharmony_ci#define DUMMY_PORT 80 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic struct bpf_link *links[2]; 2962306a36Sopenharmony_cistatic struct bpf_object *obj; 3062306a36Sopenharmony_cistatic int cnt; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic __u64 time_get_ns(void) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct timespec ts; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &ts); 3762306a36Sopenharmony_ci return ts.tv_sec * 1000000000ull + ts.tv_nsec; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void test_task_rename(int cpu) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci char buf[] = "test\n"; 4362306a36Sopenharmony_ci __u64 start_time; 4462306a36Sopenharmony_ci int i, fd; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci fd = open("/proc/self/comm", O_WRONLY|O_TRUNC); 4762306a36Sopenharmony_ci if (fd < 0) { 4862306a36Sopenharmony_ci printf("couldn't open /proc\n"); 4962306a36Sopenharmony_ci exit(1); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci start_time = time_get_ns(); 5262306a36Sopenharmony_ci for (i = 0; i < MAX_CNT; i++) { 5362306a36Sopenharmony_ci if (write(fd, buf, sizeof(buf)) < 0) { 5462306a36Sopenharmony_ci printf("task rename failed: %s\n", strerror(errno)); 5562306a36Sopenharmony_ci close(fd); 5662306a36Sopenharmony_ci return; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci printf("task_rename:%d: %lld events per sec\n", 6062306a36Sopenharmony_ci cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 6162306a36Sopenharmony_ci close(fd); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void test_fib_table_lookup(int cpu) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct sockaddr_in addr; 6762306a36Sopenharmony_ci char buf[] = "test\n"; 6862306a36Sopenharmony_ci __u64 start_time; 6962306a36Sopenharmony_ci int i, fd; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 7262306a36Sopenharmony_ci if (fd < 0) { 7362306a36Sopenharmony_ci printf("couldn't open socket\n"); 7462306a36Sopenharmony_ci exit(1); 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci memset((char *)&addr, 0, sizeof(addr)); 7762306a36Sopenharmony_ci addr.sin_addr.s_addr = inet_addr(DUMMY_IP); 7862306a36Sopenharmony_ci addr.sin_port = htons(DUMMY_PORT); 7962306a36Sopenharmony_ci addr.sin_family = AF_INET; 8062306a36Sopenharmony_ci start_time = time_get_ns(); 8162306a36Sopenharmony_ci for (i = 0; i < MAX_CNT; i++) { 8262306a36Sopenharmony_ci if (sendto(fd, buf, strlen(buf), 0, 8362306a36Sopenharmony_ci (struct sockaddr *)&addr, sizeof(addr)) < 0) { 8462306a36Sopenharmony_ci printf("failed to start ping: %s\n", strerror(errno)); 8562306a36Sopenharmony_ci close(fd); 8662306a36Sopenharmony_ci return; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci printf("fib_table_lookup:%d: %lld events per sec\n", 9062306a36Sopenharmony_ci cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 9162306a36Sopenharmony_ci close(fd); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic void loop(int cpu, int flags) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci cpu_set_t cpuset; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci CPU_ZERO(&cpuset); 9962306a36Sopenharmony_ci CPU_SET(cpu, &cpuset); 10062306a36Sopenharmony_ci sched_setaffinity(0, sizeof(cpuset), &cpuset); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (flags & 1) 10362306a36Sopenharmony_ci test_task_rename(cpu); 10462306a36Sopenharmony_ci if (flags & 2) 10562306a36Sopenharmony_ci test_fib_table_lookup(cpu); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic void run_perf_test(int tasks, int flags) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci pid_t pid[tasks]; 11162306a36Sopenharmony_ci int i; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci for (i = 0; i < tasks; i++) { 11462306a36Sopenharmony_ci pid[i] = fork(); 11562306a36Sopenharmony_ci if (pid[i] == 0) { 11662306a36Sopenharmony_ci loop(i, flags); 11762306a36Sopenharmony_ci exit(0); 11862306a36Sopenharmony_ci } else if (pid[i] == -1) { 11962306a36Sopenharmony_ci printf("couldn't spawn #%d process\n", i); 12062306a36Sopenharmony_ci exit(1); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci for (i = 0; i < tasks; i++) { 12462306a36Sopenharmony_ci int status; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci assert(waitpid(pid[i], &status, 0) == pid[i]); 12762306a36Sopenharmony_ci assert(status == 0); 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int load_progs(char *filename) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct bpf_program *prog; 13462306a36Sopenharmony_ci int err = 0; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci obj = bpf_object__open_file(filename, NULL); 13762306a36Sopenharmony_ci err = libbpf_get_error(obj); 13862306a36Sopenharmony_ci if (err < 0) { 13962306a36Sopenharmony_ci fprintf(stderr, "ERROR: opening BPF object file failed\n"); 14062306a36Sopenharmony_ci return err; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* load BPF program */ 14462306a36Sopenharmony_ci err = bpf_object__load(obj); 14562306a36Sopenharmony_ci if (err < 0) { 14662306a36Sopenharmony_ci fprintf(stderr, "ERROR: loading BPF object file failed\n"); 14762306a36Sopenharmony_ci return err; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci bpf_object__for_each_program(prog, obj) { 15162306a36Sopenharmony_ci links[cnt] = bpf_program__attach(prog); 15262306a36Sopenharmony_ci err = libbpf_get_error(links[cnt]); 15362306a36Sopenharmony_ci if (err < 0) { 15462306a36Sopenharmony_ci fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 15562306a36Sopenharmony_ci links[cnt] = NULL; 15662306a36Sopenharmony_ci return err; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci cnt++; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return err; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void unload_progs(void) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci while (cnt) 16762306a36Sopenharmony_ci bpf_link__destroy(links[--cnt]); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci bpf_object__close(obj); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ciint main(int argc, char **argv) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci int num_cpu = sysconf(_SC_NPROCESSORS_ONLN); 17562306a36Sopenharmony_ci int test_flags = ~0; 17662306a36Sopenharmony_ci char filename[256]; 17762306a36Sopenharmony_ci int err = 0; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (argc > 1) 18162306a36Sopenharmony_ci test_flags = atoi(argv[1]) ? : test_flags; 18262306a36Sopenharmony_ci if (argc > 2) 18362306a36Sopenharmony_ci num_cpu = atoi(argv[2]) ? : num_cpu; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (test_flags & 0x3) { 18662306a36Sopenharmony_ci printf("BASE\n"); 18762306a36Sopenharmony_ci run_perf_test(num_cpu, test_flags); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (test_flags & 0xC) { 19162306a36Sopenharmony_ci snprintf(filename, sizeof(filename), 19262306a36Sopenharmony_ci "%s_kprobe.bpf.o", argv[0]); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci printf("w/KPROBE\n"); 19562306a36Sopenharmony_ci err = load_progs(filename); 19662306a36Sopenharmony_ci if (!err) 19762306a36Sopenharmony_ci run_perf_test(num_cpu, test_flags >> 2); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci unload_progs(); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (test_flags & 0x30) { 20362306a36Sopenharmony_ci snprintf(filename, sizeof(filename), 20462306a36Sopenharmony_ci "%s_tp.bpf.o", argv[0]); 20562306a36Sopenharmony_ci printf("w/TRACEPOINT\n"); 20662306a36Sopenharmony_ci err = load_progs(filename); 20762306a36Sopenharmony_ci if (!err) 20862306a36Sopenharmony_ci run_perf_test(num_cpu, test_flags >> 4); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci unload_progs(); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (test_flags & 0xC0) { 21462306a36Sopenharmony_ci snprintf(filename, sizeof(filename), 21562306a36Sopenharmony_ci "%s_raw_tp.bpf.o", argv[0]); 21662306a36Sopenharmony_ci printf("w/RAW_TRACEPOINT\n"); 21762306a36Sopenharmony_ci err = load_progs(filename); 21862306a36Sopenharmony_ci if (!err) 21962306a36Sopenharmony_ci run_perf_test(num_cpu, test_flags >> 6); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci unload_progs(); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return err; 22562306a36Sopenharmony_ci} 226