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