1*26e90931SAlexei Starovoitov /* Copyright (c) 2016 Facebook 2*26e90931SAlexei Starovoitov * 3*26e90931SAlexei Starovoitov * This program is free software; you can redistribute it and/or 4*26e90931SAlexei Starovoitov * modify it under the terms of version 2 of the GNU General Public 5*26e90931SAlexei Starovoitov * License as published by the Free Software Foundation. 6*26e90931SAlexei Starovoitov */ 7*26e90931SAlexei Starovoitov #define _GNU_SOURCE 8*26e90931SAlexei Starovoitov #include <sched.h> 9*26e90931SAlexei Starovoitov #include <stdio.h> 10*26e90931SAlexei Starovoitov #include <sys/types.h> 11*26e90931SAlexei Starovoitov #include <asm/unistd.h> 12*26e90931SAlexei Starovoitov #include <unistd.h> 13*26e90931SAlexei Starovoitov #include <assert.h> 14*26e90931SAlexei Starovoitov #include <sys/wait.h> 15*26e90931SAlexei Starovoitov #include <stdlib.h> 16*26e90931SAlexei Starovoitov #include <signal.h> 17*26e90931SAlexei Starovoitov #include <linux/bpf.h> 18*26e90931SAlexei Starovoitov #include <string.h> 19*26e90931SAlexei Starovoitov #include <time.h> 20*26e90931SAlexei Starovoitov #include "libbpf.h" 21*26e90931SAlexei Starovoitov #include "bpf_load.h" 22*26e90931SAlexei Starovoitov 23*26e90931SAlexei Starovoitov #define MAX_CNT 1000000 24*26e90931SAlexei Starovoitov 25*26e90931SAlexei Starovoitov static __u64 time_get_ns(void) 26*26e90931SAlexei Starovoitov { 27*26e90931SAlexei Starovoitov struct timespec ts; 28*26e90931SAlexei Starovoitov 29*26e90931SAlexei Starovoitov clock_gettime(CLOCK_MONOTONIC, &ts); 30*26e90931SAlexei Starovoitov return ts.tv_sec * 1000000000ull + ts.tv_nsec; 31*26e90931SAlexei Starovoitov } 32*26e90931SAlexei Starovoitov 33*26e90931SAlexei Starovoitov #define HASH_PREALLOC (1 << 0) 34*26e90931SAlexei Starovoitov #define PERCPU_HASH_PREALLOC (1 << 1) 35*26e90931SAlexei Starovoitov #define HASH_KMALLOC (1 << 2) 36*26e90931SAlexei Starovoitov #define PERCPU_HASH_KMALLOC (1 << 3) 37*26e90931SAlexei Starovoitov 38*26e90931SAlexei Starovoitov static int test_flags = ~0; 39*26e90931SAlexei Starovoitov 40*26e90931SAlexei Starovoitov static void test_hash_prealloc(int cpu) 41*26e90931SAlexei Starovoitov { 42*26e90931SAlexei Starovoitov __u64 start_time; 43*26e90931SAlexei Starovoitov int i; 44*26e90931SAlexei Starovoitov 45*26e90931SAlexei Starovoitov start_time = time_get_ns(); 46*26e90931SAlexei Starovoitov for (i = 0; i < MAX_CNT; i++) 47*26e90931SAlexei Starovoitov syscall(__NR_getuid); 48*26e90931SAlexei Starovoitov printf("%d:hash_map_perf pre-alloc %lld events per sec\n", 49*26e90931SAlexei Starovoitov cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 50*26e90931SAlexei Starovoitov } 51*26e90931SAlexei Starovoitov 52*26e90931SAlexei Starovoitov static void test_percpu_hash_prealloc(int cpu) 53*26e90931SAlexei Starovoitov { 54*26e90931SAlexei Starovoitov __u64 start_time; 55*26e90931SAlexei Starovoitov int i; 56*26e90931SAlexei Starovoitov 57*26e90931SAlexei Starovoitov start_time = time_get_ns(); 58*26e90931SAlexei Starovoitov for (i = 0; i < MAX_CNT; i++) 59*26e90931SAlexei Starovoitov syscall(__NR_geteuid); 60*26e90931SAlexei Starovoitov printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n", 61*26e90931SAlexei Starovoitov cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 62*26e90931SAlexei Starovoitov } 63*26e90931SAlexei Starovoitov 64*26e90931SAlexei Starovoitov static void test_hash_kmalloc(int cpu) 65*26e90931SAlexei Starovoitov { 66*26e90931SAlexei Starovoitov __u64 start_time; 67*26e90931SAlexei Starovoitov int i; 68*26e90931SAlexei Starovoitov 69*26e90931SAlexei Starovoitov start_time = time_get_ns(); 70*26e90931SAlexei Starovoitov for (i = 0; i < MAX_CNT; i++) 71*26e90931SAlexei Starovoitov syscall(__NR_getgid); 72*26e90931SAlexei Starovoitov printf("%d:hash_map_perf kmalloc %lld events per sec\n", 73*26e90931SAlexei Starovoitov cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 74*26e90931SAlexei Starovoitov } 75*26e90931SAlexei Starovoitov 76*26e90931SAlexei Starovoitov static void test_percpu_hash_kmalloc(int cpu) 77*26e90931SAlexei Starovoitov { 78*26e90931SAlexei Starovoitov __u64 start_time; 79*26e90931SAlexei Starovoitov int i; 80*26e90931SAlexei Starovoitov 81*26e90931SAlexei Starovoitov start_time = time_get_ns(); 82*26e90931SAlexei Starovoitov for (i = 0; i < MAX_CNT; i++) 83*26e90931SAlexei Starovoitov syscall(__NR_getegid); 84*26e90931SAlexei Starovoitov printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n", 85*26e90931SAlexei Starovoitov cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); 86*26e90931SAlexei Starovoitov } 87*26e90931SAlexei Starovoitov 88*26e90931SAlexei Starovoitov static void loop(int cpu) 89*26e90931SAlexei Starovoitov { 90*26e90931SAlexei Starovoitov cpu_set_t cpuset; 91*26e90931SAlexei Starovoitov 92*26e90931SAlexei Starovoitov CPU_ZERO(&cpuset); 93*26e90931SAlexei Starovoitov CPU_SET(cpu, &cpuset); 94*26e90931SAlexei Starovoitov sched_setaffinity(0, sizeof(cpuset), &cpuset); 95*26e90931SAlexei Starovoitov 96*26e90931SAlexei Starovoitov if (test_flags & HASH_PREALLOC) 97*26e90931SAlexei Starovoitov test_hash_prealloc(cpu); 98*26e90931SAlexei Starovoitov 99*26e90931SAlexei Starovoitov if (test_flags & PERCPU_HASH_PREALLOC) 100*26e90931SAlexei Starovoitov test_percpu_hash_prealloc(cpu); 101*26e90931SAlexei Starovoitov 102*26e90931SAlexei Starovoitov if (test_flags & HASH_KMALLOC) 103*26e90931SAlexei Starovoitov test_hash_kmalloc(cpu); 104*26e90931SAlexei Starovoitov 105*26e90931SAlexei Starovoitov if (test_flags & PERCPU_HASH_KMALLOC) 106*26e90931SAlexei Starovoitov test_percpu_hash_kmalloc(cpu); 107*26e90931SAlexei Starovoitov } 108*26e90931SAlexei Starovoitov 109*26e90931SAlexei Starovoitov static void run_perf_test(int tasks) 110*26e90931SAlexei Starovoitov { 111*26e90931SAlexei Starovoitov pid_t pid[tasks]; 112*26e90931SAlexei Starovoitov int i; 113*26e90931SAlexei Starovoitov 114*26e90931SAlexei Starovoitov for (i = 0; i < tasks; i++) { 115*26e90931SAlexei Starovoitov pid[i] = fork(); 116*26e90931SAlexei Starovoitov if (pid[i] == 0) { 117*26e90931SAlexei Starovoitov loop(i); 118*26e90931SAlexei Starovoitov exit(0); 119*26e90931SAlexei Starovoitov } else if (pid[i] == -1) { 120*26e90931SAlexei Starovoitov printf("couldn't spawn #%d process\n", i); 121*26e90931SAlexei Starovoitov exit(1); 122*26e90931SAlexei Starovoitov } 123*26e90931SAlexei Starovoitov } 124*26e90931SAlexei Starovoitov for (i = 0; i < tasks; i++) { 125*26e90931SAlexei Starovoitov int status; 126*26e90931SAlexei Starovoitov 127*26e90931SAlexei Starovoitov assert(waitpid(pid[i], &status, 0) == pid[i]); 128*26e90931SAlexei Starovoitov assert(status == 0); 129*26e90931SAlexei Starovoitov } 130*26e90931SAlexei Starovoitov } 131*26e90931SAlexei Starovoitov 132*26e90931SAlexei Starovoitov int main(int argc, char **argv) 133*26e90931SAlexei Starovoitov { 134*26e90931SAlexei Starovoitov struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 135*26e90931SAlexei Starovoitov char filename[256]; 136*26e90931SAlexei Starovoitov int num_cpu = 8; 137*26e90931SAlexei Starovoitov 138*26e90931SAlexei Starovoitov snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 139*26e90931SAlexei Starovoitov setrlimit(RLIMIT_MEMLOCK, &r); 140*26e90931SAlexei Starovoitov 141*26e90931SAlexei Starovoitov if (argc > 1) 142*26e90931SAlexei Starovoitov test_flags = atoi(argv[1]) ? : test_flags; 143*26e90931SAlexei Starovoitov 144*26e90931SAlexei Starovoitov if (argc > 2) 145*26e90931SAlexei Starovoitov num_cpu = atoi(argv[2]) ? : num_cpu; 146*26e90931SAlexei Starovoitov 147*26e90931SAlexei Starovoitov if (load_bpf_file(filename)) { 148*26e90931SAlexei Starovoitov printf("%s", bpf_log_buf); 149*26e90931SAlexei Starovoitov return 1; 150*26e90931SAlexei Starovoitov } 151*26e90931SAlexei Starovoitov 152*26e90931SAlexei Starovoitov run_perf_test(num_cpu); 153*26e90931SAlexei Starovoitov 154*26e90931SAlexei Starovoitov return 0; 155*26e90931SAlexei Starovoitov } 156