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