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)
38*5db58fafSMartin KaFai Lau #define LRU_HASH_PREALLOC	(1 << 4)
39*5db58fafSMartin KaFai Lau #define PERCPU_LRU_HASH_PREALLOC	(1 << 5)
4026e90931SAlexei Starovoitov 
4126e90931SAlexei Starovoitov static int test_flags = ~0;
4226e90931SAlexei Starovoitov 
4326e90931SAlexei Starovoitov static void test_hash_prealloc(int cpu)
4426e90931SAlexei Starovoitov {
4526e90931SAlexei Starovoitov 	__u64 start_time;
4626e90931SAlexei Starovoitov 	int i;
4726e90931SAlexei Starovoitov 
4826e90931SAlexei Starovoitov 	start_time = time_get_ns();
4926e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
5026e90931SAlexei Starovoitov 		syscall(__NR_getuid);
5126e90931SAlexei Starovoitov 	printf("%d:hash_map_perf pre-alloc %lld events per sec\n",
5226e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
5326e90931SAlexei Starovoitov }
5426e90931SAlexei Starovoitov 
55*5db58fafSMartin KaFai Lau static void test_lru_hash_prealloc(int cpu)
56*5db58fafSMartin KaFai Lau {
57*5db58fafSMartin KaFai Lau 	__u64 start_time;
58*5db58fafSMartin KaFai Lau 	int i;
59*5db58fafSMartin KaFai Lau 
60*5db58fafSMartin KaFai Lau 	start_time = time_get_ns();
61*5db58fafSMartin KaFai Lau 	for (i = 0; i < MAX_CNT; i++)
62*5db58fafSMartin KaFai Lau 		syscall(__NR_getpid);
63*5db58fafSMartin KaFai Lau 	printf("%d:lru_hash_map_perf pre-alloc %lld events per sec\n",
64*5db58fafSMartin KaFai Lau 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
65*5db58fafSMartin KaFai Lau }
66*5db58fafSMartin KaFai Lau 
67*5db58fafSMartin KaFai Lau static void test_percpu_lru_hash_prealloc(int cpu)
68*5db58fafSMartin KaFai Lau {
69*5db58fafSMartin KaFai Lau 	__u64 start_time;
70*5db58fafSMartin KaFai Lau 	int i;
71*5db58fafSMartin KaFai Lau 
72*5db58fafSMartin KaFai Lau 	start_time = time_get_ns();
73*5db58fafSMartin KaFai Lau 	for (i = 0; i < MAX_CNT; i++)
74*5db58fafSMartin KaFai Lau 		syscall(__NR_getppid);
75*5db58fafSMartin KaFai Lau 	printf("%d:lru_hash_map_perf pre-alloc %lld events per sec\n",
76*5db58fafSMartin KaFai Lau 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
77*5db58fafSMartin KaFai Lau }
78*5db58fafSMartin KaFai Lau 
7926e90931SAlexei Starovoitov static void test_percpu_hash_prealloc(int cpu)
8026e90931SAlexei Starovoitov {
8126e90931SAlexei Starovoitov 	__u64 start_time;
8226e90931SAlexei Starovoitov 	int i;
8326e90931SAlexei Starovoitov 
8426e90931SAlexei Starovoitov 	start_time = time_get_ns();
8526e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
8626e90931SAlexei Starovoitov 		syscall(__NR_geteuid);
8726e90931SAlexei Starovoitov 	printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n",
8826e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
8926e90931SAlexei Starovoitov }
9026e90931SAlexei Starovoitov 
9126e90931SAlexei Starovoitov static void test_hash_kmalloc(int cpu)
9226e90931SAlexei Starovoitov {
9326e90931SAlexei Starovoitov 	__u64 start_time;
9426e90931SAlexei Starovoitov 	int i;
9526e90931SAlexei Starovoitov 
9626e90931SAlexei Starovoitov 	start_time = time_get_ns();
9726e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
9826e90931SAlexei Starovoitov 		syscall(__NR_getgid);
9926e90931SAlexei Starovoitov 	printf("%d:hash_map_perf kmalloc %lld events per sec\n",
10026e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
10126e90931SAlexei Starovoitov }
10226e90931SAlexei Starovoitov 
10326e90931SAlexei Starovoitov static void test_percpu_hash_kmalloc(int cpu)
10426e90931SAlexei Starovoitov {
10526e90931SAlexei Starovoitov 	__u64 start_time;
10626e90931SAlexei Starovoitov 	int i;
10726e90931SAlexei Starovoitov 
10826e90931SAlexei Starovoitov 	start_time = time_get_ns();
10926e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
11026e90931SAlexei Starovoitov 		syscall(__NR_getegid);
11126e90931SAlexei Starovoitov 	printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n",
11226e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
11326e90931SAlexei Starovoitov }
11426e90931SAlexei Starovoitov 
11526e90931SAlexei Starovoitov static void loop(int cpu)
11626e90931SAlexei Starovoitov {
11726e90931SAlexei Starovoitov 	cpu_set_t cpuset;
11826e90931SAlexei Starovoitov 
11926e90931SAlexei Starovoitov 	CPU_ZERO(&cpuset);
12026e90931SAlexei Starovoitov 	CPU_SET(cpu, &cpuset);
12126e90931SAlexei Starovoitov 	sched_setaffinity(0, sizeof(cpuset), &cpuset);
12226e90931SAlexei Starovoitov 
12326e90931SAlexei Starovoitov 	if (test_flags & HASH_PREALLOC)
12426e90931SAlexei Starovoitov 		test_hash_prealloc(cpu);
12526e90931SAlexei Starovoitov 
12626e90931SAlexei Starovoitov 	if (test_flags & PERCPU_HASH_PREALLOC)
12726e90931SAlexei Starovoitov 		test_percpu_hash_prealloc(cpu);
12826e90931SAlexei Starovoitov 
12926e90931SAlexei Starovoitov 	if (test_flags & HASH_KMALLOC)
13026e90931SAlexei Starovoitov 		test_hash_kmalloc(cpu);
13126e90931SAlexei Starovoitov 
13226e90931SAlexei Starovoitov 	if (test_flags & PERCPU_HASH_KMALLOC)
13326e90931SAlexei Starovoitov 		test_percpu_hash_kmalloc(cpu);
134*5db58fafSMartin KaFai Lau 
135*5db58fafSMartin KaFai Lau 	if (test_flags & LRU_HASH_PREALLOC)
136*5db58fafSMartin KaFai Lau 		test_lru_hash_prealloc(cpu);
137*5db58fafSMartin KaFai Lau 
138*5db58fafSMartin KaFai Lau 	if (test_flags & PERCPU_LRU_HASH_PREALLOC)
139*5db58fafSMartin KaFai Lau 		test_percpu_lru_hash_prealloc(cpu);
14026e90931SAlexei Starovoitov }
14126e90931SAlexei Starovoitov 
14226e90931SAlexei Starovoitov static void run_perf_test(int tasks)
14326e90931SAlexei Starovoitov {
14426e90931SAlexei Starovoitov 	pid_t pid[tasks];
14526e90931SAlexei Starovoitov 	int i;
14626e90931SAlexei Starovoitov 
14726e90931SAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
14826e90931SAlexei Starovoitov 		pid[i] = fork();
14926e90931SAlexei Starovoitov 		if (pid[i] == 0) {
15026e90931SAlexei Starovoitov 			loop(i);
15126e90931SAlexei Starovoitov 			exit(0);
15226e90931SAlexei Starovoitov 		} else if (pid[i] == -1) {
15326e90931SAlexei Starovoitov 			printf("couldn't spawn #%d process\n", i);
15426e90931SAlexei Starovoitov 			exit(1);
15526e90931SAlexei Starovoitov 		}
15626e90931SAlexei Starovoitov 	}
15726e90931SAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
15826e90931SAlexei Starovoitov 		int status;
15926e90931SAlexei Starovoitov 
16026e90931SAlexei Starovoitov 		assert(waitpid(pid[i], &status, 0) == pid[i]);
16126e90931SAlexei Starovoitov 		assert(status == 0);
16226e90931SAlexei Starovoitov 	}
16326e90931SAlexei Starovoitov }
16426e90931SAlexei Starovoitov 
16526e90931SAlexei Starovoitov int main(int argc, char **argv)
16626e90931SAlexei Starovoitov {
16726e90931SAlexei Starovoitov 	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
16826e90931SAlexei Starovoitov 	char filename[256];
16926e90931SAlexei Starovoitov 	int num_cpu = 8;
17026e90931SAlexei Starovoitov 
17126e90931SAlexei Starovoitov 	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
17226e90931SAlexei Starovoitov 	setrlimit(RLIMIT_MEMLOCK, &r);
17326e90931SAlexei Starovoitov 
17426e90931SAlexei Starovoitov 	if (argc > 1)
17526e90931SAlexei Starovoitov 		test_flags = atoi(argv[1]) ? : test_flags;
17626e90931SAlexei Starovoitov 
17726e90931SAlexei Starovoitov 	if (argc > 2)
17826e90931SAlexei Starovoitov 		num_cpu = atoi(argv[2]) ? : num_cpu;
17926e90931SAlexei Starovoitov 
18026e90931SAlexei Starovoitov 	if (load_bpf_file(filename)) {
18126e90931SAlexei Starovoitov 		printf("%s", bpf_log_buf);
18226e90931SAlexei Starovoitov 		return 1;
18326e90931SAlexei Starovoitov 	}
18426e90931SAlexei Starovoitov 
18526e90931SAlexei Starovoitov 	run_perf_test(num_cpu);
18626e90931SAlexei Starovoitov 
18726e90931SAlexei Starovoitov 	return 0;
18826e90931SAlexei Starovoitov }
189