xref: /linux/samples/bpf/test_overhead_user.c (revision e04946f5)
125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e3edfdecSAlexei Starovoitov /* Copyright (c) 2016 Facebook
3e3edfdecSAlexei Starovoitov  */
4e3edfdecSAlexei Starovoitov #define _GNU_SOURCE
5e3edfdecSAlexei Starovoitov #include <sched.h>
602a2f000STaeung Song #include <errno.h>
7e3edfdecSAlexei Starovoitov #include <stdio.h>
8e3edfdecSAlexei Starovoitov #include <sys/types.h>
9e3edfdecSAlexei Starovoitov #include <asm/unistd.h>
10e3edfdecSAlexei Starovoitov #include <fcntl.h>
11e3edfdecSAlexei Starovoitov #include <unistd.h>
12e3edfdecSAlexei Starovoitov #include <assert.h>
13e3edfdecSAlexei Starovoitov #include <sys/wait.h>
1458e975d0SDaniel T. Lee #include <sys/socket.h>
1558e975d0SDaniel T. Lee #include <arpa/inet.h>
16e3edfdecSAlexei Starovoitov #include <stdlib.h>
17e3edfdecSAlexei Starovoitov #include <signal.h>
18e3edfdecSAlexei Starovoitov #include <linux/bpf.h>
19e3edfdecSAlexei Starovoitov #include <string.h>
20e3edfdecSAlexei Starovoitov #include <time.h>
212bf3e2efSJakub Kicinski #include <bpf/bpf.h>
22c6497df0SDaniel T. Lee #include <bpf/libbpf.h>
23e3edfdecSAlexei Starovoitov 
24e3edfdecSAlexei Starovoitov #define MAX_CNT 1000000
2558e975d0SDaniel T. Lee #define DUMMY_IP "127.0.0.1"
2658e975d0SDaniel T. Lee #define DUMMY_PORT 80
27e3edfdecSAlexei Starovoitov 
28c6497df0SDaniel T. Lee static struct bpf_link *links[2];
29c6497df0SDaniel T. Lee static struct bpf_object *obj;
30c6497df0SDaniel T. Lee static int cnt;
31c6497df0SDaniel T. Lee 
time_get_ns(void)32e3edfdecSAlexei Starovoitov static __u64 time_get_ns(void)
33e3edfdecSAlexei Starovoitov {
34e3edfdecSAlexei Starovoitov 	struct timespec ts;
35e3edfdecSAlexei Starovoitov 
36e3edfdecSAlexei Starovoitov 	clock_gettime(CLOCK_MONOTONIC, &ts);
37e3edfdecSAlexei Starovoitov 	return ts.tv_sec * 1000000000ull + ts.tv_nsec;
38e3edfdecSAlexei Starovoitov }
39e3edfdecSAlexei Starovoitov 
test_task_rename(int cpu)40e3edfdecSAlexei Starovoitov static void test_task_rename(int cpu)
41e3edfdecSAlexei Starovoitov {
42e3edfdecSAlexei Starovoitov 	char buf[] = "test\n";
4358e975d0SDaniel T. Lee 	__u64 start_time;
44e3edfdecSAlexei Starovoitov 	int i, fd;
45e3edfdecSAlexei Starovoitov 
46e3edfdecSAlexei Starovoitov 	fd = open("/proc/self/comm", O_WRONLY|O_TRUNC);
47e3edfdecSAlexei Starovoitov 	if (fd < 0) {
48e3edfdecSAlexei Starovoitov 		printf("couldn't open /proc\n");
49e3edfdecSAlexei Starovoitov 		exit(1);
50e3edfdecSAlexei Starovoitov 	}
51e3edfdecSAlexei Starovoitov 	start_time = time_get_ns();
5202a2f000STaeung Song 	for (i = 0; i < MAX_CNT; i++) {
5302a2f000STaeung Song 		if (write(fd, buf, sizeof(buf)) < 0) {
5402a2f000STaeung Song 			printf("task rename failed: %s\n", strerror(errno));
5502a2f000STaeung Song 			close(fd);
5602a2f000STaeung Song 			return;
5702a2f000STaeung Song 		}
5802a2f000STaeung Song 	}
59e3edfdecSAlexei Starovoitov 	printf("task_rename:%d: %lld events per sec\n",
60e3edfdecSAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
61e3edfdecSAlexei Starovoitov 	close(fd);
62e3edfdecSAlexei Starovoitov }
63e3edfdecSAlexei Starovoitov 
test_fib_table_lookup(int cpu)6458e975d0SDaniel T. Lee static void test_fib_table_lookup(int cpu)
65e3edfdecSAlexei Starovoitov {
6658e975d0SDaniel T. Lee 	struct sockaddr_in addr;
6758e975d0SDaniel T. Lee 	char buf[] = "test\n";
68e3edfdecSAlexei Starovoitov 	__u64 start_time;
69e3edfdecSAlexei Starovoitov 	int i, fd;
70e3edfdecSAlexei Starovoitov 
7158e975d0SDaniel T. Lee 	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
72e3edfdecSAlexei Starovoitov 	if (fd < 0) {
7358e975d0SDaniel T. Lee 		printf("couldn't open socket\n");
74e3edfdecSAlexei Starovoitov 		exit(1);
75e3edfdecSAlexei Starovoitov 	}
7658e975d0SDaniel T. Lee 	memset((char *)&addr, 0, sizeof(addr));
7758e975d0SDaniel T. Lee 	addr.sin_addr.s_addr = inet_addr(DUMMY_IP);
7858e975d0SDaniel T. Lee 	addr.sin_port = htons(DUMMY_PORT);
7958e975d0SDaniel T. Lee 	addr.sin_family = AF_INET;
80e3edfdecSAlexei Starovoitov 	start_time = time_get_ns();
8102a2f000STaeung Song 	for (i = 0; i < MAX_CNT; i++) {
8258e975d0SDaniel T. Lee 		if (sendto(fd, buf, strlen(buf), 0,
8358e975d0SDaniel T. Lee 			   (struct sockaddr *)&addr, sizeof(addr)) < 0) {
8458e975d0SDaniel T. Lee 			printf("failed to start ping: %s\n", strerror(errno));
8502a2f000STaeung Song 			close(fd);
8602a2f000STaeung Song 			return;
8702a2f000STaeung Song 		}
8802a2f000STaeung Song 	}
8958e975d0SDaniel T. Lee 	printf("fib_table_lookup:%d: %lld events per sec\n",
90e3edfdecSAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
91e3edfdecSAlexei Starovoitov 	close(fd);
92e3edfdecSAlexei Starovoitov }
93e3edfdecSAlexei Starovoitov 
loop(int cpu,int flags)94e3edfdecSAlexei Starovoitov static void loop(int cpu, int flags)
95e3edfdecSAlexei Starovoitov {
96e3edfdecSAlexei Starovoitov 	cpu_set_t cpuset;
97e3edfdecSAlexei Starovoitov 
98e3edfdecSAlexei Starovoitov 	CPU_ZERO(&cpuset);
99e3edfdecSAlexei Starovoitov 	CPU_SET(cpu, &cpuset);
100e3edfdecSAlexei Starovoitov 	sched_setaffinity(0, sizeof(cpuset), &cpuset);
101e3edfdecSAlexei Starovoitov 
102e3edfdecSAlexei Starovoitov 	if (flags & 1)
103e3edfdecSAlexei Starovoitov 		test_task_rename(cpu);
104e3edfdecSAlexei Starovoitov 	if (flags & 2)
10558e975d0SDaniel T. Lee 		test_fib_table_lookup(cpu);
106e3edfdecSAlexei Starovoitov }
107e3edfdecSAlexei Starovoitov 
run_perf_test(int tasks,int flags)108e3edfdecSAlexei Starovoitov static void run_perf_test(int tasks, int flags)
109e3edfdecSAlexei Starovoitov {
110e3edfdecSAlexei Starovoitov 	pid_t pid[tasks];
111e3edfdecSAlexei Starovoitov 	int i;
112e3edfdecSAlexei Starovoitov 
113e3edfdecSAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
114e3edfdecSAlexei Starovoitov 		pid[i] = fork();
115e3edfdecSAlexei Starovoitov 		if (pid[i] == 0) {
116e3edfdecSAlexei Starovoitov 			loop(i, flags);
117e3edfdecSAlexei Starovoitov 			exit(0);
118e3edfdecSAlexei Starovoitov 		} else if (pid[i] == -1) {
119e3edfdecSAlexei Starovoitov 			printf("couldn't spawn #%d process\n", i);
120e3edfdecSAlexei Starovoitov 			exit(1);
121e3edfdecSAlexei Starovoitov 		}
122e3edfdecSAlexei Starovoitov 	}
123e3edfdecSAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
124e3edfdecSAlexei Starovoitov 		int status;
125e3edfdecSAlexei Starovoitov 
126e3edfdecSAlexei Starovoitov 		assert(waitpid(pid[i], &status, 0) == pid[i]);
127e3edfdecSAlexei Starovoitov 		assert(status == 0);
128e3edfdecSAlexei Starovoitov 	}
129e3edfdecSAlexei Starovoitov }
130e3edfdecSAlexei Starovoitov 
load_progs(char * filename)131c6497df0SDaniel T. Lee static int load_progs(char *filename)
132c6497df0SDaniel T. Lee {
133c6497df0SDaniel T. Lee 	struct bpf_program *prog;
134c6497df0SDaniel T. Lee 	int err = 0;
135c6497df0SDaniel T. Lee 
136c6497df0SDaniel T. Lee 	obj = bpf_object__open_file(filename, NULL);
137c6497df0SDaniel T. Lee 	err = libbpf_get_error(obj);
138c6497df0SDaniel T. Lee 	if (err < 0) {
139c6497df0SDaniel T. Lee 		fprintf(stderr, "ERROR: opening BPF object file failed\n");
140c6497df0SDaniel T. Lee 		return err;
141c6497df0SDaniel T. Lee 	}
142c6497df0SDaniel T. Lee 
143c6497df0SDaniel T. Lee 	/* load BPF program */
144c6497df0SDaniel T. Lee 	err = bpf_object__load(obj);
145c6497df0SDaniel T. Lee 	if (err < 0) {
146c6497df0SDaniel T. Lee 		fprintf(stderr, "ERROR: loading BPF object file failed\n");
147c6497df0SDaniel T. Lee 		return err;
148c6497df0SDaniel T. Lee 	}
149c6497df0SDaniel T. Lee 
150c6497df0SDaniel T. Lee 	bpf_object__for_each_program(prog, obj) {
151c6497df0SDaniel T. Lee 		links[cnt] = bpf_program__attach(prog);
152c6497df0SDaniel T. Lee 		err = libbpf_get_error(links[cnt]);
153c6497df0SDaniel T. Lee 		if (err < 0) {
154c6497df0SDaniel T. Lee 			fprintf(stderr, "ERROR: bpf_program__attach failed\n");
155c6497df0SDaniel T. Lee 			links[cnt] = NULL;
156c6497df0SDaniel T. Lee 			return err;
157c6497df0SDaniel T. Lee 		}
158c6497df0SDaniel T. Lee 		cnt++;
159c6497df0SDaniel T. Lee 	}
160c6497df0SDaniel T. Lee 
161c6497df0SDaniel T. Lee 	return err;
162c6497df0SDaniel T. Lee }
163c6497df0SDaniel T. Lee 
unload_progs(void)164e3edfdecSAlexei Starovoitov static void unload_progs(void)
165e3edfdecSAlexei Starovoitov {
166c6497df0SDaniel T. Lee 	while (cnt)
167c6497df0SDaniel T. Lee 		bpf_link__destroy(links[--cnt]);
168c6497df0SDaniel T. Lee 
169c6497df0SDaniel T. Lee 	bpf_object__close(obj);
170e3edfdecSAlexei Starovoitov }
171e3edfdecSAlexei Starovoitov 
main(int argc,char ** argv)172e3edfdecSAlexei Starovoitov int main(int argc, char **argv)
173e3edfdecSAlexei Starovoitov {
174c6497df0SDaniel T. Lee 	int num_cpu = sysconf(_SC_NPROCESSORS_ONLN);
175e3edfdecSAlexei Starovoitov 	int test_flags = ~0;
176c6497df0SDaniel T. Lee 	char filename[256];
177c6497df0SDaniel T. Lee 	int err = 0;
178e3edfdecSAlexei Starovoitov 
179e3edfdecSAlexei Starovoitov 
180e3edfdecSAlexei Starovoitov 	if (argc > 1)
181e3edfdecSAlexei Starovoitov 		test_flags = atoi(argv[1]) ? : test_flags;
182e3edfdecSAlexei Starovoitov 	if (argc > 2)
183e3edfdecSAlexei Starovoitov 		num_cpu = atoi(argv[2]) ? : num_cpu;
184e3edfdecSAlexei Starovoitov 
185e3edfdecSAlexei Starovoitov 	if (test_flags & 0x3) {
186e3edfdecSAlexei Starovoitov 		printf("BASE\n");
187e3edfdecSAlexei Starovoitov 		run_perf_test(num_cpu, test_flags);
188e3edfdecSAlexei Starovoitov 	}
189e3edfdecSAlexei Starovoitov 
190e3edfdecSAlexei Starovoitov 	if (test_flags & 0xC) {
191e3edfdecSAlexei Starovoitov 		snprintf(filename, sizeof(filename),
192*e04946f5SDaniel T. Lee 			 "%s_kprobe.bpf.o", argv[0]);
193c6497df0SDaniel T. Lee 
194e3edfdecSAlexei Starovoitov 		printf("w/KPROBE\n");
195c6497df0SDaniel T. Lee 		err = load_progs(filename);
196c6497df0SDaniel T. Lee 		if (!err)
197e3edfdecSAlexei Starovoitov 			run_perf_test(num_cpu, test_flags >> 2);
198c6497df0SDaniel T. Lee 
199e3edfdecSAlexei Starovoitov 		unload_progs();
200e3edfdecSAlexei Starovoitov 	}
201e3edfdecSAlexei Starovoitov 
202e3edfdecSAlexei Starovoitov 	if (test_flags & 0x30) {
203e3edfdecSAlexei Starovoitov 		snprintf(filename, sizeof(filename),
204*e04946f5SDaniel T. Lee 			 "%s_tp.bpf.o", argv[0]);
205e3edfdecSAlexei Starovoitov 		printf("w/TRACEPOINT\n");
206c6497df0SDaniel T. Lee 		err = load_progs(filename);
207c6497df0SDaniel T. Lee 		if (!err)
208e3edfdecSAlexei Starovoitov 			run_perf_test(num_cpu, test_flags >> 4);
209c6497df0SDaniel T. Lee 
210e3edfdecSAlexei Starovoitov 		unload_progs();
211e3edfdecSAlexei Starovoitov 	}
212e3edfdecSAlexei Starovoitov 
2134662a4e5SAlexei Starovoitov 	if (test_flags & 0xC0) {
2144662a4e5SAlexei Starovoitov 		snprintf(filename, sizeof(filename),
215*e04946f5SDaniel T. Lee 			 "%s_raw_tp.bpf.o", argv[0]);
2164662a4e5SAlexei Starovoitov 		printf("w/RAW_TRACEPOINT\n");
217c6497df0SDaniel T. Lee 		err = load_progs(filename);
218c6497df0SDaniel T. Lee 		if (!err)
2194662a4e5SAlexei Starovoitov 			run_perf_test(num_cpu, test_flags >> 6);
220c6497df0SDaniel T. Lee 
2214662a4e5SAlexei Starovoitov 		unload_progs();
2224662a4e5SAlexei Starovoitov 	}
2234662a4e5SAlexei Starovoitov 
224c6497df0SDaniel T. Lee 	return err;
225e3edfdecSAlexei Starovoitov }
226