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 41 static int test_flags = ~0; 42 43 static void test_hash_prealloc(int cpu) 44 { 45 __u64 start_time; 46 int i; 47 48 start_time = time_get_ns(); 49 for (i = 0; i < MAX_CNT; i++) 50 syscall(__NR_getuid); 51 printf("%d:hash_map_perf pre-alloc %lld events per sec\n", 52 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 53 } 54 55 static void test_lru_hash_prealloc(int cpu) 56 { 57 __u64 start_time; 58 int i; 59 60 start_time = time_get_ns(); 61 for (i = 0; i < MAX_CNT; i++) 62 syscall(__NR_getpid); 63 printf("%d:lru_hash_map_perf pre-alloc %lld events per sec\n", 64 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 65 } 66 67 static void test_percpu_lru_hash_prealloc(int cpu) 68 { 69 __u64 start_time; 70 int i; 71 72 start_time = time_get_ns(); 73 for (i = 0; i < MAX_CNT; i++) 74 syscall(__NR_getppid); 75 printf("%d:lru_hash_map_perf pre-alloc %lld events per sec\n", 76 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 77 } 78 79 static void test_percpu_hash_prealloc(int cpu) 80 { 81 __u64 start_time; 82 int i; 83 84 start_time = time_get_ns(); 85 for (i = 0; i < MAX_CNT; i++) 86 syscall(__NR_geteuid); 87 printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n", 88 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 89 } 90 91 static void test_hash_kmalloc(int cpu) 92 { 93 __u64 start_time; 94 int i; 95 96 start_time = time_get_ns(); 97 for (i = 0; i < MAX_CNT; i++) 98 syscall(__NR_getgid); 99 printf("%d:hash_map_perf kmalloc %lld events per sec\n", 100 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 101 } 102 103 static void test_percpu_hash_kmalloc(int cpu) 104 { 105 __u64 start_time; 106 int i; 107 108 start_time = time_get_ns(); 109 for (i = 0; i < MAX_CNT; i++) 110 syscall(__NR_getegid); 111 printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n", 112 cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 113 } 114 115 static void loop(int cpu) 116 { 117 cpu_set_t cpuset; 118 119 CPU_ZERO(&cpuset); 120 CPU_SET(cpu, &cpuset); 121 sched_setaffinity(0, sizeof(cpuset), &cpuset); 122 123 if (test_flags & HASH_PREALLOC) 124 test_hash_prealloc(cpu); 125 126 if (test_flags & PERCPU_HASH_PREALLOC) 127 test_percpu_hash_prealloc(cpu); 128 129 if (test_flags & HASH_KMALLOC) 130 test_hash_kmalloc(cpu); 131 132 if (test_flags & PERCPU_HASH_KMALLOC) 133 test_percpu_hash_kmalloc(cpu); 134 135 if (test_flags & LRU_HASH_PREALLOC) 136 test_lru_hash_prealloc(cpu); 137 138 if (test_flags & PERCPU_LRU_HASH_PREALLOC) 139 test_percpu_lru_hash_prealloc(cpu); 140 } 141 142 static void run_perf_test(int tasks) 143 { 144 pid_t pid[tasks]; 145 int i; 146 147 for (i = 0; i < tasks; i++) { 148 pid[i] = fork(); 149 if (pid[i] == 0) { 150 loop(i); 151 exit(0); 152 } else if (pid[i] == -1) { 153 printf("couldn't spawn #%d process\n", i); 154 exit(1); 155 } 156 } 157 for (i = 0; i < tasks; i++) { 158 int status; 159 160 assert(waitpid(pid[i], &status, 0) == pid[i]); 161 assert(status == 0); 162 } 163 } 164 165 int main(int argc, char **argv) 166 { 167 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 168 char filename[256]; 169 int num_cpu = 8; 170 171 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 172 setrlimit(RLIMIT_MEMLOCK, &r); 173 174 if (argc > 1) 175 test_flags = atoi(argv[1]) ? : test_flags; 176 177 if (argc > 2) 178 num_cpu = atoi(argv[2]) ? : num_cpu; 179 180 if (load_bpf_file(filename)) { 181 printf("%s", bpf_log_buf); 182 return 1; 183 } 184 185 run_perf_test(num_cpu); 186 187 return 0; 188 } 189