1*26e90931SAlexei Starovoitov /* Copyright (c) 2016 Facebook
2*26e90931SAlexei Starovoitov  *
3*26e90931SAlexei Starovoitov  * This program is free software; you can redistribute it and/or
4*26e90931SAlexei Starovoitov  * modify it under the terms of version 2 of the GNU General Public
5*26e90931SAlexei Starovoitov  * License as published by the Free Software Foundation.
6*26e90931SAlexei Starovoitov  */
7*26e90931SAlexei Starovoitov #define _GNU_SOURCE
8*26e90931SAlexei Starovoitov #include <sched.h>
9*26e90931SAlexei Starovoitov #include <stdio.h>
10*26e90931SAlexei Starovoitov #include <sys/types.h>
11*26e90931SAlexei Starovoitov #include <asm/unistd.h>
12*26e90931SAlexei Starovoitov #include <unistd.h>
13*26e90931SAlexei Starovoitov #include <assert.h>
14*26e90931SAlexei Starovoitov #include <sys/wait.h>
15*26e90931SAlexei Starovoitov #include <stdlib.h>
16*26e90931SAlexei Starovoitov #include <signal.h>
17*26e90931SAlexei Starovoitov #include <linux/bpf.h>
18*26e90931SAlexei Starovoitov #include <string.h>
19*26e90931SAlexei Starovoitov #include <time.h>
20*26e90931SAlexei Starovoitov #include "libbpf.h"
21*26e90931SAlexei Starovoitov #include "bpf_load.h"
22*26e90931SAlexei Starovoitov 
23*26e90931SAlexei Starovoitov #define MAX_CNT 1000000
24*26e90931SAlexei Starovoitov 
25*26e90931SAlexei Starovoitov static __u64 time_get_ns(void)
26*26e90931SAlexei Starovoitov {
27*26e90931SAlexei Starovoitov 	struct timespec ts;
28*26e90931SAlexei Starovoitov 
29*26e90931SAlexei Starovoitov 	clock_gettime(CLOCK_MONOTONIC, &ts);
30*26e90931SAlexei Starovoitov 	return ts.tv_sec * 1000000000ull + ts.tv_nsec;
31*26e90931SAlexei Starovoitov }
32*26e90931SAlexei Starovoitov 
33*26e90931SAlexei Starovoitov #define HASH_PREALLOC		(1 << 0)
34*26e90931SAlexei Starovoitov #define PERCPU_HASH_PREALLOC	(1 << 1)
35*26e90931SAlexei Starovoitov #define HASH_KMALLOC		(1 << 2)
36*26e90931SAlexei Starovoitov #define PERCPU_HASH_KMALLOC	(1 << 3)
37*26e90931SAlexei Starovoitov 
38*26e90931SAlexei Starovoitov static int test_flags = ~0;
39*26e90931SAlexei Starovoitov 
40*26e90931SAlexei Starovoitov static void test_hash_prealloc(int cpu)
41*26e90931SAlexei Starovoitov {
42*26e90931SAlexei Starovoitov 	__u64 start_time;
43*26e90931SAlexei Starovoitov 	int i;
44*26e90931SAlexei Starovoitov 
45*26e90931SAlexei Starovoitov 	start_time = time_get_ns();
46*26e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
47*26e90931SAlexei Starovoitov 		syscall(__NR_getuid);
48*26e90931SAlexei Starovoitov 	printf("%d:hash_map_perf pre-alloc %lld events per sec\n",
49*26e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
50*26e90931SAlexei Starovoitov }
51*26e90931SAlexei Starovoitov 
52*26e90931SAlexei Starovoitov static void test_percpu_hash_prealloc(int cpu)
53*26e90931SAlexei Starovoitov {
54*26e90931SAlexei Starovoitov 	__u64 start_time;
55*26e90931SAlexei Starovoitov 	int i;
56*26e90931SAlexei Starovoitov 
57*26e90931SAlexei Starovoitov 	start_time = time_get_ns();
58*26e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
59*26e90931SAlexei Starovoitov 		syscall(__NR_geteuid);
60*26e90931SAlexei Starovoitov 	printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n",
61*26e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
62*26e90931SAlexei Starovoitov }
63*26e90931SAlexei Starovoitov 
64*26e90931SAlexei Starovoitov static void test_hash_kmalloc(int cpu)
65*26e90931SAlexei Starovoitov {
66*26e90931SAlexei Starovoitov 	__u64 start_time;
67*26e90931SAlexei Starovoitov 	int i;
68*26e90931SAlexei Starovoitov 
69*26e90931SAlexei Starovoitov 	start_time = time_get_ns();
70*26e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
71*26e90931SAlexei Starovoitov 		syscall(__NR_getgid);
72*26e90931SAlexei Starovoitov 	printf("%d:hash_map_perf kmalloc %lld events per sec\n",
73*26e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
74*26e90931SAlexei Starovoitov }
75*26e90931SAlexei Starovoitov 
76*26e90931SAlexei Starovoitov static void test_percpu_hash_kmalloc(int cpu)
77*26e90931SAlexei Starovoitov {
78*26e90931SAlexei Starovoitov 	__u64 start_time;
79*26e90931SAlexei Starovoitov 	int i;
80*26e90931SAlexei Starovoitov 
81*26e90931SAlexei Starovoitov 	start_time = time_get_ns();
82*26e90931SAlexei Starovoitov 	for (i = 0; i < MAX_CNT; i++)
83*26e90931SAlexei Starovoitov 		syscall(__NR_getegid);
84*26e90931SAlexei Starovoitov 	printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n",
85*26e90931SAlexei Starovoitov 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
86*26e90931SAlexei Starovoitov }
87*26e90931SAlexei Starovoitov 
88*26e90931SAlexei Starovoitov static void loop(int cpu)
89*26e90931SAlexei Starovoitov {
90*26e90931SAlexei Starovoitov 	cpu_set_t cpuset;
91*26e90931SAlexei Starovoitov 
92*26e90931SAlexei Starovoitov 	CPU_ZERO(&cpuset);
93*26e90931SAlexei Starovoitov 	CPU_SET(cpu, &cpuset);
94*26e90931SAlexei Starovoitov 	sched_setaffinity(0, sizeof(cpuset), &cpuset);
95*26e90931SAlexei Starovoitov 
96*26e90931SAlexei Starovoitov 	if (test_flags & HASH_PREALLOC)
97*26e90931SAlexei Starovoitov 		test_hash_prealloc(cpu);
98*26e90931SAlexei Starovoitov 
99*26e90931SAlexei Starovoitov 	if (test_flags & PERCPU_HASH_PREALLOC)
100*26e90931SAlexei Starovoitov 		test_percpu_hash_prealloc(cpu);
101*26e90931SAlexei Starovoitov 
102*26e90931SAlexei Starovoitov 	if (test_flags & HASH_KMALLOC)
103*26e90931SAlexei Starovoitov 		test_hash_kmalloc(cpu);
104*26e90931SAlexei Starovoitov 
105*26e90931SAlexei Starovoitov 	if (test_flags & PERCPU_HASH_KMALLOC)
106*26e90931SAlexei Starovoitov 		test_percpu_hash_kmalloc(cpu);
107*26e90931SAlexei Starovoitov }
108*26e90931SAlexei Starovoitov 
109*26e90931SAlexei Starovoitov static void run_perf_test(int tasks)
110*26e90931SAlexei Starovoitov {
111*26e90931SAlexei Starovoitov 	pid_t pid[tasks];
112*26e90931SAlexei Starovoitov 	int i;
113*26e90931SAlexei Starovoitov 
114*26e90931SAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
115*26e90931SAlexei Starovoitov 		pid[i] = fork();
116*26e90931SAlexei Starovoitov 		if (pid[i] == 0) {
117*26e90931SAlexei Starovoitov 			loop(i);
118*26e90931SAlexei Starovoitov 			exit(0);
119*26e90931SAlexei Starovoitov 		} else if (pid[i] == -1) {
120*26e90931SAlexei Starovoitov 			printf("couldn't spawn #%d process\n", i);
121*26e90931SAlexei Starovoitov 			exit(1);
122*26e90931SAlexei Starovoitov 		}
123*26e90931SAlexei Starovoitov 	}
124*26e90931SAlexei Starovoitov 	for (i = 0; i < tasks; i++) {
125*26e90931SAlexei Starovoitov 		int status;
126*26e90931SAlexei Starovoitov 
127*26e90931SAlexei Starovoitov 		assert(waitpid(pid[i], &status, 0) == pid[i]);
128*26e90931SAlexei Starovoitov 		assert(status == 0);
129*26e90931SAlexei Starovoitov 	}
130*26e90931SAlexei Starovoitov }
131*26e90931SAlexei Starovoitov 
132*26e90931SAlexei Starovoitov int main(int argc, char **argv)
133*26e90931SAlexei Starovoitov {
134*26e90931SAlexei Starovoitov 	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
135*26e90931SAlexei Starovoitov 	char filename[256];
136*26e90931SAlexei Starovoitov 	int num_cpu = 8;
137*26e90931SAlexei Starovoitov 
138*26e90931SAlexei Starovoitov 	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
139*26e90931SAlexei Starovoitov 	setrlimit(RLIMIT_MEMLOCK, &r);
140*26e90931SAlexei Starovoitov 
141*26e90931SAlexei Starovoitov 	if (argc > 1)
142*26e90931SAlexei Starovoitov 		test_flags = atoi(argv[1]) ? : test_flags;
143*26e90931SAlexei Starovoitov 
144*26e90931SAlexei Starovoitov 	if (argc > 2)
145*26e90931SAlexei Starovoitov 		num_cpu = atoi(argv[2]) ? : num_cpu;
146*26e90931SAlexei Starovoitov 
147*26e90931SAlexei Starovoitov 	if (load_bpf_file(filename)) {
148*26e90931SAlexei Starovoitov 		printf("%s", bpf_log_buf);
149*26e90931SAlexei Starovoitov 		return 1;
150*26e90931SAlexei Starovoitov 	}
151*26e90931SAlexei Starovoitov 
152*26e90931SAlexei Starovoitov 	run_perf_test(num_cpu);
153*26e90931SAlexei Starovoitov 
154*26e90931SAlexei Starovoitov 	return 0;
155*26e90931SAlexei Starovoitov }
156