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