126e90931SAlexei Starovoitov /* Copyright (c) 2016 Facebook
226e90931SAlexei Starovoitov  *
326e90931SAlexei Starovoitov  * This program is free software; you can redistribute it and/or
426e90931SAlexei Starovoitov  * modify it under the terms of version 2 of the GNU General Public
526e90931SAlexei Starovoitov  * License as published by the Free Software Foundation.
626e90931SAlexei Starovoitov  */
726e90931SAlexei Starovoitov #define _GNU_SOURCE
826e90931SAlexei Starovoitov #include <sched.h>
926e90931SAlexei Starovoitov #include <stdio.h>
1026e90931SAlexei Starovoitov #include <sys/types.h>
1126e90931SAlexei Starovoitov #include <asm/unistd.h>
1226e90931SAlexei Starovoitov #include <unistd.h>
1326e90931SAlexei Starovoitov #include <assert.h>
1426e90931SAlexei Starovoitov #include <sys/wait.h>
1526e90931SAlexei Starovoitov #include <stdlib.h>
1626e90931SAlexei Starovoitov #include <signal.h>
1726e90931SAlexei Starovoitov #include <linux/bpf.h>
1826e90931SAlexei Starovoitov #include <string.h>
1926e90931SAlexei Starovoitov #include <time.h>
2077e63534SNaveen N. Rao #include <sys/resource.h>
2126e90931SAlexei Starovoitov #include "libbpf.h"
2226e90931SAlexei Starovoitov #include "bpf_load.h"
2326e90931SAlexei Starovoitov 
2426e90931SAlexei Starovoitov #define MAX_CNT 1000000
2526e90931SAlexei Starovoitov 
2626e90931SAlexei Starovoitov static __u64 time_get_ns(void)
2726e90931SAlexei Starovoitov {
2826e90931SAlexei Starovoitov 	struct timespec ts;
2926e90931SAlexei Starovoitov 
3026e90931SAlexei Starovoitov 	clock_gettime(CLOCK_MONOTONIC, &ts);
3126e90931SAlexei Starovoitov 	return ts.tv_sec * 1000000000ull + ts.tv_nsec;
3226e90931SAlexei Starovoitov }
3326e90931SAlexei Starovoitov 
3426e90931SAlexei Starovoitov #define HASH_PREALLOC		(1 << 0)
3526e90931SAlexei Starovoitov #define PERCPU_HASH_PREALLOC	(1 << 1)
3626e90931SAlexei Starovoitov #define HASH_KMALLOC		(1 << 2)
3726e90931SAlexei Starovoitov #define PERCPU_HASH_KMALLOC	(1 << 3)
385db58fafSMartin KaFai Lau #define LRU_HASH_PREALLOC	(1 << 4)
395db58fafSMartin KaFai Lau #define PERCPU_LRU_HASH_PREALLOC	(1 << 5)
40b8a943e2SDavid Herrmann #define LPM_KMALLOC		(1 << 6)
41*95ff141eSAlexei Starovoitov #define HASH_LOOKUP		(1 << 7)
42*95ff141eSAlexei Starovoitov #define ARRAY_LOOKUP		(1 << 8)
4326e90931SAlexei Starovoitov 
4426e90931SAlexei Starovoitov static int test_flags = ~0;
4526e90931SAlexei Starovoitov 
4626e90931SAlexei Starovoitov static void test_hash_prealloc(int cpu)
4726e90931SAlexei Starovoitov {
4826e90931SAlexei Starovoitov 	__u64 start_time;
4926e90931SAlexei Starovoitov 	int i;
5026e90931SAlexei Starovoitov 
5126e90931SAlexei Starovoitov 	start_time = time_get_ns();
5226e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
5326e90931SAlexei Starovoitov 		syscall(__NR_getuid);
5426e90931SAlexei Starovoitov 	printf("%d:hash_map_perf pre-alloc %lld events per sec\n",
5526e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
5626e90931SAlexei Starovoitov }
5726e90931SAlexei Starovoitov 
585db58fafSMartin KaFai Lau static void test_lru_hash_prealloc(int cpu)
595db58fafSMartin KaFai Lau {
605db58fafSMartin KaFai Lau 	__u64 start_time;
615db58fafSMartin KaFai Lau 	int i;
625db58fafSMartin KaFai Lau 
635db58fafSMartin KaFai Lau 	start_time = time_get_ns();
645db58fafSMartin KaFai Lau 	for (i = 0; i < MAX_CNT; i++)
655db58fafSMartin KaFai Lau 		syscall(__NR_getpid);
665db58fafSMartin KaFai Lau 	printf("%d:lru_hash_map_perf pre-alloc %lld events per sec\n",
675db58fafSMartin KaFai Lau 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
685db58fafSMartin KaFai Lau }
695db58fafSMartin KaFai Lau 
705db58fafSMartin KaFai Lau static void test_percpu_lru_hash_prealloc(int cpu)
715db58fafSMartin KaFai Lau {
725db58fafSMartin KaFai Lau 	__u64 start_time;
735db58fafSMartin KaFai Lau 	int i;
745db58fafSMartin KaFai Lau 
755db58fafSMartin KaFai Lau 	start_time = time_get_ns();
765db58fafSMartin KaFai Lau 	for (i = 0; i < MAX_CNT; i++)
775db58fafSMartin KaFai Lau 		syscall(__NR_getppid);
785db58fafSMartin KaFai Lau 	printf("%d:lru_hash_map_perf pre-alloc %lld events per sec\n",
795db58fafSMartin KaFai Lau 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
805db58fafSMartin KaFai Lau }
815db58fafSMartin KaFai Lau 
8226e90931SAlexei Starovoitov static void test_percpu_hash_prealloc(int cpu)
8326e90931SAlexei Starovoitov {
8426e90931SAlexei Starovoitov 	__u64 start_time;
8526e90931SAlexei Starovoitov 	int i;
8626e90931SAlexei Starovoitov 
8726e90931SAlexei Starovoitov 	start_time = time_get_ns();
8826e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
8926e90931SAlexei Starovoitov 		syscall(__NR_geteuid);
9026e90931SAlexei Starovoitov 	printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n",
9126e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
9226e90931SAlexei Starovoitov }
9326e90931SAlexei Starovoitov 
9426e90931SAlexei Starovoitov static void test_hash_kmalloc(int cpu)
9526e90931SAlexei Starovoitov {
9626e90931SAlexei Starovoitov 	__u64 start_time;
9726e90931SAlexei Starovoitov 	int i;
9826e90931SAlexei Starovoitov 
9926e90931SAlexei Starovoitov 	start_time = time_get_ns();
10026e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
10126e90931SAlexei Starovoitov 		syscall(__NR_getgid);
10226e90931SAlexei Starovoitov 	printf("%d:hash_map_perf kmalloc %lld events per sec\n",
10326e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
10426e90931SAlexei Starovoitov }
10526e90931SAlexei Starovoitov 
10626e90931SAlexei Starovoitov static void test_percpu_hash_kmalloc(int cpu)
10726e90931SAlexei Starovoitov {
10826e90931SAlexei Starovoitov 	__u64 start_time;
10926e90931SAlexei Starovoitov 	int i;
11026e90931SAlexei Starovoitov 
11126e90931SAlexei Starovoitov 	start_time = time_get_ns();
11226e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
11326e90931SAlexei Starovoitov 		syscall(__NR_getegid);
11426e90931SAlexei Starovoitov 	printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n",
11526e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
11626e90931SAlexei Starovoitov }
11726e90931SAlexei Starovoitov 
118b8a943e2SDavid Herrmann static void test_lpm_kmalloc(int cpu)
119b8a943e2SDavid Herrmann {
120b8a943e2SDavid Herrmann 	__u64 start_time;
121b8a943e2SDavid Herrmann 	int i;
122b8a943e2SDavid Herrmann 
123b8a943e2SDavid Herrmann 	start_time = time_get_ns();
124b8a943e2SDavid Herrmann 	for (i = 0; i < MAX_CNT; i++)
125b8a943e2SDavid Herrmann 		syscall(__NR_gettid);
126b8a943e2SDavid Herrmann 	printf("%d:lpm_perf kmalloc %lld events per sec\n",
127b8a943e2SDavid Herrmann 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
128b8a943e2SDavid Herrmann }
129b8a943e2SDavid Herrmann 
130*95ff141eSAlexei Starovoitov static void test_hash_lookup(int cpu)
131*95ff141eSAlexei Starovoitov {
132*95ff141eSAlexei Starovoitov 	__u64 start_time;
133*95ff141eSAlexei Starovoitov 	int i;
134*95ff141eSAlexei Starovoitov 
135*95ff141eSAlexei Starovoitov 	start_time = time_get_ns();
136*95ff141eSAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
137*95ff141eSAlexei Starovoitov 		syscall(__NR_getpgid, 0);
138*95ff141eSAlexei Starovoitov 	printf("%d:hash_lookup %lld lookups per sec\n",
139*95ff141eSAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll * 64 / (time_get_ns() - start_time));
140*95ff141eSAlexei Starovoitov }
141*95ff141eSAlexei Starovoitov 
142*95ff141eSAlexei Starovoitov static void test_array_lookup(int cpu)
143*95ff141eSAlexei Starovoitov {
144*95ff141eSAlexei Starovoitov 	__u64 start_time;
145*95ff141eSAlexei Starovoitov 	int i;
146*95ff141eSAlexei Starovoitov 
147*95ff141eSAlexei Starovoitov 	start_time = time_get_ns();
148*95ff141eSAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
149*95ff141eSAlexei Starovoitov 		syscall(__NR_getpgrp, 0);
150*95ff141eSAlexei Starovoitov 	printf("%d:array_lookup %lld lookups per sec\n",
151*95ff141eSAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll * 64 / (time_get_ns() - start_time));
152*95ff141eSAlexei Starovoitov }
153*95ff141eSAlexei Starovoitov 
15426e90931SAlexei Starovoitov static void loop(int cpu)
15526e90931SAlexei Starovoitov {
15626e90931SAlexei Starovoitov 	cpu_set_t cpuset;
15726e90931SAlexei Starovoitov 
15826e90931SAlexei Starovoitov 	CPU_ZERO(&cpuset);
15926e90931SAlexei Starovoitov 	CPU_SET(cpu, &cpuset);
16026e90931SAlexei Starovoitov 	sched_setaffinity(0, sizeof(cpuset), &cpuset);
16126e90931SAlexei Starovoitov 
16226e90931SAlexei Starovoitov 	if (test_flags & HASH_PREALLOC)
16326e90931SAlexei Starovoitov 		test_hash_prealloc(cpu);
16426e90931SAlexei Starovoitov 
16526e90931SAlexei Starovoitov 	if (test_flags & PERCPU_HASH_PREALLOC)
16626e90931SAlexei Starovoitov 		test_percpu_hash_prealloc(cpu);
16726e90931SAlexei Starovoitov 
16826e90931SAlexei Starovoitov 	if (test_flags & HASH_KMALLOC)
16926e90931SAlexei Starovoitov 		test_hash_kmalloc(cpu);
17026e90931SAlexei Starovoitov 
17126e90931SAlexei Starovoitov 	if (test_flags & PERCPU_HASH_KMALLOC)
17226e90931SAlexei Starovoitov 		test_percpu_hash_kmalloc(cpu);
1735db58fafSMartin KaFai Lau 
1745db58fafSMartin KaFai Lau 	if (test_flags & LRU_HASH_PREALLOC)
1755db58fafSMartin KaFai Lau 		test_lru_hash_prealloc(cpu);
1765db58fafSMartin KaFai Lau 
1775db58fafSMartin KaFai Lau 	if (test_flags & PERCPU_LRU_HASH_PREALLOC)
1785db58fafSMartin KaFai Lau 		test_percpu_lru_hash_prealloc(cpu);
179b8a943e2SDavid Herrmann 
180b8a943e2SDavid Herrmann 	if (test_flags & LPM_KMALLOC)
181b8a943e2SDavid Herrmann 		test_lpm_kmalloc(cpu);
182*95ff141eSAlexei Starovoitov 
183*95ff141eSAlexei Starovoitov 	if (test_flags & HASH_LOOKUP)
184*95ff141eSAlexei Starovoitov 		test_hash_lookup(cpu);
185*95ff141eSAlexei Starovoitov 
186*95ff141eSAlexei Starovoitov 	if (test_flags & ARRAY_LOOKUP)
187*95ff141eSAlexei Starovoitov 		test_array_lookup(cpu);
18826e90931SAlexei Starovoitov }
18926e90931SAlexei Starovoitov 
19026e90931SAlexei Starovoitov static void run_perf_test(int tasks)
19126e90931SAlexei Starovoitov {
19226e90931SAlexei Starovoitov 	pid_t pid[tasks];
19326e90931SAlexei Starovoitov 	int i;
19426e90931SAlexei Starovoitov 
19526e90931SAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
19626e90931SAlexei Starovoitov 		pid[i] = fork();
19726e90931SAlexei Starovoitov 		if (pid[i] == 0) {
19826e90931SAlexei Starovoitov 			loop(i);
19926e90931SAlexei Starovoitov 			exit(0);
20026e90931SAlexei Starovoitov 		} else if (pid[i] == -1) {
20126e90931SAlexei Starovoitov 			printf("couldn't spawn #%d process\n", i);
20226e90931SAlexei Starovoitov 			exit(1);
20326e90931SAlexei Starovoitov 		}
20426e90931SAlexei Starovoitov 	}
20526e90931SAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
20626e90931SAlexei Starovoitov 		int status;
20726e90931SAlexei Starovoitov 
20826e90931SAlexei Starovoitov 		assert(waitpid(pid[i], &status, 0) == pid[i]);
20926e90931SAlexei Starovoitov 		assert(status == 0);
21026e90931SAlexei Starovoitov 	}
21126e90931SAlexei Starovoitov }
21226e90931SAlexei Starovoitov 
213b8a943e2SDavid Herrmann static void fill_lpm_trie(void)
214b8a943e2SDavid Herrmann {
215b8a943e2SDavid Herrmann 	struct bpf_lpm_trie_key *key;
216b8a943e2SDavid Herrmann 	unsigned long value = 0;
217b8a943e2SDavid Herrmann 	unsigned int i;
218b8a943e2SDavid Herrmann 	int r;
219b8a943e2SDavid Herrmann 
220b8a943e2SDavid Herrmann 	key = alloca(sizeof(*key) + 4);
221b8a943e2SDavid Herrmann 	key->prefixlen = 32;
222b8a943e2SDavid Herrmann 
223b8a943e2SDavid Herrmann 	for (i = 0; i < 512; ++i) {
224b8a943e2SDavid Herrmann 		key->prefixlen = rand() % 33;
225b8a943e2SDavid Herrmann 		key->data[0] = rand() & 0xff;
226b8a943e2SDavid Herrmann 		key->data[1] = rand() & 0xff;
227b8a943e2SDavid Herrmann 		key->data[2] = rand() & 0xff;
228b8a943e2SDavid Herrmann 		key->data[3] = rand() & 0xff;
229b8a943e2SDavid Herrmann 		r = bpf_map_update_elem(map_fd[6], key, &value, 0);
230b8a943e2SDavid Herrmann 		assert(!r);
231b8a943e2SDavid Herrmann 	}
232b8a943e2SDavid Herrmann 
233b8a943e2SDavid Herrmann 	key->prefixlen = 32;
234b8a943e2SDavid Herrmann 	key->data[0] = 192;
235b8a943e2SDavid Herrmann 	key->data[1] = 168;
236b8a943e2SDavid Herrmann 	key->data[2] = 0;
237b8a943e2SDavid Herrmann 	key->data[3] = 1;
238b8a943e2SDavid Herrmann 	value = 128;
239b8a943e2SDavid Herrmann 
240b8a943e2SDavid Herrmann 	r = bpf_map_update_elem(map_fd[6], key, &value, 0);
241b8a943e2SDavid Herrmann 	assert(!r);
242b8a943e2SDavid Herrmann }
243b8a943e2SDavid Herrmann 
24426e90931SAlexei Starovoitov int main(int argc, char **argv)
24526e90931SAlexei Starovoitov {
24626e90931SAlexei Starovoitov 	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
24726e90931SAlexei Starovoitov 	char filename[256];
24826e90931SAlexei Starovoitov 	int num_cpu = 8;
24926e90931SAlexei Starovoitov 
25026e90931SAlexei Starovoitov 	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
25126e90931SAlexei Starovoitov 	setrlimit(RLIMIT_MEMLOCK, &r);
25226e90931SAlexei Starovoitov 
25326e90931SAlexei Starovoitov 	if (argc > 1)
25426e90931SAlexei Starovoitov 		test_flags = atoi(argv[1]) ? : test_flags;
25526e90931SAlexei Starovoitov 
25626e90931SAlexei Starovoitov 	if (argc > 2)
25726e90931SAlexei Starovoitov 		num_cpu = atoi(argv[2]) ? : num_cpu;
25826e90931SAlexei Starovoitov 
25926e90931SAlexei Starovoitov 	if (load_bpf_file(filename)) {
26026e90931SAlexei Starovoitov 		printf("%s", bpf_log_buf);
26126e90931SAlexei Starovoitov 		return 1;
26226e90931SAlexei Starovoitov 	}
26326e90931SAlexei Starovoitov 
264b8a943e2SDavid Herrmann 	fill_lpm_trie();
265b8a943e2SDavid Herrmann 
26626e90931SAlexei Starovoitov 	run_perf_test(num_cpu);
26726e90931SAlexei Starovoitov 
26826e90931SAlexei Starovoitov 	return 0;
26926e90931SAlexei Starovoitov }
270