blob: 2a12f48b5c6dca672564af26105fb2cf5922aa21 [file] [log] [blame]
Alexei Starovoitov26e90932016-03-08 15:07:54 -08001/* 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>
Naveen N. Rao77e63532016-04-04 22:31:32 +053020#include <sys/resource.h>
Martin KaFai Laubf8db5d2017-04-14 10:30:27 -070021#include <arpa/inet.h>
22#include <errno.h>
23
Alexei Starovoitov26e90932016-03-08 15:07:54 -080024#include "libbpf.h"
25#include "bpf_load.h"
26
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -070027#define TEST_BIT(t) (1U << (t))
Alexei Starovoitov26e90932016-03-08 15:07:54 -080028
29static __u64 time_get_ns(void)
30{
31 struct timespec ts;
32
33 clock_gettime(CLOCK_MONOTONIC, &ts);
34 return ts.tv_sec * 1000000000ull + ts.tv_nsec;
35}
36
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -070037enum test_type {
38 HASH_PREALLOC,
39 PERCPU_HASH_PREALLOC,
40 HASH_KMALLOC,
41 PERCPU_HASH_KMALLOC,
42 LRU_HASH_PREALLOC,
43 NOCOMMON_LRU_HASH_PREALLOC,
44 LPM_KMALLOC,
45 HASH_LOOKUP,
46 ARRAY_LOOKUP,
47 NR_TESTS,
48};
49
50const char *test_map_names[NR_TESTS] = {
51 [HASH_PREALLOC] = "hash_map",
52 [PERCPU_HASH_PREALLOC] = "percpu_hash_map",
53 [HASH_KMALLOC] = "hash_map_alloc",
54 [PERCPU_HASH_KMALLOC] = "percpu_hash_map_alloc",
55 [LRU_HASH_PREALLOC] = "lru_hash_map",
56 [NOCOMMON_LRU_HASH_PREALLOC] = "nocommon_lru_hash_map",
57 [LPM_KMALLOC] = "lpm_trie_map_alloc",
58 [HASH_LOOKUP] = "hash_map",
59 [ARRAY_LOOKUP] = "array_map",
60};
Alexei Starovoitov26e90932016-03-08 15:07:54 -080061
62static int test_flags = ~0;
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -070063static uint32_t num_map_entries;
64static uint32_t max_cnt = 1000000;
65
66static int check_test_flags(enum test_type t)
67{
68 return test_flags & TEST_BIT(t);
69}
Alexei Starovoitov26e90932016-03-08 15:07:54 -080070
71static void test_hash_prealloc(int cpu)
72{
73 __u64 start_time;
74 int i;
75
76 start_time = time_get_ns();
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -070077 for (i = 0; i < max_cnt; i++)
Alexei Starovoitov26e90932016-03-08 15:07:54 -080078 syscall(__NR_getuid);
79 printf("%d:hash_map_perf pre-alloc %lld events per sec\n",
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -070080 cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
Alexei Starovoitov26e90932016-03-08 15:07:54 -080081}
82
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -070083static void do_test_lru(enum test_type test, int cpu)
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080084{
Martin KaFai Laubf8db5d2017-04-14 10:30:27 -070085 struct sockaddr_in6 in6 = { .sin6_family = AF_INET6 };
86 const char *test_name;
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -080087 __u64 start_time;
Martin KaFai Laubf8db5d2017-04-14 10:30:27 -070088 int i, ret;
89
90 in6.sin6_addr.s6_addr16[0] = 0xdead;
91 in6.sin6_addr.s6_addr16[1] = 0xbeef;
92
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -070093 if (test == LRU_HASH_PREALLOC) {
Martin KaFai Laubf8db5d2017-04-14 10:30:27 -070094 test_name = "lru_hash_map_perf";
95 in6.sin6_addr.s6_addr16[7] = 0;
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -070096 } else if (test == NOCOMMON_LRU_HASH_PREALLOC) {
Martin KaFai Laubf8db5d2017-04-14 10:30:27 -070097 test_name = "nocommon_lru_hash_map_perf";
98 in6.sin6_addr.s6_addr16[7] = 1;
99 } else {
100 assert(0);
101 }
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800102
103 start_time = time_get_ns();
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700104 for (i = 0; i < max_cnt; i++) {
Martin KaFai Laubf8db5d2017-04-14 10:30:27 -0700105 ret = connect(-1, (const struct sockaddr *)&in6, sizeof(in6));
106 assert(ret == -1 && errno == EBADF);
107 }
108 printf("%d:%s pre-alloc %lld events per sec\n",
109 cpu, test_name,
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700110 max_cnt * 1000000000ll / (time_get_ns() - start_time));
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800111}
112
Martin KaFai Laubf8db5d2017-04-14 10:30:27 -0700113static void test_lru_hash_prealloc(int cpu)
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800114{
Martin KaFai Laubf8db5d2017-04-14 10:30:27 -0700115 do_test_lru(LRU_HASH_PREALLOC, cpu);
116}
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800117
Martin KaFai Laubf8db5d2017-04-14 10:30:27 -0700118static void test_nocommon_lru_hash_prealloc(int cpu)
119{
120 do_test_lru(NOCOMMON_LRU_HASH_PREALLOC, cpu);
Martin KaFai Lau5db58fa2016-11-11 10:55:11 -0800121}
122
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800123static void test_percpu_hash_prealloc(int cpu)
124{
125 __u64 start_time;
126 int i;
127
128 start_time = time_get_ns();
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700129 for (i = 0; i < max_cnt; i++)
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800130 syscall(__NR_geteuid);
131 printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n",
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700132 cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800133}
134
135static void test_hash_kmalloc(int cpu)
136{
137 __u64 start_time;
138 int i;
139
140 start_time = time_get_ns();
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700141 for (i = 0; i < max_cnt; i++)
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800142 syscall(__NR_getgid);
143 printf("%d:hash_map_perf kmalloc %lld events per sec\n",
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700144 cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800145}
146
147static void test_percpu_hash_kmalloc(int cpu)
148{
149 __u64 start_time;
150 int i;
151
152 start_time = time_get_ns();
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700153 for (i = 0; i < max_cnt; i++)
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800154 syscall(__NR_getegid);
155 printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n",
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700156 cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800157}
158
David Herrmannb8a943e2017-01-21 17:26:13 +0100159static void test_lpm_kmalloc(int cpu)
160{
161 __u64 start_time;
162 int i;
163
164 start_time = time_get_ns();
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700165 for (i = 0; i < max_cnt; i++)
David Herrmannb8a943e2017-01-21 17:26:13 +0100166 syscall(__NR_gettid);
167 printf("%d:lpm_perf kmalloc %lld events per sec\n",
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700168 cpu, max_cnt * 1000000000ll / (time_get_ns() - start_time));
David Herrmannb8a943e2017-01-21 17:26:13 +0100169}
170
Alexei Starovoitov95ff1412017-03-15 18:26:44 -0700171static void test_hash_lookup(int cpu)
172{
173 __u64 start_time;
174 int i;
175
176 start_time = time_get_ns();
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700177 for (i = 0; i < max_cnt; i++)
Alexei Starovoitov95ff1412017-03-15 18:26:44 -0700178 syscall(__NR_getpgid, 0);
179 printf("%d:hash_lookup %lld lookups per sec\n",
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700180 cpu, max_cnt * 1000000000ll * 64 / (time_get_ns() - start_time));
Alexei Starovoitov95ff1412017-03-15 18:26:44 -0700181}
182
183static void test_array_lookup(int cpu)
184{
185 __u64 start_time;
186 int i;
187
188 start_time = time_get_ns();
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700189 for (i = 0; i < max_cnt; i++)
Alexei Starovoitov95ff1412017-03-15 18:26:44 -0700190 syscall(__NR_getpgrp, 0);
191 printf("%d:array_lookup %lld lookups per sec\n",
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700192 cpu, max_cnt * 1000000000ll * 64 / (time_get_ns() - start_time));
Alexei Starovoitov95ff1412017-03-15 18:26:44 -0700193}
194
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700195typedef void (*test_func)(int cpu);
196const test_func test_funcs[] = {
197 [HASH_PREALLOC] = test_hash_prealloc,
198 [PERCPU_HASH_PREALLOC] = test_percpu_hash_prealloc,
199 [HASH_KMALLOC] = test_hash_kmalloc,
200 [PERCPU_HASH_KMALLOC] = test_percpu_hash_kmalloc,
201 [LRU_HASH_PREALLOC] = test_lru_hash_prealloc,
202 [NOCOMMON_LRU_HASH_PREALLOC] = test_nocommon_lru_hash_prealloc,
203 [LPM_KMALLOC] = test_lpm_kmalloc,
204 [HASH_LOOKUP] = test_hash_lookup,
205 [ARRAY_LOOKUP] = test_array_lookup,
206};
207
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800208static void loop(int cpu)
209{
210 cpu_set_t cpuset;
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700211 int i;
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800212
213 CPU_ZERO(&cpuset);
214 CPU_SET(cpu, &cpuset);
215 sched_setaffinity(0, sizeof(cpuset), &cpuset);
216
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700217 for (i = 0; i < NR_TESTS; i++) {
218 if (check_test_flags(i))
219 test_funcs[i](cpu);
220 }
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800221}
222
223static void run_perf_test(int tasks)
224{
225 pid_t pid[tasks];
226 int i;
227
228 for (i = 0; i < tasks; i++) {
229 pid[i] = fork();
230 if (pid[i] == 0) {
231 loop(i);
232 exit(0);
233 } else if (pid[i] == -1) {
234 printf("couldn't spawn #%d process\n", i);
235 exit(1);
236 }
237 }
238 for (i = 0; i < tasks; i++) {
239 int status;
240
241 assert(waitpid(pid[i], &status, 0) == pid[i]);
242 assert(status == 0);
243 }
244}
245
David Herrmannb8a943e2017-01-21 17:26:13 +0100246static void fill_lpm_trie(void)
247{
248 struct bpf_lpm_trie_key *key;
249 unsigned long value = 0;
250 unsigned int i;
251 int r;
252
253 key = alloca(sizeof(*key) + 4);
254 key->prefixlen = 32;
255
256 for (i = 0; i < 512; ++i) {
257 key->prefixlen = rand() % 33;
258 key->data[0] = rand() & 0xff;
259 key->data[1] = rand() & 0xff;
260 key->data[2] = rand() & 0xff;
261 key->data[3] = rand() & 0xff;
262 r = bpf_map_update_elem(map_fd[6], key, &value, 0);
263 assert(!r);
264 }
265
266 key->prefixlen = 32;
267 key->data[0] = 192;
268 key->data[1] = 168;
269 key->data[2] = 0;
270 key->data[3] = 1;
271 value = 128;
272
273 r = bpf_map_update_elem(map_fd[6], key, &value, 0);
274 assert(!r);
275}
276
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700277static void fixup_map(struct bpf_map_def *map, const char *name, int idx)
278{
279 int i;
280
281 if (num_map_entries <= 0)
282 return;
283
284 /* Only change the max_entries for the enabled test(s) */
285 for (i = 0; i < NR_TESTS; i++) {
286 if (!strcmp(test_map_names[i], name) &&
287 (check_test_flags(i))) {
288 map->max_entries = num_map_entries;
289 }
290 }
291}
292
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800293int main(int argc, char **argv)
294{
295 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
296 char filename[256];
297 int num_cpu = 8;
298
299 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
300 setrlimit(RLIMIT_MEMLOCK, &r);
301
302 if (argc > 1)
303 test_flags = atoi(argv[1]) ? : test_flags;
304
305 if (argc > 2)
306 num_cpu = atoi(argv[2]) ? : num_cpu;
307
Martin KaFai Lau9fd63d02017-04-14 10:30:28 -0700308 if (argc > 3)
309 num_map_entries = atoi(argv[3]);
310
311 if (argc > 4)
312 max_cnt = atoi(argv[4]);
313
314 if (load_bpf_file_fixup_map(filename, fixup_map)) {
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800315 printf("%s", bpf_log_buf);
316 return 1;
317 }
318
David Herrmannb8a943e2017-01-21 17:26:13 +0100319 fill_lpm_trie();
320
Alexei Starovoitov26e90932016-03-08 15:07:54 -0800321 run_perf_test(num_cpu);
322
323 return 0;
324}