18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* Copyright (c) 2016 Facebook
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci#define _GNU_SOURCE
58c2ecf20Sopenharmony_ci#include <sched.h>
68c2ecf20Sopenharmony_ci#include <stdio.h>
78c2ecf20Sopenharmony_ci#include <sys/types.h>
88c2ecf20Sopenharmony_ci#include <asm/unistd.h>
98c2ecf20Sopenharmony_ci#include <unistd.h>
108c2ecf20Sopenharmony_ci#include <assert.h>
118c2ecf20Sopenharmony_ci#include <sys/wait.h>
128c2ecf20Sopenharmony_ci#include <stdlib.h>
138c2ecf20Sopenharmony_ci#include <signal.h>
148c2ecf20Sopenharmony_ci#include <string.h>
158c2ecf20Sopenharmony_ci#include <time.h>
168c2ecf20Sopenharmony_ci#include <sys/resource.h>
178c2ecf20Sopenharmony_ci#include <arpa/inet.h>
188c2ecf20Sopenharmony_ci#include <errno.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
218c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define TEST_BIT(t) (1U << (t))
248c2ecf20Sopenharmony_ci#define MAX_NR_CPUS 1024
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic __u64 time_get_ns(void)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	struct timespec ts;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	clock_gettime(CLOCK_MONOTONIC, &ts);
318c2ecf20Sopenharmony_ci	return ts.tv_sec * 1000000000ull + ts.tv_nsec;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cienum test_type {
358c2ecf20Sopenharmony_ci	HASH_PREALLOC,
368c2ecf20Sopenharmony_ci	PERCPU_HASH_PREALLOC,
378c2ecf20Sopenharmony_ci	HASH_KMALLOC,
388c2ecf20Sopenharmony_ci	PERCPU_HASH_KMALLOC,
398c2ecf20Sopenharmony_ci	LRU_HASH_PREALLOC,
408c2ecf20Sopenharmony_ci	NOCOMMON_LRU_HASH_PREALLOC,
418c2ecf20Sopenharmony_ci	LPM_KMALLOC,
428c2ecf20Sopenharmony_ci	HASH_LOOKUP,
438c2ecf20Sopenharmony_ci	ARRAY_LOOKUP,
448c2ecf20Sopenharmony_ci	INNER_LRU_HASH_PREALLOC,
458c2ecf20Sopenharmony_ci	LRU_HASH_LOOKUP,
468c2ecf20Sopenharmony_ci	NR_TESTS,
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciconst char *test_map_names[NR_TESTS] = {
508c2ecf20Sopenharmony_ci	[HASH_PREALLOC] = "hash_map",
518c2ecf20Sopenharmony_ci	[PERCPU_HASH_PREALLOC] = "percpu_hash_map",
528c2ecf20Sopenharmony_ci	[HASH_KMALLOC] = "hash_map_alloc",
538c2ecf20Sopenharmony_ci	[PERCPU_HASH_KMALLOC] = "percpu_hash_map_alloc",
548c2ecf20Sopenharmony_ci	[LRU_HASH_PREALLOC] = "lru_hash_map",
558c2ecf20Sopenharmony_ci	[NOCOMMON_LRU_HASH_PREALLOC] = "nocommon_lru_hash_map",
568c2ecf20Sopenharmony_ci	[LPM_KMALLOC] = "lpm_trie_map_alloc",
578c2ecf20Sopenharmony_ci	[HASH_LOOKUP] = "hash_map",
588c2ecf20Sopenharmony_ci	[ARRAY_LOOKUP] = "array_map",
598c2ecf20Sopenharmony_ci	[INNER_LRU_HASH_PREALLOC] = "inner_lru_hash_map",
608c2ecf20Sopenharmony_ci	[LRU_HASH_LOOKUP] = "lru_hash_lookup_map",
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cienum map_idx {
648c2ecf20Sopenharmony_ci	array_of_lru_hashs_idx,
658c2ecf20Sopenharmony_ci	hash_map_alloc_idx,
668c2ecf20Sopenharmony_ci	lru_hash_lookup_idx,
678c2ecf20Sopenharmony_ci	NR_IDXES,
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int map_fd[NR_IDXES];
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int test_flags = ~0;
738c2ecf20Sopenharmony_cistatic uint32_t num_map_entries;
748c2ecf20Sopenharmony_cistatic uint32_t inner_lru_hash_size;
758c2ecf20Sopenharmony_cistatic int lru_hash_lookup_test_entries = 32;
768c2ecf20Sopenharmony_cistatic uint32_t max_cnt = 1000000;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic int check_test_flags(enum test_type t)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	return test_flags & TEST_BIT(t);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void test_hash_prealloc(int cpu)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	__u64 start_time;
868c2ecf20Sopenharmony_ci	int i;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	start_time = time_get_ns();
898c2ecf20Sopenharmony_ci	for (i = 0; i < max_cnt; i++)
908c2ecf20Sopenharmony_ci		syscall(__NR_getuid);
918c2ecf20Sopenharmony_ci	printf("%d:hash_map_perf pre-alloc %lld events per sec\n",
928c2ecf20Sopenharmony_ci	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic int pre_test_lru_hash_lookup(int tasks)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	int fd = map_fd[lru_hash_lookup_idx];
988c2ecf20Sopenharmony_ci	uint32_t key;
998c2ecf20Sopenharmony_ci	long val = 1;
1008c2ecf20Sopenharmony_ci	int ret;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if (num_map_entries > lru_hash_lookup_test_entries)
1038c2ecf20Sopenharmony_ci		lru_hash_lookup_test_entries = num_map_entries;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/* Populate the lru_hash_map for LRU_HASH_LOOKUP perf test.
1068c2ecf20Sopenharmony_ci	 *
1078c2ecf20Sopenharmony_ci	 * It is fine that the user requests for a map with
1088c2ecf20Sopenharmony_ci	 * num_map_entries < 32 and some of the later lru hash lookup
1098c2ecf20Sopenharmony_ci	 * may return not found.  For LRU map, we are not interested
1108c2ecf20Sopenharmony_ci	 * in such small map performance.
1118c2ecf20Sopenharmony_ci	 */
1128c2ecf20Sopenharmony_ci	for (key = 0; key < lru_hash_lookup_test_entries; key++) {
1138c2ecf20Sopenharmony_ci		ret = bpf_map_update_elem(fd, &key, &val, BPF_NOEXIST);
1148c2ecf20Sopenharmony_ci		if (ret)
1158c2ecf20Sopenharmony_ci			return ret;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return 0;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic void do_test_lru(enum test_type test, int cpu)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	static int inner_lru_map_fds[MAX_NR_CPUS];
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	struct sockaddr_in6 in6 = { .sin6_family = AF_INET6 };
1268c2ecf20Sopenharmony_ci	const char *test_name;
1278c2ecf20Sopenharmony_ci	__u64 start_time;
1288c2ecf20Sopenharmony_ci	int i, ret;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (test == INNER_LRU_HASH_PREALLOC && cpu) {
1318c2ecf20Sopenharmony_ci		/* If CPU is not 0, create inner_lru hash map and insert the fd
1328c2ecf20Sopenharmony_ci		 * value into the array_of_lru_hash map. In case of CPU 0,
1338c2ecf20Sopenharmony_ci		 * 'inner_lru_hash_map' was statically inserted on the map init
1348c2ecf20Sopenharmony_ci		 */
1358c2ecf20Sopenharmony_ci		int outer_fd = map_fd[array_of_lru_hashs_idx];
1368c2ecf20Sopenharmony_ci		unsigned int mycpu, mynode;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci		assert(cpu < MAX_NR_CPUS);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci		ret = syscall(__NR_getcpu, &mycpu, &mynode, NULL);
1418c2ecf20Sopenharmony_ci		assert(!ret);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		inner_lru_map_fds[cpu] =
1448c2ecf20Sopenharmony_ci			bpf_create_map_node(BPF_MAP_TYPE_LRU_HASH,
1458c2ecf20Sopenharmony_ci					    test_map_names[INNER_LRU_HASH_PREALLOC],
1468c2ecf20Sopenharmony_ci					    sizeof(uint32_t),
1478c2ecf20Sopenharmony_ci					    sizeof(long),
1488c2ecf20Sopenharmony_ci					    inner_lru_hash_size, 0,
1498c2ecf20Sopenharmony_ci					    mynode);
1508c2ecf20Sopenharmony_ci		if (inner_lru_map_fds[cpu] == -1) {
1518c2ecf20Sopenharmony_ci			printf("cannot create BPF_MAP_TYPE_LRU_HASH %s(%d)\n",
1528c2ecf20Sopenharmony_ci			       strerror(errno), errno);
1538c2ecf20Sopenharmony_ci			exit(1);
1548c2ecf20Sopenharmony_ci		}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		ret = bpf_map_update_elem(outer_fd, &cpu,
1578c2ecf20Sopenharmony_ci					  &inner_lru_map_fds[cpu],
1588c2ecf20Sopenharmony_ci					  BPF_ANY);
1598c2ecf20Sopenharmony_ci		if (ret) {
1608c2ecf20Sopenharmony_ci			printf("cannot update ARRAY_OF_LRU_HASHS with key:%u. %s(%d)\n",
1618c2ecf20Sopenharmony_ci			       cpu, strerror(errno), errno);
1628c2ecf20Sopenharmony_ci			exit(1);
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	in6.sin6_addr.s6_addr16[0] = 0xdead;
1678c2ecf20Sopenharmony_ci	in6.sin6_addr.s6_addr16[1] = 0xbeef;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (test == LRU_HASH_PREALLOC) {
1708c2ecf20Sopenharmony_ci		test_name = "lru_hash_map_perf";
1718c2ecf20Sopenharmony_ci		in6.sin6_addr.s6_addr16[2] = 0;
1728c2ecf20Sopenharmony_ci	} else if (test == NOCOMMON_LRU_HASH_PREALLOC) {
1738c2ecf20Sopenharmony_ci		test_name = "nocommon_lru_hash_map_perf";
1748c2ecf20Sopenharmony_ci		in6.sin6_addr.s6_addr16[2] = 1;
1758c2ecf20Sopenharmony_ci	} else if (test == INNER_LRU_HASH_PREALLOC) {
1768c2ecf20Sopenharmony_ci		test_name = "inner_lru_hash_map_perf";
1778c2ecf20Sopenharmony_ci		in6.sin6_addr.s6_addr16[2] = 2;
1788c2ecf20Sopenharmony_ci	} else if (test == LRU_HASH_LOOKUP) {
1798c2ecf20Sopenharmony_ci		test_name = "lru_hash_lookup_perf";
1808c2ecf20Sopenharmony_ci		in6.sin6_addr.s6_addr16[2] = 3;
1818c2ecf20Sopenharmony_ci		in6.sin6_addr.s6_addr32[3] = 0;
1828c2ecf20Sopenharmony_ci	} else {
1838c2ecf20Sopenharmony_ci		assert(0);
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	start_time = time_get_ns();
1878c2ecf20Sopenharmony_ci	for (i = 0; i < max_cnt; i++) {
1888c2ecf20Sopenharmony_ci		ret = connect(-1, (const struct sockaddr *)&in6, sizeof(in6));
1898c2ecf20Sopenharmony_ci		assert(ret == -1 && errno == EBADF);
1908c2ecf20Sopenharmony_ci		if (in6.sin6_addr.s6_addr32[3] <
1918c2ecf20Sopenharmony_ci		    lru_hash_lookup_test_entries - 32)
1928c2ecf20Sopenharmony_ci			in6.sin6_addr.s6_addr32[3] += 32;
1938c2ecf20Sopenharmony_ci		else
1948c2ecf20Sopenharmony_ci			in6.sin6_addr.s6_addr32[3] = 0;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci	printf("%d:%s pre-alloc %lld events per sec\n",
1978c2ecf20Sopenharmony_ci	       cpu, test_name,
1988c2ecf20Sopenharmony_ci	       max_cnt * 1000000000ll / (time_get_ns() - start_time));
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic void test_lru_hash_prealloc(int cpu)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	do_test_lru(LRU_HASH_PREALLOC, cpu);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic void test_nocommon_lru_hash_prealloc(int cpu)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	do_test_lru(NOCOMMON_LRU_HASH_PREALLOC, cpu);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic void test_inner_lru_hash_prealloc(int cpu)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	do_test_lru(INNER_LRU_HASH_PREALLOC, cpu);
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic void test_lru_hash_lookup(int cpu)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	do_test_lru(LRU_HASH_LOOKUP, cpu);
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic void test_percpu_hash_prealloc(int cpu)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	__u64 start_time;
2248c2ecf20Sopenharmony_ci	int i;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	start_time = time_get_ns();
2278c2ecf20Sopenharmony_ci	for (i = 0; i < max_cnt; i++)
2288c2ecf20Sopenharmony_ci		syscall(__NR_geteuid);
2298c2ecf20Sopenharmony_ci	printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n",
2308c2ecf20Sopenharmony_ci	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic void test_hash_kmalloc(int cpu)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	__u64 start_time;
2368c2ecf20Sopenharmony_ci	int i;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	start_time = time_get_ns();
2398c2ecf20Sopenharmony_ci	for (i = 0; i < max_cnt; i++)
2408c2ecf20Sopenharmony_ci		syscall(__NR_getgid);
2418c2ecf20Sopenharmony_ci	printf("%d:hash_map_perf kmalloc %lld events per sec\n",
2428c2ecf20Sopenharmony_ci	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic void test_percpu_hash_kmalloc(int cpu)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	__u64 start_time;
2488c2ecf20Sopenharmony_ci	int i;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	start_time = time_get_ns();
2518c2ecf20Sopenharmony_ci	for (i = 0; i < max_cnt; i++)
2528c2ecf20Sopenharmony_ci		syscall(__NR_getegid);
2538c2ecf20Sopenharmony_ci	printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n",
2548c2ecf20Sopenharmony_ci	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic void test_lpm_kmalloc(int cpu)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	__u64 start_time;
2608c2ecf20Sopenharmony_ci	int i;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	start_time = time_get_ns();
2638c2ecf20Sopenharmony_ci	for (i = 0; i < max_cnt; i++)
2648c2ecf20Sopenharmony_ci		syscall(__NR_gettid);
2658c2ecf20Sopenharmony_ci	printf("%d:lpm_perf kmalloc %lld events per sec\n",
2668c2ecf20Sopenharmony_ci	       cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic void test_hash_lookup(int cpu)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	__u64 start_time;
2728c2ecf20Sopenharmony_ci	int i;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	start_time = time_get_ns();
2758c2ecf20Sopenharmony_ci	for (i = 0; i < max_cnt; i++)
2768c2ecf20Sopenharmony_ci		syscall(__NR_getpgid, 0);
2778c2ecf20Sopenharmony_ci	printf("%d:hash_lookup %lld lookups per sec\n",
2788c2ecf20Sopenharmony_ci	       cpu, max_cnt * 1000000000ll * 64 / (time_get_ns() - start_time));
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic void test_array_lookup(int cpu)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	__u64 start_time;
2848c2ecf20Sopenharmony_ci	int i;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	start_time = time_get_ns();
2878c2ecf20Sopenharmony_ci	for (i = 0; i < max_cnt; i++)
2888c2ecf20Sopenharmony_ci		syscall(__NR_getppid, 0);
2898c2ecf20Sopenharmony_ci	printf("%d:array_lookup %lld lookups per sec\n",
2908c2ecf20Sopenharmony_ci	       cpu, max_cnt * 1000000000ll * 64 / (time_get_ns() - start_time));
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_citypedef int (*pre_test_func)(int tasks);
2948c2ecf20Sopenharmony_ciconst pre_test_func pre_test_funcs[] = {
2958c2ecf20Sopenharmony_ci	[LRU_HASH_LOOKUP] = pre_test_lru_hash_lookup,
2968c2ecf20Sopenharmony_ci};
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_citypedef void (*test_func)(int cpu);
2998c2ecf20Sopenharmony_ciconst test_func test_funcs[] = {
3008c2ecf20Sopenharmony_ci	[HASH_PREALLOC] = test_hash_prealloc,
3018c2ecf20Sopenharmony_ci	[PERCPU_HASH_PREALLOC] = test_percpu_hash_prealloc,
3028c2ecf20Sopenharmony_ci	[HASH_KMALLOC] = test_hash_kmalloc,
3038c2ecf20Sopenharmony_ci	[PERCPU_HASH_KMALLOC] = test_percpu_hash_kmalloc,
3048c2ecf20Sopenharmony_ci	[LRU_HASH_PREALLOC] = test_lru_hash_prealloc,
3058c2ecf20Sopenharmony_ci	[NOCOMMON_LRU_HASH_PREALLOC] = test_nocommon_lru_hash_prealloc,
3068c2ecf20Sopenharmony_ci	[LPM_KMALLOC] = test_lpm_kmalloc,
3078c2ecf20Sopenharmony_ci	[HASH_LOOKUP] = test_hash_lookup,
3088c2ecf20Sopenharmony_ci	[ARRAY_LOOKUP] = test_array_lookup,
3098c2ecf20Sopenharmony_ci	[INNER_LRU_HASH_PREALLOC] = test_inner_lru_hash_prealloc,
3108c2ecf20Sopenharmony_ci	[LRU_HASH_LOOKUP] = test_lru_hash_lookup,
3118c2ecf20Sopenharmony_ci};
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic int pre_test(int tasks)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	int i;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	for (i = 0; i < NR_TESTS; i++) {
3188c2ecf20Sopenharmony_ci		if (pre_test_funcs[i] && check_test_flags(i)) {
3198c2ecf20Sopenharmony_ci			int ret = pre_test_funcs[i](tasks);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci			if (ret)
3228c2ecf20Sopenharmony_ci				return ret;
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return 0;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic void loop(int cpu)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	cpu_set_t cpuset;
3328c2ecf20Sopenharmony_ci	int i;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	CPU_ZERO(&cpuset);
3358c2ecf20Sopenharmony_ci	CPU_SET(cpu, &cpuset);
3368c2ecf20Sopenharmony_ci	sched_setaffinity(0, sizeof(cpuset), &cpuset);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	for (i = 0; i < NR_TESTS; i++) {
3398c2ecf20Sopenharmony_ci		if (check_test_flags(i))
3408c2ecf20Sopenharmony_ci			test_funcs[i](cpu);
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic void run_perf_test(int tasks)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	pid_t pid[tasks];
3478c2ecf20Sopenharmony_ci	int i;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	assert(!pre_test(tasks));
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	for (i = 0; i < tasks; i++) {
3528c2ecf20Sopenharmony_ci		pid[i] = fork();
3538c2ecf20Sopenharmony_ci		if (pid[i] == 0) {
3548c2ecf20Sopenharmony_ci			loop(i);
3558c2ecf20Sopenharmony_ci			exit(0);
3568c2ecf20Sopenharmony_ci		} else if (pid[i] == -1) {
3578c2ecf20Sopenharmony_ci			printf("couldn't spawn #%d process\n", i);
3588c2ecf20Sopenharmony_ci			exit(1);
3598c2ecf20Sopenharmony_ci		}
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci	for (i = 0; i < tasks; i++) {
3628c2ecf20Sopenharmony_ci		int status;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		assert(waitpid(pid[i], &status, 0) == pid[i]);
3658c2ecf20Sopenharmony_ci		assert(status == 0);
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic void fill_lpm_trie(void)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct bpf_lpm_trie_key *key;
3728c2ecf20Sopenharmony_ci	unsigned long value = 0;
3738c2ecf20Sopenharmony_ci	unsigned int i;
3748c2ecf20Sopenharmony_ci	int r;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	key = alloca(sizeof(*key) + 4);
3778c2ecf20Sopenharmony_ci	key->prefixlen = 32;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	for (i = 0; i < 512; ++i) {
3808c2ecf20Sopenharmony_ci		key->prefixlen = rand() % 33;
3818c2ecf20Sopenharmony_ci		key->data[0] = rand() & 0xff;
3828c2ecf20Sopenharmony_ci		key->data[1] = rand() & 0xff;
3838c2ecf20Sopenharmony_ci		key->data[2] = rand() & 0xff;
3848c2ecf20Sopenharmony_ci		key->data[3] = rand() & 0xff;
3858c2ecf20Sopenharmony_ci		r = bpf_map_update_elem(map_fd[hash_map_alloc_idx],
3868c2ecf20Sopenharmony_ci					key, &value, 0);
3878c2ecf20Sopenharmony_ci		assert(!r);
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	key->prefixlen = 32;
3918c2ecf20Sopenharmony_ci	key->data[0] = 192;
3928c2ecf20Sopenharmony_ci	key->data[1] = 168;
3938c2ecf20Sopenharmony_ci	key->data[2] = 0;
3948c2ecf20Sopenharmony_ci	key->data[3] = 1;
3958c2ecf20Sopenharmony_ci	value = 128;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	r = bpf_map_update_elem(map_fd[hash_map_alloc_idx], key, &value, 0);
3988c2ecf20Sopenharmony_ci	assert(!r);
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic void fixup_map(struct bpf_object *obj)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct bpf_map *map;
4048c2ecf20Sopenharmony_ci	int i;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	bpf_object__for_each_map(map, obj) {
4078c2ecf20Sopenharmony_ci		const char *name = bpf_map__name(map);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		/* Only change the max_entries for the enabled test(s) */
4108c2ecf20Sopenharmony_ci		for (i = 0; i < NR_TESTS; i++) {
4118c2ecf20Sopenharmony_ci			if (!strcmp(test_map_names[i], name) &&
4128c2ecf20Sopenharmony_ci			    (check_test_flags(i))) {
4138c2ecf20Sopenharmony_ci				bpf_map__resize(map, num_map_entries);
4148c2ecf20Sopenharmony_ci				continue;
4158c2ecf20Sopenharmony_ci			}
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	inner_lru_hash_size = num_map_entries;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ciint main(int argc, char **argv)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
4258c2ecf20Sopenharmony_ci	int nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
4268c2ecf20Sopenharmony_ci	struct bpf_link *links[8];
4278c2ecf20Sopenharmony_ci	struct bpf_program *prog;
4288c2ecf20Sopenharmony_ci	struct bpf_object *obj;
4298c2ecf20Sopenharmony_ci	struct bpf_map *map;
4308c2ecf20Sopenharmony_ci	char filename[256];
4318c2ecf20Sopenharmony_ci	int i = 0;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	if (setrlimit(RLIMIT_MEMLOCK, &r)) {
4348c2ecf20Sopenharmony_ci		perror("setrlimit(RLIMIT_MEMLOCK)");
4358c2ecf20Sopenharmony_ci		return 1;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	if (argc > 1)
4398c2ecf20Sopenharmony_ci		test_flags = atoi(argv[1]) ? : test_flags;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (argc > 2)
4428c2ecf20Sopenharmony_ci		nr_cpus = atoi(argv[2]) ? : nr_cpus;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (argc > 3)
4458c2ecf20Sopenharmony_ci		num_map_entries = atoi(argv[3]);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (argc > 4)
4488c2ecf20Sopenharmony_ci		max_cnt = atoi(argv[4]);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
4518c2ecf20Sopenharmony_ci	obj = bpf_object__open_file(filename, NULL);
4528c2ecf20Sopenharmony_ci	if (libbpf_get_error(obj)) {
4538c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: opening BPF object file failed\n");
4548c2ecf20Sopenharmony_ci		return 0;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	map = bpf_object__find_map_by_name(obj, "inner_lru_hash_map");
4588c2ecf20Sopenharmony_ci	if (libbpf_get_error(map)) {
4598c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: finding a map in obj file failed\n");
4608c2ecf20Sopenharmony_ci		goto cleanup;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	inner_lru_hash_size = bpf_map__max_entries(map);
4648c2ecf20Sopenharmony_ci	if (!inner_lru_hash_size) {
4658c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: failed to get map attribute\n");
4668c2ecf20Sopenharmony_ci		goto cleanup;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	/* resize BPF map prior to loading */
4708c2ecf20Sopenharmony_ci	if (num_map_entries > 0)
4718c2ecf20Sopenharmony_ci		fixup_map(obj);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/* load BPF program */
4748c2ecf20Sopenharmony_ci	if (bpf_object__load(obj)) {
4758c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: loading BPF object file failed\n");
4768c2ecf20Sopenharmony_ci		goto cleanup;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	map_fd[0] = bpf_object__find_map_fd_by_name(obj, "array_of_lru_hashs");
4808c2ecf20Sopenharmony_ci	map_fd[1] = bpf_object__find_map_fd_by_name(obj, "hash_map_alloc");
4818c2ecf20Sopenharmony_ci	map_fd[2] = bpf_object__find_map_fd_by_name(obj, "lru_hash_lookup_map");
4828c2ecf20Sopenharmony_ci	if (map_fd[0] < 0 || map_fd[1] < 0 || map_fd[2] < 0) {
4838c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: finding a map in obj file failed\n");
4848c2ecf20Sopenharmony_ci		goto cleanup;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	bpf_object__for_each_program(prog, obj) {
4888c2ecf20Sopenharmony_ci		links[i] = bpf_program__attach(prog);
4898c2ecf20Sopenharmony_ci		if (libbpf_get_error(links[i])) {
4908c2ecf20Sopenharmony_ci			fprintf(stderr, "ERROR: bpf_program__attach failed\n");
4918c2ecf20Sopenharmony_ci			links[i] = NULL;
4928c2ecf20Sopenharmony_ci			goto cleanup;
4938c2ecf20Sopenharmony_ci		}
4948c2ecf20Sopenharmony_ci		i++;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	fill_lpm_trie();
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	run_perf_test(nr_cpus);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cicleanup:
5028c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
5038c2ecf20Sopenharmony_ci		bpf_link__destroy(links[i]);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	bpf_object__close(obj);
5068c2ecf20Sopenharmony_ci	return 0;
5078c2ecf20Sopenharmony_ci}
508