xref: /openbmc/linux/samples/bpf/map_perf_test_user.c (revision 4f139972b489f8bc2c821aa25ac65018d92af3f7)
1 /* Copyright (c) 2016 Facebook
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of version 2 of the GNU General Public
5  * License as published by the Free Software Foundation.
6  */
7 #define _GNU_SOURCE
8 #include <sched.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <asm/unistd.h>
12 #include <unistd.h>
13 #include <assert.h>
14 #include <sys/wait.h>
15 #include <stdlib.h>
16 #include <signal.h>
17 #include <linux/bpf.h>
18 #include <string.h>
19 #include <time.h>
20 #include <sys/resource.h>
21 #include "libbpf.h"
22 #include "bpf_load.h"
23 
24 #define MAX_CNT 1000000
25 
26 static __u64 time_get_ns(void)
27 {
28 	struct timespec ts;
29 
30 	clock_gettime(CLOCK_MONOTONIC, &ts);
31 	return ts.tv_sec * 1000000000ull + ts.tv_nsec;
32 }
33 
34 #define HASH_PREALLOC		(1 << 0)
35 #define PERCPU_HASH_PREALLOC	(1 << 1)
36 #define HASH_KMALLOC		(1 << 2)
37 #define PERCPU_HASH_KMALLOC	(1 << 3)
38 #define LRU_HASH_PREALLOC	(1 << 4)
39 #define PERCPU_LRU_HASH_PREALLOC	(1 << 5)
40 #define LPM_KMALLOC		(1 << 6)
41 #define HASH_LOOKUP		(1 << 7)
42 #define ARRAY_LOOKUP		(1 << 8)
43 
44 static int test_flags = ~0;
45 
46 static void test_hash_prealloc(int cpu)
47 {
48 	__u64 start_time;
49 	int i;
50 
51 	start_time = time_get_ns();
52 	for (i = 0; i < MAX_CNT; i++)
53 		syscall(__NR_getuid);
54 	printf("%d:hash_map_perf pre-alloc %lld events per sec\n",
55 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
56 }
57 
58 static void test_lru_hash_prealloc(int cpu)
59 {
60 	__u64 start_time;
61 	int i;
62 
63 	start_time = time_get_ns();
64 	for (i = 0; i < MAX_CNT; i++)
65 		syscall(__NR_getpid);
66 	printf("%d:lru_hash_map_perf pre-alloc %lld events per sec\n",
67 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
68 }
69 
70 static void test_percpu_lru_hash_prealloc(int cpu)
71 {
72 	__u64 start_time;
73 	int i;
74 
75 	start_time = time_get_ns();
76 	for (i = 0; i < MAX_CNT; i++)
77 		syscall(__NR_getppid);
78 	printf("%d:lru_hash_map_perf pre-alloc %lld events per sec\n",
79 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
80 }
81 
82 static void test_percpu_hash_prealloc(int cpu)
83 {
84 	__u64 start_time;
85 	int i;
86 
87 	start_time = time_get_ns();
88 	for (i = 0; i < MAX_CNT; i++)
89 		syscall(__NR_geteuid);
90 	printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n",
91 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
92 }
93 
94 static void test_hash_kmalloc(int cpu)
95 {
96 	__u64 start_time;
97 	int i;
98 
99 	start_time = time_get_ns();
100 	for (i = 0; i < MAX_CNT; i++)
101 		syscall(__NR_getgid);
102 	printf("%d:hash_map_perf kmalloc %lld events per sec\n",
103 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
104 }
105 
106 static void test_percpu_hash_kmalloc(int cpu)
107 {
108 	__u64 start_time;
109 	int i;
110 
111 	start_time = time_get_ns();
112 	for (i = 0; i < MAX_CNT; i++)
113 		syscall(__NR_getegid);
114 	printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n",
115 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
116 }
117 
118 static void test_lpm_kmalloc(int cpu)
119 {
120 	__u64 start_time;
121 	int i;
122 
123 	start_time = time_get_ns();
124 	for (i = 0; i < MAX_CNT; i++)
125 		syscall(__NR_gettid);
126 	printf("%d:lpm_perf kmalloc %lld events per sec\n",
127 	       cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
128 }
129 
130 static void test_hash_lookup(int cpu)
131 {
132 	__u64 start_time;
133 	int i;
134 
135 	start_time = time_get_ns();
136 	for (i = 0; i < MAX_CNT; i++)
137 		syscall(__NR_getpgid, 0);
138 	printf("%d:hash_lookup %lld lookups per sec\n",
139 	       cpu, MAX_CNT * 1000000000ll * 64 / (time_get_ns() - start_time));
140 }
141 
142 static void test_array_lookup(int cpu)
143 {
144 	__u64 start_time;
145 	int i;
146 
147 	start_time = time_get_ns();
148 	for (i = 0; i < MAX_CNT; i++)
149 		syscall(__NR_getpgrp, 0);
150 	printf("%d:array_lookup %lld lookups per sec\n",
151 	       cpu, MAX_CNT * 1000000000ll * 64 / (time_get_ns() - start_time));
152 }
153 
154 static void loop(int cpu)
155 {
156 	cpu_set_t cpuset;
157 
158 	CPU_ZERO(&cpuset);
159 	CPU_SET(cpu, &cpuset);
160 	sched_setaffinity(0, sizeof(cpuset), &cpuset);
161 
162 	if (test_flags & HASH_PREALLOC)
163 		test_hash_prealloc(cpu);
164 
165 	if (test_flags & PERCPU_HASH_PREALLOC)
166 		test_percpu_hash_prealloc(cpu);
167 
168 	if (test_flags & HASH_KMALLOC)
169 		test_hash_kmalloc(cpu);
170 
171 	if (test_flags & PERCPU_HASH_KMALLOC)
172 		test_percpu_hash_kmalloc(cpu);
173 
174 	if (test_flags & LRU_HASH_PREALLOC)
175 		test_lru_hash_prealloc(cpu);
176 
177 	if (test_flags & PERCPU_LRU_HASH_PREALLOC)
178 		test_percpu_lru_hash_prealloc(cpu);
179 
180 	if (test_flags & LPM_KMALLOC)
181 		test_lpm_kmalloc(cpu);
182 
183 	if (test_flags & HASH_LOOKUP)
184 		test_hash_lookup(cpu);
185 
186 	if (test_flags & ARRAY_LOOKUP)
187 		test_array_lookup(cpu);
188 }
189 
190 static void run_perf_test(int tasks)
191 {
192 	pid_t pid[tasks];
193 	int i;
194 
195 	for (i = 0; i < tasks; i++) {
196 		pid[i] = fork();
197 		if (pid[i] == 0) {
198 			loop(i);
199 			exit(0);
200 		} else if (pid[i] == -1) {
201 			printf("couldn't spawn #%d process\n", i);
202 			exit(1);
203 		}
204 	}
205 	for (i = 0; i < tasks; i++) {
206 		int status;
207 
208 		assert(waitpid(pid[i], &status, 0) == pid[i]);
209 		assert(status == 0);
210 	}
211 }
212 
213 static void fill_lpm_trie(void)
214 {
215 	struct bpf_lpm_trie_key *key;
216 	unsigned long value = 0;
217 	unsigned int i;
218 	int r;
219 
220 	key = alloca(sizeof(*key) + 4);
221 	key->prefixlen = 32;
222 
223 	for (i = 0; i < 512; ++i) {
224 		key->prefixlen = rand() % 33;
225 		key->data[0] = rand() & 0xff;
226 		key->data[1] = rand() & 0xff;
227 		key->data[2] = rand() & 0xff;
228 		key->data[3] = rand() & 0xff;
229 		r = bpf_map_update_elem(map_fd[6], key, &value, 0);
230 		assert(!r);
231 	}
232 
233 	key->prefixlen = 32;
234 	key->data[0] = 192;
235 	key->data[1] = 168;
236 	key->data[2] = 0;
237 	key->data[3] = 1;
238 	value = 128;
239 
240 	r = bpf_map_update_elem(map_fd[6], key, &value, 0);
241 	assert(!r);
242 }
243 
244 int main(int argc, char **argv)
245 {
246 	struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
247 	char filename[256];
248 	int num_cpu = 8;
249 
250 	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
251 	setrlimit(RLIMIT_MEMLOCK, &r);
252 
253 	if (argc > 1)
254 		test_flags = atoi(argv[1]) ? : test_flags;
255 
256 	if (argc > 2)
257 		num_cpu = atoi(argv[2]) ? : num_cpu;
258 
259 	if (load_bpf_file(filename)) {
260 		printf("%s", bpf_log_buf);
261 		return 1;
262 	}
263 
264 	fill_lpm_trie();
265 
266 	run_perf_test(num_cpu);
267 
268 	return 0;
269 }
270