125763b3cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
226e90931SAlexei Starovoitov /* Copyright (c) 2016 Facebook
326e90931SAlexei Starovoitov  */
426e90931SAlexei Starovoitov #define _GNU_SOURCE
526e90931SAlexei Starovoitov #include <sched.h>
626e90931SAlexei Starovoitov #include <stdio.h>
726e90931SAlexei Starovoitov #include <sys/types.h>
826e90931SAlexei Starovoitov #include <asm/unistd.h>
926e90931SAlexei Starovoitov #include <unistd.h>
1026e90931SAlexei Starovoitov #include <assert.h>
1126e90931SAlexei Starovoitov #include <sys/wait.h>
1226e90931SAlexei Starovoitov #include <stdlib.h>
1326e90931SAlexei Starovoitov #include <signal.h>
1426e90931SAlexei Starovoitov #include <string.h>
1526e90931SAlexei Starovoitov #include <time.h>
16bf8db5d2SMartin KaFai Lau #include <arpa/inet.h>
17bf8db5d2SMartin KaFai Lau #include <errno.h>
18bf8db5d2SMartin KaFai Lau 
192bf3e2efSJakub Kicinski #include <bpf/bpf.h>
20cc7f641dSDaniel T. Lee #include <bpf/libbpf.h>
2126e90931SAlexei Starovoitov 
229fd63d05SMartin KaFai Lau #define TEST_BIT(t) (1U << (t))
233a5795b8SMartin KaFai Lau #define MAX_NR_CPUS 1024
2426e90931SAlexei Starovoitov 
2526e90931SAlexei Starovoitov static __u64 time_get_ns(void)
2626e90931SAlexei Starovoitov {
2726e90931SAlexei Starovoitov 	struct timespec ts;
2826e90931SAlexei Starovoitov 
2926e90931SAlexei Starovoitov 	clock_gettime(CLOCK_MONOTONIC, &ts);
3026e90931SAlexei Starovoitov 	return ts.tv_sec * 1000000000ull + ts.tv_nsec;
3126e90931SAlexei Starovoitov }
3226e90931SAlexei Starovoitov 
339fd63d05SMartin KaFai Lau enum test_type {
349fd63d05SMartin KaFai Lau 	HASH_PREALLOC,
359fd63d05SMartin KaFai Lau 	PERCPU_HASH_PREALLOC,
369fd63d05SMartin KaFai Lau 	HASH_KMALLOC,
379fd63d05SMartin KaFai Lau 	PERCPU_HASH_KMALLOC,
389fd63d05SMartin KaFai Lau 	LRU_HASH_PREALLOC,
399fd63d05SMartin KaFai Lau 	NOCOMMON_LRU_HASH_PREALLOC,
409fd63d05SMartin KaFai Lau 	LPM_KMALLOC,
419fd63d05SMartin KaFai Lau 	HASH_LOOKUP,
429fd63d05SMartin KaFai Lau 	ARRAY_LOOKUP,
433a5795b8SMartin KaFai Lau 	INNER_LRU_HASH_PREALLOC,
44637cd8c3SMartin KaFai Lau 	LRU_HASH_LOOKUP,
459fd63d05SMartin KaFai Lau 	NR_TESTS,
469fd63d05SMartin KaFai Lau };
479fd63d05SMartin KaFai Lau 
489fd63d05SMartin KaFai Lau const char *test_map_names[NR_TESTS] = {
499fd63d05SMartin KaFai Lau 	[HASH_PREALLOC] = "hash_map",
509fd63d05SMartin KaFai Lau 	[PERCPU_HASH_PREALLOC] = "percpu_hash_map",
519fd63d05SMartin KaFai Lau 	[HASH_KMALLOC] = "hash_map_alloc",
529fd63d05SMartin KaFai Lau 	[PERCPU_HASH_KMALLOC] = "percpu_hash_map_alloc",
539fd63d05SMartin KaFai Lau 	[LRU_HASH_PREALLOC] = "lru_hash_map",
549fd63d05SMartin KaFai Lau 	[NOCOMMON_LRU_HASH_PREALLOC] = "nocommon_lru_hash_map",
559fd63d05SMartin KaFai Lau 	[LPM_KMALLOC] = "lpm_trie_map_alloc",
569fd63d05SMartin KaFai Lau 	[HASH_LOOKUP] = "hash_map",
579fd63d05SMartin KaFai Lau 	[ARRAY_LOOKUP] = "array_map",
583a5795b8SMartin KaFai Lau 	[INNER_LRU_HASH_PREALLOC] = "inner_lru_hash_map",
59637cd8c3SMartin KaFai Lau 	[LRU_HASH_LOOKUP] = "lru_hash_lookup_map",
609fd63d05SMartin KaFai Lau };
6126e90931SAlexei Starovoitov 
62cc7f641dSDaniel T. Lee enum map_idx {
63cc7f641dSDaniel T. Lee 	array_of_lru_hashs_idx,
64cc7f641dSDaniel T. Lee 	hash_map_alloc_idx,
65cc7f641dSDaniel T. Lee 	lru_hash_lookup_idx,
66cc7f641dSDaniel T. Lee 	NR_IDXES,
67cc7f641dSDaniel T. Lee };
68cc7f641dSDaniel T. Lee 
69cc7f641dSDaniel T. Lee static int map_fd[NR_IDXES];
70cc7f641dSDaniel T. Lee 
7126e90931SAlexei Starovoitov static int test_flags = ~0;
729fd63d05SMartin KaFai Lau static uint32_t num_map_entries;
733a5795b8SMartin KaFai Lau static uint32_t inner_lru_hash_size;
74637cd8c3SMartin KaFai Lau static int lru_hash_lookup_test_entries = 32;
7589dc8d0cSAlexei Starovoitov static uint32_t max_cnt = 10000;
769fd63d05SMartin KaFai Lau 
779fd63d05SMartin KaFai Lau static int check_test_flags(enum test_type t)
789fd63d05SMartin KaFai Lau {
799fd63d05SMartin KaFai Lau 	return test_flags & TEST_BIT(t);
809fd63d05SMartin KaFai Lau }
8126e90931SAlexei Starovoitov 
8226e90931SAlexei Starovoitov static void test_hash_prealloc(int cpu)
8326e90931SAlexei Starovoitov {
8426e90931SAlexei Starovoitov 	__u64 start_time;
8526e90931SAlexei Starovoitov 	int i;
8626e90931SAlexei Starovoitov 
8726e90931SAlexei Starovoitov 	start_time = time_get_ns();
889fd63d05SMartin KaFai Lau 	for (i = 0; i < max_cnt; i++)
8926e90931SAlexei Starovoitov 		syscall(__NR_getuid);
9026e90931SAlexei Starovoitov 	printf("%d:hash_map_perf pre-alloc %lld events per sec\n",
919fd63d05SMartin KaFai Lau 	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
9226e90931SAlexei Starovoitov }
9326e90931SAlexei Starovoitov 
94637cd8c3SMartin KaFai Lau static int pre_test_lru_hash_lookup(int tasks)
95637cd8c3SMartin KaFai Lau {
96637cd8c3SMartin KaFai Lau 	int fd = map_fd[lru_hash_lookup_idx];
97637cd8c3SMartin KaFai Lau 	uint32_t key;
98637cd8c3SMartin KaFai Lau 	long val = 1;
99637cd8c3SMartin KaFai Lau 	int ret;
100637cd8c3SMartin KaFai Lau 
101637cd8c3SMartin KaFai Lau 	if (num_map_entries > lru_hash_lookup_test_entries)
102637cd8c3SMartin KaFai Lau 		lru_hash_lookup_test_entries = num_map_entries;
103637cd8c3SMartin KaFai Lau 
104637cd8c3SMartin KaFai Lau 	/* Populate the lru_hash_map for LRU_HASH_LOOKUP perf test.
105637cd8c3SMartin KaFai Lau 	 *
106637cd8c3SMartin KaFai Lau 	 * It is fine that the user requests for a map with
107637cd8c3SMartin KaFai Lau 	 * num_map_entries < 32 and some of the later lru hash lookup
108637cd8c3SMartin KaFai Lau 	 * may return not found.  For LRU map, we are not interested
109637cd8c3SMartin KaFai Lau 	 * in such small map performance.
110637cd8c3SMartin KaFai Lau 	 */
111637cd8c3SMartin KaFai Lau 	for (key = 0; key < lru_hash_lookup_test_entries; key++) {
112637cd8c3SMartin KaFai Lau 		ret = bpf_map_update_elem(fd, &key, &val, BPF_NOEXIST);
113637cd8c3SMartin KaFai Lau 		if (ret)
114637cd8c3SMartin KaFai Lau 			return ret;
115637cd8c3SMartin KaFai Lau 	}
116637cd8c3SMartin KaFai Lau 
117637cd8c3SMartin KaFai Lau 	return 0;
118637cd8c3SMartin KaFai Lau }
119637cd8c3SMartin KaFai Lau 
1209fd63d05SMartin KaFai Lau static void do_test_lru(enum test_type test, int cpu)
1215db58fafSMartin KaFai Lau {
1223a5795b8SMartin KaFai Lau 	static int inner_lru_map_fds[MAX_NR_CPUS];
1233a5795b8SMartin KaFai Lau 
124bf8db5d2SMartin KaFai Lau 	struct sockaddr_in6 in6 = { .sin6_family = AF_INET6 };
125bf8db5d2SMartin KaFai Lau 	const char *test_name;
1265db58fafSMartin KaFai Lau 	__u64 start_time;
127bf8db5d2SMartin KaFai Lau 	int i, ret;
1285db58fafSMartin KaFai Lau 
129cc7f641dSDaniel T. Lee 	if (test == INNER_LRU_HASH_PREALLOC && cpu) {
130cc7f641dSDaniel T. Lee 		/* If CPU is not 0, create inner_lru hash map and insert the fd
131cc7f641dSDaniel T. Lee 		 * value into the array_of_lru_hash map. In case of CPU 0,
132cc7f641dSDaniel T. Lee 		 * 'inner_lru_hash_map' was statically inserted on the map init
133cc7f641dSDaniel T. Lee 		 */
1343a5795b8SMartin KaFai Lau 		int outer_fd = map_fd[array_of_lru_hashs_idx];
135ad17d0e6SMartin KaFai Lau 		unsigned int mycpu, mynode;
136c58f9815SAndrii Nakryiko 		LIBBPF_OPTS(bpf_map_create_opts, opts,
137c58f9815SAndrii Nakryiko 			.map_flags = BPF_F_NUMA_NODE,
138c58f9815SAndrii Nakryiko 		);
1393a5795b8SMartin KaFai Lau 
1403a5795b8SMartin KaFai Lau 		assert(cpu < MAX_NR_CPUS);
1413a5795b8SMartin KaFai Lau 
142ad17d0e6SMartin KaFai Lau 		ret = syscall(__NR_getcpu, &mycpu, &mynode, NULL);
143ad17d0e6SMartin KaFai Lau 		assert(!ret);
144ad17d0e6SMartin KaFai Lau 
145c58f9815SAndrii Nakryiko 		opts.numa_node = mynode;
1463a5795b8SMartin KaFai Lau 		inner_lru_map_fds[cpu] =
147c58f9815SAndrii Nakryiko 			bpf_map_create(BPF_MAP_TYPE_LRU_HASH,
14888cda1c9SMartin KaFai Lau 				       test_map_names[INNER_LRU_HASH_PREALLOC],
149ad17d0e6SMartin KaFai Lau 				       sizeof(uint32_t),
150ad17d0e6SMartin KaFai Lau 				       sizeof(long),
151c58f9815SAndrii Nakryiko 				       inner_lru_hash_size, &opts);
1523a5795b8SMartin KaFai Lau 		if (inner_lru_map_fds[cpu] == -1) {
1533a5795b8SMartin KaFai Lau 			printf("cannot create BPF_MAP_TYPE_LRU_HASH %s(%d)\n",
1543a5795b8SMartin KaFai Lau 			       strerror(errno), errno);
1553a5795b8SMartin KaFai Lau 			exit(1);
1563a5795b8SMartin KaFai Lau 		}
1573a5795b8SMartin KaFai Lau 
1583a5795b8SMartin KaFai Lau 		ret = bpf_map_update_elem(outer_fd, &cpu,
1593a5795b8SMartin KaFai Lau 					  &inner_lru_map_fds[cpu],
1603a5795b8SMartin KaFai Lau 					  BPF_ANY);
1613a5795b8SMartin KaFai Lau 		if (ret) {
1623a5795b8SMartin KaFai Lau 			printf("cannot update ARRAY_OF_LRU_HASHS with key:%u. %s(%d)\n",
1633a5795b8SMartin KaFai Lau 			       cpu, strerror(errno), errno);
1643a5795b8SMartin KaFai Lau 			exit(1);
1653a5795b8SMartin KaFai Lau 		}
1663a5795b8SMartin KaFai Lau 	}
1673a5795b8SMartin KaFai Lau 
168bf8db5d2SMartin KaFai Lau 	in6.sin6_addr.s6_addr16[0] = 0xdead;
169bf8db5d2SMartin KaFai Lau 	in6.sin6_addr.s6_addr16[1] = 0xbeef;
170bf8db5d2SMartin KaFai Lau 
1719fd63d05SMartin KaFai Lau 	if (test == LRU_HASH_PREALLOC) {
172bf8db5d2SMartin KaFai Lau 		test_name = "lru_hash_map_perf";
173637cd8c3SMartin KaFai Lau 		in6.sin6_addr.s6_addr16[2] = 0;
1749fd63d05SMartin KaFai Lau 	} else if (test == NOCOMMON_LRU_HASH_PREALLOC) {
175bf8db5d2SMartin KaFai Lau 		test_name = "nocommon_lru_hash_map_perf";
176637cd8c3SMartin KaFai Lau 		in6.sin6_addr.s6_addr16[2] = 1;
1773a5795b8SMartin KaFai Lau 	} else if (test == INNER_LRU_HASH_PREALLOC) {
1783a5795b8SMartin KaFai Lau 		test_name = "inner_lru_hash_map_perf";
179637cd8c3SMartin KaFai Lau 		in6.sin6_addr.s6_addr16[2] = 2;
180637cd8c3SMartin KaFai Lau 	} else if (test == LRU_HASH_LOOKUP) {
181637cd8c3SMartin KaFai Lau 		test_name = "lru_hash_lookup_perf";
182637cd8c3SMartin KaFai Lau 		in6.sin6_addr.s6_addr16[2] = 3;
183637cd8c3SMartin KaFai Lau 		in6.sin6_addr.s6_addr32[3] = 0;
184bf8db5d2SMartin KaFai Lau 	} else {
185bf8db5d2SMartin KaFai Lau 		assert(0);
1865db58fafSMartin KaFai Lau 	}
1875db58fafSMartin KaFai Lau 
1885db58fafSMartin KaFai Lau 	start_time = time_get_ns();
1899fd63d05SMartin KaFai Lau 	for (i = 0; i < max_cnt; i++) {
190bf8db5d2SMartin KaFai Lau 		ret = connect(-1, (const struct sockaddr *)&in6, sizeof(in6));
191bf8db5d2SMartin KaFai Lau 		assert(ret == -1 && errno == EBADF);
192637cd8c3SMartin KaFai Lau 		if (in6.sin6_addr.s6_addr32[3] <
193637cd8c3SMartin KaFai Lau 		    lru_hash_lookup_test_entries - 32)
194637cd8c3SMartin KaFai Lau 			in6.sin6_addr.s6_addr32[3] += 32;
195637cd8c3SMartin KaFai Lau 		else
196637cd8c3SMartin KaFai Lau 			in6.sin6_addr.s6_addr32[3] = 0;
197bf8db5d2SMartin KaFai Lau 	}
198bf8db5d2SMartin KaFai Lau 	printf("%d:%s pre-alloc %lld events per sec\n",
199bf8db5d2SMartin KaFai Lau 	       cpu, test_name,
2009fd63d05SMartin KaFai Lau 	       max_cnt * 1000000000ll / (time_get_ns() - start_time));
201bf8db5d2SMartin KaFai Lau }
202bf8db5d2SMartin KaFai Lau 
203bf8db5d2SMartin KaFai Lau static void test_lru_hash_prealloc(int cpu)
204bf8db5d2SMartin KaFai Lau {
205bf8db5d2SMartin KaFai Lau 	do_test_lru(LRU_HASH_PREALLOC, cpu);
206bf8db5d2SMartin KaFai Lau }
207bf8db5d2SMartin KaFai Lau 
208bf8db5d2SMartin KaFai Lau static void test_nocommon_lru_hash_prealloc(int cpu)
209bf8db5d2SMartin KaFai Lau {
210bf8db5d2SMartin KaFai Lau 	do_test_lru(NOCOMMON_LRU_HASH_PREALLOC, cpu);
2115db58fafSMartin KaFai Lau }
2125db58fafSMartin KaFai Lau 
2133a5795b8SMartin KaFai Lau static void test_inner_lru_hash_prealloc(int cpu)
2143a5795b8SMartin KaFai Lau {
2153a5795b8SMartin KaFai Lau 	do_test_lru(INNER_LRU_HASH_PREALLOC, cpu);
2163a5795b8SMartin KaFai Lau }
2173a5795b8SMartin KaFai Lau 
218637cd8c3SMartin KaFai Lau static void test_lru_hash_lookup(int cpu)
219637cd8c3SMartin KaFai Lau {
220637cd8c3SMartin KaFai Lau 	do_test_lru(LRU_HASH_LOOKUP, cpu);
221637cd8c3SMartin KaFai Lau }
222637cd8c3SMartin KaFai Lau 
22326e90931SAlexei Starovoitov static void test_percpu_hash_prealloc(int cpu)
22426e90931SAlexei Starovoitov {
22526e90931SAlexei Starovoitov 	__u64 start_time;
22626e90931SAlexei Starovoitov 	int i;
22726e90931SAlexei Starovoitov 
22826e90931SAlexei Starovoitov 	start_time = time_get_ns();
2299fd63d05SMartin KaFai Lau 	for (i = 0; i < max_cnt; i++)
23026e90931SAlexei Starovoitov 		syscall(__NR_geteuid);
23126e90931SAlexei Starovoitov 	printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n",
2329fd63d05SMartin KaFai Lau 	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
23326e90931SAlexei Starovoitov }
23426e90931SAlexei Starovoitov 
23526e90931SAlexei Starovoitov static void test_hash_kmalloc(int cpu)
23626e90931SAlexei Starovoitov {
23726e90931SAlexei Starovoitov 	__u64 start_time;
23826e90931SAlexei Starovoitov 	int i;
23926e90931SAlexei Starovoitov 
24026e90931SAlexei Starovoitov 	start_time = time_get_ns();
2419fd63d05SMartin KaFai Lau 	for (i = 0; i < max_cnt; i++)
24226e90931SAlexei Starovoitov 		syscall(__NR_getgid);
24326e90931SAlexei Starovoitov 	printf("%d:hash_map_perf kmalloc %lld events per sec\n",
2449fd63d05SMartin KaFai Lau 	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
24526e90931SAlexei Starovoitov }
24626e90931SAlexei Starovoitov 
24726e90931SAlexei Starovoitov static void test_percpu_hash_kmalloc(int cpu)
24826e90931SAlexei Starovoitov {
24926e90931SAlexei Starovoitov 	__u64 start_time;
25026e90931SAlexei Starovoitov 	int i;
25126e90931SAlexei Starovoitov 
25226e90931SAlexei Starovoitov 	start_time = time_get_ns();
2539fd63d05SMartin KaFai Lau 	for (i = 0; i < max_cnt; i++)
25426e90931SAlexei Starovoitov 		syscall(__NR_getegid);
25526e90931SAlexei Starovoitov 	printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n",
2569fd63d05SMartin KaFai Lau 	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
25726e90931SAlexei Starovoitov }
25826e90931SAlexei Starovoitov 
259b8a943e2SDavid Herrmann static void test_lpm_kmalloc(int cpu)
260b8a943e2SDavid Herrmann {
261b8a943e2SDavid Herrmann 	__u64 start_time;
262b8a943e2SDavid Herrmann 	int i;
263b8a943e2SDavid Herrmann 
264b8a943e2SDavid Herrmann 	start_time = time_get_ns();
2659fd63d05SMartin KaFai Lau 	for (i = 0; i < max_cnt; i++)
266b8a943e2SDavid Herrmann 		syscall(__NR_gettid);
267b8a943e2SDavid Herrmann 	printf("%d:lpm_perf kmalloc %lld events per sec\n",
2689fd63d05SMartin KaFai Lau 	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
269b8a943e2SDavid Herrmann }
270b8a943e2SDavid Herrmann 
27195ff141eSAlexei Starovoitov static void test_hash_lookup(int cpu)
27295ff141eSAlexei Starovoitov {
27395ff141eSAlexei Starovoitov 	__u64 start_time;
27495ff141eSAlexei Starovoitov 	int i;
27595ff141eSAlexei Starovoitov 
27695ff141eSAlexei Starovoitov 	start_time = time_get_ns();
2779fd63d05SMartin KaFai Lau 	for (i = 0; i < max_cnt; i++)
27895ff141eSAlexei Starovoitov 		syscall(__NR_getpgid, 0);
27995ff141eSAlexei Starovoitov 	printf("%d:hash_lookup %lld lookups per sec\n",
2809fd63d05SMartin KaFai Lau 	       cpu, max_cnt * 1000000000ll * 64 / (time_get_ns() - start_time));
28195ff141eSAlexei Starovoitov }
28295ff141eSAlexei Starovoitov 
28395ff141eSAlexei Starovoitov static void test_array_lookup(int cpu)
28495ff141eSAlexei Starovoitov {
28595ff141eSAlexei Starovoitov 	__u64 start_time;
28695ff141eSAlexei Starovoitov 	int i;
28795ff141eSAlexei Starovoitov 
28895ff141eSAlexei Starovoitov 	start_time = time_get_ns();
2899fd63d05SMartin KaFai Lau 	for (i = 0; i < max_cnt; i++)
29095ec6696SJoel Fernandes 		syscall(__NR_getppid, 0);
29195ff141eSAlexei Starovoitov 	printf("%d:array_lookup %lld lookups per sec\n",
2929fd63d05SMartin KaFai Lau 	       cpu, max_cnt * 1000000000ll * 64 / (time_get_ns() - start_time));
29395ff141eSAlexei Starovoitov }
29495ff141eSAlexei Starovoitov 
295637cd8c3SMartin KaFai Lau typedef int (*pre_test_func)(int tasks);
296637cd8c3SMartin KaFai Lau const pre_test_func pre_test_funcs[] = {
297637cd8c3SMartin KaFai Lau 	[LRU_HASH_LOOKUP] = pre_test_lru_hash_lookup,
298637cd8c3SMartin KaFai Lau };
299637cd8c3SMartin KaFai Lau 
3009fd63d05SMartin KaFai Lau typedef void (*test_func)(int cpu);
3019fd63d05SMartin KaFai Lau const test_func test_funcs[] = {
3029fd63d05SMartin KaFai Lau 	[HASH_PREALLOC] = test_hash_prealloc,
3039fd63d05SMartin KaFai Lau 	[PERCPU_HASH_PREALLOC] = test_percpu_hash_prealloc,
3049fd63d05SMartin KaFai Lau 	[HASH_KMALLOC] = test_hash_kmalloc,
3059fd63d05SMartin KaFai Lau 	[PERCPU_HASH_KMALLOC] = test_percpu_hash_kmalloc,
3069fd63d05SMartin KaFai Lau 	[LRU_HASH_PREALLOC] = test_lru_hash_prealloc,
3079fd63d05SMartin KaFai Lau 	[NOCOMMON_LRU_HASH_PREALLOC] = test_nocommon_lru_hash_prealloc,
3089fd63d05SMartin KaFai Lau 	[LPM_KMALLOC] = test_lpm_kmalloc,
3099fd63d05SMartin KaFai Lau 	[HASH_LOOKUP] = test_hash_lookup,
3109fd63d05SMartin KaFai Lau 	[ARRAY_LOOKUP] = test_array_lookup,
3113a5795b8SMartin KaFai Lau 	[INNER_LRU_HASH_PREALLOC] = test_inner_lru_hash_prealloc,
312637cd8c3SMartin KaFai Lau 	[LRU_HASH_LOOKUP] = test_lru_hash_lookup,
3139fd63d05SMartin KaFai Lau };
3149fd63d05SMartin KaFai Lau 
315637cd8c3SMartin KaFai Lau static int pre_test(int tasks)
316637cd8c3SMartin KaFai Lau {
317637cd8c3SMartin KaFai Lau 	int i;
318637cd8c3SMartin KaFai Lau 
319637cd8c3SMartin KaFai Lau 	for (i = 0; i < NR_TESTS; i++) {
320637cd8c3SMartin KaFai Lau 		if (pre_test_funcs[i] && check_test_flags(i)) {
321637cd8c3SMartin KaFai Lau 			int ret = pre_test_funcs[i](tasks);
322637cd8c3SMartin KaFai Lau 
323637cd8c3SMartin KaFai Lau 			if (ret)
324637cd8c3SMartin KaFai Lau 				return ret;
325637cd8c3SMartin KaFai Lau 		}
326637cd8c3SMartin KaFai Lau 	}
327637cd8c3SMartin KaFai Lau 
328637cd8c3SMartin KaFai Lau 	return 0;
329637cd8c3SMartin KaFai Lau }
330637cd8c3SMartin KaFai Lau 
33126e90931SAlexei Starovoitov static void loop(int cpu)
33226e90931SAlexei Starovoitov {
33326e90931SAlexei Starovoitov 	cpu_set_t cpuset;
3349fd63d05SMartin KaFai Lau 	int i;
33526e90931SAlexei Starovoitov 
33626e90931SAlexei Starovoitov 	CPU_ZERO(&cpuset);
33726e90931SAlexei Starovoitov 	CPU_SET(cpu, &cpuset);
33826e90931SAlexei Starovoitov 	sched_setaffinity(0, sizeof(cpuset), &cpuset);
33926e90931SAlexei Starovoitov 
3409fd63d05SMartin KaFai Lau 	for (i = 0; i < NR_TESTS; i++) {
3419fd63d05SMartin KaFai Lau 		if (check_test_flags(i))
3429fd63d05SMartin KaFai Lau 			test_funcs[i](cpu);
3439fd63d05SMartin KaFai Lau 	}
34426e90931SAlexei Starovoitov }
34526e90931SAlexei Starovoitov 
34626e90931SAlexei Starovoitov static void run_perf_test(int tasks)
34726e90931SAlexei Starovoitov {
34826e90931SAlexei Starovoitov 	pid_t pid[tasks];
34926e90931SAlexei Starovoitov 	int i;
35026e90931SAlexei Starovoitov 
351637cd8c3SMartin KaFai Lau 	assert(!pre_test(tasks));
352637cd8c3SMartin KaFai Lau 
35326e90931SAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
35426e90931SAlexei Starovoitov 		pid[i] = fork();
35526e90931SAlexei Starovoitov 		if (pid[i] == 0) {
35626e90931SAlexei Starovoitov 			loop(i);
35726e90931SAlexei Starovoitov 			exit(0);
35826e90931SAlexei Starovoitov 		} else if (pid[i] == -1) {
35926e90931SAlexei Starovoitov 			printf("couldn't spawn #%d process\n", i);
36026e90931SAlexei Starovoitov 			exit(1);
36126e90931SAlexei Starovoitov 		}
36226e90931SAlexei Starovoitov 	}
36326e90931SAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
36426e90931SAlexei Starovoitov 		int status;
36526e90931SAlexei Starovoitov 
36626e90931SAlexei Starovoitov 		assert(waitpid(pid[i], &status, 0) == pid[i]);
36726e90931SAlexei Starovoitov 		assert(status == 0);
36826e90931SAlexei Starovoitov 	}
36926e90931SAlexei Starovoitov }
37026e90931SAlexei Starovoitov 
371b8a943e2SDavid Herrmann static void fill_lpm_trie(void)
372b8a943e2SDavid Herrmann {
373b8a943e2SDavid Herrmann 	struct bpf_lpm_trie_key *key;
374b8a943e2SDavid Herrmann 	unsigned long value = 0;
375b8a943e2SDavid Herrmann 	unsigned int i;
376b8a943e2SDavid Herrmann 	int r;
377b8a943e2SDavid Herrmann 
378b8a943e2SDavid Herrmann 	key = alloca(sizeof(*key) + 4);
379b8a943e2SDavid Herrmann 	key->prefixlen = 32;
380b8a943e2SDavid Herrmann 
381b8a943e2SDavid Herrmann 	for (i = 0; i < 512; ++i) {
382b8a943e2SDavid Herrmann 		key->prefixlen = rand() % 33;
383b8a943e2SDavid Herrmann 		key->data[0] = rand() & 0xff;
384b8a943e2SDavid Herrmann 		key->data[1] = rand() & 0xff;
385b8a943e2SDavid Herrmann 		key->data[2] = rand() & 0xff;
386b8a943e2SDavid Herrmann 		key->data[3] = rand() & 0xff;
387cc7f641dSDaniel T. Lee 		r = bpf_map_update_elem(map_fd[hash_map_alloc_idx],
388cc7f641dSDaniel T. Lee 					key, &value, 0);
389b8a943e2SDavid Herrmann 		assert(!r);
390b8a943e2SDavid Herrmann 	}
391b8a943e2SDavid Herrmann 
392b8a943e2SDavid Herrmann 	key->prefixlen = 32;
393b8a943e2SDavid Herrmann 	key->data[0] = 192;
394b8a943e2SDavid Herrmann 	key->data[1] = 168;
395b8a943e2SDavid Herrmann 	key->data[2] = 0;
396b8a943e2SDavid Herrmann 	key->data[3] = 1;
397b8a943e2SDavid Herrmann 	value = 128;
398b8a943e2SDavid Herrmann 
399cc7f641dSDaniel T. Lee 	r = bpf_map_update_elem(map_fd[hash_map_alloc_idx], key, &value, 0);
400b8a943e2SDavid Herrmann 	assert(!r);
401b8a943e2SDavid Herrmann }
402b8a943e2SDavid Herrmann 
403cc7f641dSDaniel T. Lee static void fixup_map(struct bpf_object *obj)
4049fd63d05SMartin KaFai Lau {
405cc7f641dSDaniel T. Lee 	struct bpf_map *map;
4069fd63d05SMartin KaFai Lau 	int i;
4079fd63d05SMartin KaFai Lau 
408cc7f641dSDaniel T. Lee 	bpf_object__for_each_map(map, obj) {
409cc7f641dSDaniel T. Lee 		const char *name = bpf_map__name(map);
4103a5795b8SMartin KaFai Lau 
4119fd63d05SMartin KaFai Lau 		/* Only change the max_entries for the enabled test(s) */
4129fd63d05SMartin KaFai Lau 		for (i = 0; i < NR_TESTS; i++) {
413cc7f641dSDaniel T. Lee 			if (!strcmp(test_map_names[i], name) &&
4149fd63d05SMartin KaFai Lau 			    (check_test_flags(i))) {
41561afd3daSAndrii Nakryiko 				bpf_map__set_max_entries(map, num_map_entries);
416cc7f641dSDaniel T. Lee 				continue;
4179fd63d05SMartin KaFai Lau 			}
4189fd63d05SMartin KaFai Lau 		}
4199fd63d05SMartin KaFai Lau 	}
4209fd63d05SMartin KaFai Lau 
421cc7f641dSDaniel T. Lee 	inner_lru_hash_size = num_map_entries;
422cc7f641dSDaniel T. Lee }
423cc7f641dSDaniel T. Lee 
42426e90931SAlexei Starovoitov int main(int argc, char **argv)
42526e90931SAlexei Starovoitov {
426cc7f641dSDaniel T. Lee 	int nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
427cc7f641dSDaniel T. Lee 	struct bpf_link *links[8];
428cc7f641dSDaniel T. Lee 	struct bpf_program *prog;
429cc7f641dSDaniel T. Lee 	struct bpf_object *obj;
430cc7f641dSDaniel T. Lee 	struct bpf_map *map;
43126e90931SAlexei Starovoitov 	char filename[256];
432cc7f641dSDaniel T. Lee 	int i = 0;
43326e90931SAlexei Starovoitov 
43426e90931SAlexei Starovoitov 	if (argc > 1)
43526e90931SAlexei Starovoitov 		test_flags = atoi(argv[1]) ? : test_flags;
43626e90931SAlexei Starovoitov 
43726e90931SAlexei Starovoitov 	if (argc > 2)
438cc7f641dSDaniel T. Lee 		nr_cpus = atoi(argv[2]) ? : nr_cpus;
43926e90931SAlexei Starovoitov 
4409fd63d05SMartin KaFai Lau 	if (argc > 3)
4419fd63d05SMartin KaFai Lau 		num_map_entries = atoi(argv[3]);
4429fd63d05SMartin KaFai Lau 
4439fd63d05SMartin KaFai Lau 	if (argc > 4)
4449fd63d05SMartin KaFai Lau 		max_cnt = atoi(argv[4]);
4459fd63d05SMartin KaFai Lau 
446*d4fffba4SDaniel T. Lee 	snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]);
447cc7f641dSDaniel T. Lee 	obj = bpf_object__open_file(filename, NULL);
448cc7f641dSDaniel T. Lee 	if (libbpf_get_error(obj)) {
449cc7f641dSDaniel T. Lee 		fprintf(stderr, "ERROR: opening BPF object file failed\n");
450cc7f641dSDaniel T. Lee 		return 0;
451cc7f641dSDaniel T. Lee 	}
452cc7f641dSDaniel T. Lee 
453cc7f641dSDaniel T. Lee 	map = bpf_object__find_map_by_name(obj, "inner_lru_hash_map");
454cc7f641dSDaniel T. Lee 	if (libbpf_get_error(map)) {
455cc7f641dSDaniel T. Lee 		fprintf(stderr, "ERROR: finding a map in obj file failed\n");
456cc7f641dSDaniel T. Lee 		goto cleanup;
457cc7f641dSDaniel T. Lee 	}
458cc7f641dSDaniel T. Lee 
459cc7f641dSDaniel T. Lee 	inner_lru_hash_size = bpf_map__max_entries(map);
460cc7f641dSDaniel T. Lee 	if (!inner_lru_hash_size) {
461cc7f641dSDaniel T. Lee 		fprintf(stderr, "ERROR: failed to get map attribute\n");
462cc7f641dSDaniel T. Lee 		goto cleanup;
463cc7f641dSDaniel T. Lee 	}
464cc7f641dSDaniel T. Lee 
465cc7f641dSDaniel T. Lee 	/* resize BPF map prior to loading */
466cc7f641dSDaniel T. Lee 	if (num_map_entries > 0)
467cc7f641dSDaniel T. Lee 		fixup_map(obj);
468cc7f641dSDaniel T. Lee 
469cc7f641dSDaniel T. Lee 	/* load BPF program */
470cc7f641dSDaniel T. Lee 	if (bpf_object__load(obj)) {
471cc7f641dSDaniel T. Lee 		fprintf(stderr, "ERROR: loading BPF object file failed\n");
472cc7f641dSDaniel T. Lee 		goto cleanup;
473cc7f641dSDaniel T. Lee 	}
474cc7f641dSDaniel T. Lee 
475cc7f641dSDaniel T. Lee 	map_fd[0] = bpf_object__find_map_fd_by_name(obj, "array_of_lru_hashs");
476cc7f641dSDaniel T. Lee 	map_fd[1] = bpf_object__find_map_fd_by_name(obj, "hash_map_alloc");
477cc7f641dSDaniel T. Lee 	map_fd[2] = bpf_object__find_map_fd_by_name(obj, "lru_hash_lookup_map");
478cc7f641dSDaniel T. Lee 	if (map_fd[0] < 0 || map_fd[1] < 0 || map_fd[2] < 0) {
479cc7f641dSDaniel T. Lee 		fprintf(stderr, "ERROR: finding a map in obj file failed\n");
480cc7f641dSDaniel T. Lee 		goto cleanup;
481cc7f641dSDaniel T. Lee 	}
482cc7f641dSDaniel T. Lee 
483cc7f641dSDaniel T. Lee 	bpf_object__for_each_program(prog, obj) {
484cc7f641dSDaniel T. Lee 		links[i] = bpf_program__attach(prog);
485cc7f641dSDaniel T. Lee 		if (libbpf_get_error(links[i])) {
486cc7f641dSDaniel T. Lee 			fprintf(stderr, "ERROR: bpf_program__attach failed\n");
487cc7f641dSDaniel T. Lee 			links[i] = NULL;
488cc7f641dSDaniel T. Lee 			goto cleanup;
489cc7f641dSDaniel T. Lee 		}
490cc7f641dSDaniel T. Lee 		i++;
49126e90931SAlexei Starovoitov 	}
49226e90931SAlexei Starovoitov 
493b8a943e2SDavid Herrmann 	fill_lpm_trie();
494b8a943e2SDavid Herrmann 
495cc7f641dSDaniel T. Lee 	run_perf_test(nr_cpus);
49626e90931SAlexei Starovoitov 
497cc7f641dSDaniel T. Lee cleanup:
498cc7f641dSDaniel T. Lee 	for (i--; i >= 0; i--)
499cc7f641dSDaniel T. Lee 		bpf_link__destroy(links[i]);
500cc7f641dSDaniel T. Lee 
501cc7f641dSDaniel T. Lee 	bpf_object__close(obj);
50226e90931SAlexei Starovoitov 	return 0;
50326e90931SAlexei Starovoitov }
504