18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2020 Facebook */ 38c2ecf20Sopenharmony_ci#define _GNU_SOURCE 48c2ecf20Sopenharmony_ci#include <argp.h> 58c2ecf20Sopenharmony_ci#include <linux/compiler.h> 68c2ecf20Sopenharmony_ci#include <sys/time.h> 78c2ecf20Sopenharmony_ci#include <sched.h> 88c2ecf20Sopenharmony_ci#include <fcntl.h> 98c2ecf20Sopenharmony_ci#include <pthread.h> 108c2ecf20Sopenharmony_ci#include <sys/sysinfo.h> 118c2ecf20Sopenharmony_ci#include <sys/resource.h> 128c2ecf20Sopenharmony_ci#include <signal.h> 138c2ecf20Sopenharmony_ci#include "bench.h" 148c2ecf20Sopenharmony_ci#include "testing_helpers.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct env env = { 178c2ecf20Sopenharmony_ci .warmup_sec = 1, 188c2ecf20Sopenharmony_ci .duration_sec = 5, 198c2ecf20Sopenharmony_ci .affinity = false, 208c2ecf20Sopenharmony_ci .consumer_cnt = 1, 218c2ecf20Sopenharmony_ci .producer_cnt = 1, 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int libbpf_print_fn(enum libbpf_print_level level, 258c2ecf20Sopenharmony_ci const char *format, va_list args) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci if (level == LIBBPF_DEBUG && !env.verbose) 288c2ecf20Sopenharmony_ci return 0; 298c2ecf20Sopenharmony_ci return vfprintf(stderr, format, args); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int bump_memlock_rlimit(void) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct rlimit rlim_new = { 358c2ecf20Sopenharmony_ci .rlim_cur = RLIM_INFINITY, 368c2ecf20Sopenharmony_ci .rlim_max = RLIM_INFINITY, 378c2ecf20Sopenharmony_ci }; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci return setrlimit(RLIMIT_MEMLOCK, &rlim_new); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_civoid setup_libbpf() 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int err; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci libbpf_set_print(libbpf_print_fn); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci err = bump_memlock_rlimit(); 498c2ecf20Sopenharmony_ci if (err) 508c2ecf20Sopenharmony_ci fprintf(stderr, "failed to increase RLIMIT_MEMLOCK: %d", err); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_civoid hits_drops_report_progress(int iter, struct bench_res *res, long delta_ns) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci double hits_per_sec, drops_per_sec; 568c2ecf20Sopenharmony_ci double hits_per_prod; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci hits_per_sec = res->hits / 1000000.0 / (delta_ns / 1000000000.0); 598c2ecf20Sopenharmony_ci hits_per_prod = hits_per_sec / env.producer_cnt; 608c2ecf20Sopenharmony_ci drops_per_sec = res->drops / 1000000.0 / (delta_ns / 1000000000.0); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci printf("Iter %3d (%7.3lfus): ", 638c2ecf20Sopenharmony_ci iter, (delta_ns - 1000000000) / 1000.0); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci printf("hits %8.3lfM/s (%7.3lfM/prod), drops %8.3lfM/s\n", 668c2ecf20Sopenharmony_ci hits_per_sec, hits_per_prod, drops_per_sec); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid hits_drops_report_final(struct bench_res res[], int res_cnt) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int i; 728c2ecf20Sopenharmony_ci double hits_mean = 0.0, drops_mean = 0.0; 738c2ecf20Sopenharmony_ci double hits_stddev = 0.0, drops_stddev = 0.0; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci for (i = 0; i < res_cnt; i++) { 768c2ecf20Sopenharmony_ci hits_mean += res[i].hits / 1000000.0 / (0.0 + res_cnt); 778c2ecf20Sopenharmony_ci drops_mean += res[i].drops / 1000000.0 / (0.0 + res_cnt); 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (res_cnt > 1) { 818c2ecf20Sopenharmony_ci for (i = 0; i < res_cnt; i++) { 828c2ecf20Sopenharmony_ci hits_stddev += (hits_mean - res[i].hits / 1000000.0) * 838c2ecf20Sopenharmony_ci (hits_mean - res[i].hits / 1000000.0) / 848c2ecf20Sopenharmony_ci (res_cnt - 1.0); 858c2ecf20Sopenharmony_ci drops_stddev += (drops_mean - res[i].drops / 1000000.0) * 868c2ecf20Sopenharmony_ci (drops_mean - res[i].drops / 1000000.0) / 878c2ecf20Sopenharmony_ci (res_cnt - 1.0); 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci hits_stddev = sqrt(hits_stddev); 908c2ecf20Sopenharmony_ci drops_stddev = sqrt(drops_stddev); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci printf("Summary: hits %8.3lf \u00B1 %5.3lfM/s (%7.3lfM/prod), ", 938c2ecf20Sopenharmony_ci hits_mean, hits_stddev, hits_mean / env.producer_cnt); 948c2ecf20Sopenharmony_ci printf("drops %8.3lf \u00B1 %5.3lfM/s\n", 958c2ecf20Sopenharmony_ci drops_mean, drops_stddev); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ciconst char *argp_program_version = "benchmark"; 998c2ecf20Sopenharmony_ciconst char *argp_program_bug_address = "<bpf@vger.kernel.org>"; 1008c2ecf20Sopenharmony_ciconst char argp_program_doc[] = 1018c2ecf20Sopenharmony_ci"benchmark Generic benchmarking framework.\n" 1028c2ecf20Sopenharmony_ci"\n" 1038c2ecf20Sopenharmony_ci"This tool runs benchmarks.\n" 1048c2ecf20Sopenharmony_ci"\n" 1058c2ecf20Sopenharmony_ci"USAGE: benchmark <bench-name>\n" 1068c2ecf20Sopenharmony_ci"\n" 1078c2ecf20Sopenharmony_ci"EXAMPLES:\n" 1088c2ecf20Sopenharmony_ci" # run 'count-local' benchmark with 1 producer and 1 consumer\n" 1098c2ecf20Sopenharmony_ci" benchmark count-local\n" 1108c2ecf20Sopenharmony_ci" # run 'count-local' with 16 producer and 8 consumer thread, pinned to CPUs\n" 1118c2ecf20Sopenharmony_ci" benchmark -p16 -c8 -a count-local\n"; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cienum { 1148c2ecf20Sopenharmony_ci ARG_PROD_AFFINITY_SET = 1000, 1158c2ecf20Sopenharmony_ci ARG_CONS_AFFINITY_SET = 1001, 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic const struct argp_option opts[] = { 1198c2ecf20Sopenharmony_ci { "list", 'l', NULL, 0, "List available benchmarks"}, 1208c2ecf20Sopenharmony_ci { "duration", 'd', "SEC", 0, "Duration of benchmark, seconds"}, 1218c2ecf20Sopenharmony_ci { "warmup", 'w', "SEC", 0, "Warm-up period, seconds"}, 1228c2ecf20Sopenharmony_ci { "producers", 'p', "NUM", 0, "Number of producer threads"}, 1238c2ecf20Sopenharmony_ci { "consumers", 'c', "NUM", 0, "Number of consumer threads"}, 1248c2ecf20Sopenharmony_ci { "verbose", 'v', NULL, 0, "Verbose debug output"}, 1258c2ecf20Sopenharmony_ci { "affinity", 'a', NULL, 0, "Set consumer/producer thread affinity"}, 1268c2ecf20Sopenharmony_ci { "prod-affinity", ARG_PROD_AFFINITY_SET, "CPUSET", 0, 1278c2ecf20Sopenharmony_ci "Set of CPUs for producer threads; implies --affinity"}, 1288c2ecf20Sopenharmony_ci { "cons-affinity", ARG_CONS_AFFINITY_SET, "CPUSET", 0, 1298c2ecf20Sopenharmony_ci "Set of CPUs for consumer threads; implies --affinity"}, 1308c2ecf20Sopenharmony_ci {}, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciextern struct argp bench_ringbufs_argp; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic const struct argp_child bench_parsers[] = { 1368c2ecf20Sopenharmony_ci { &bench_ringbufs_argp, 0, "Ring buffers benchmark", 0 }, 1378c2ecf20Sopenharmony_ci {}, 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic error_t parse_arg(int key, char *arg, struct argp_state *state) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci static int pos_args; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci switch (key) { 1458c2ecf20Sopenharmony_ci case 'v': 1468c2ecf20Sopenharmony_ci env.verbose = true; 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci case 'l': 1498c2ecf20Sopenharmony_ci env.list = true; 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci case 'd': 1528c2ecf20Sopenharmony_ci env.duration_sec = strtol(arg, NULL, 10); 1538c2ecf20Sopenharmony_ci if (env.duration_sec <= 0) { 1548c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid duration: %s\n", arg); 1558c2ecf20Sopenharmony_ci argp_usage(state); 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci case 'w': 1598c2ecf20Sopenharmony_ci env.warmup_sec = strtol(arg, NULL, 10); 1608c2ecf20Sopenharmony_ci if (env.warmup_sec <= 0) { 1618c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid warm-up duration: %s\n", arg); 1628c2ecf20Sopenharmony_ci argp_usage(state); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci case 'p': 1668c2ecf20Sopenharmony_ci env.producer_cnt = strtol(arg, NULL, 10); 1678c2ecf20Sopenharmony_ci if (env.producer_cnt <= 0) { 1688c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid producer count: %s\n", arg); 1698c2ecf20Sopenharmony_ci argp_usage(state); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci case 'c': 1738c2ecf20Sopenharmony_ci env.consumer_cnt = strtol(arg, NULL, 10); 1748c2ecf20Sopenharmony_ci if (env.consumer_cnt <= 0) { 1758c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid consumer count: %s\n", arg); 1768c2ecf20Sopenharmony_ci argp_usage(state); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci case 'a': 1808c2ecf20Sopenharmony_ci env.affinity = true; 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci case ARG_PROD_AFFINITY_SET: 1838c2ecf20Sopenharmony_ci env.affinity = true; 1848c2ecf20Sopenharmony_ci if (parse_num_list(arg, &env.prod_cpus.cpus, 1858c2ecf20Sopenharmony_ci &env.prod_cpus.cpus_len)) { 1868c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid format of CPU set for producers."); 1878c2ecf20Sopenharmony_ci argp_usage(state); 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci case ARG_CONS_AFFINITY_SET: 1918c2ecf20Sopenharmony_ci env.affinity = true; 1928c2ecf20Sopenharmony_ci if (parse_num_list(arg, &env.cons_cpus.cpus, 1938c2ecf20Sopenharmony_ci &env.cons_cpus.cpus_len)) { 1948c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid format of CPU set for consumers."); 1958c2ecf20Sopenharmony_ci argp_usage(state); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci case ARGP_KEY_ARG: 1998c2ecf20Sopenharmony_ci if (pos_args++) { 2008c2ecf20Sopenharmony_ci fprintf(stderr, 2018c2ecf20Sopenharmony_ci "Unrecognized positional argument: %s\n", arg); 2028c2ecf20Sopenharmony_ci argp_usage(state); 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci env.bench_name = strdup(arg); 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci default: 2078c2ecf20Sopenharmony_ci return ARGP_ERR_UNKNOWN; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci return 0; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic void parse_cmdline_args(int argc, char **argv) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci static const struct argp argp = { 2158c2ecf20Sopenharmony_ci .options = opts, 2168c2ecf20Sopenharmony_ci .parser = parse_arg, 2178c2ecf20Sopenharmony_ci .doc = argp_program_doc, 2188c2ecf20Sopenharmony_ci .children = bench_parsers, 2198c2ecf20Sopenharmony_ci }; 2208c2ecf20Sopenharmony_ci if (argp_parse(&argp, argc, argv, 0, NULL, NULL)) 2218c2ecf20Sopenharmony_ci exit(1); 2228c2ecf20Sopenharmony_ci if (!env.list && !env.bench_name) { 2238c2ecf20Sopenharmony_ci argp_help(&argp, stderr, ARGP_HELP_DOC, "bench"); 2248c2ecf20Sopenharmony_ci exit(1); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void collect_measurements(long delta_ns); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic __u64 last_time_ns; 2318c2ecf20Sopenharmony_cistatic void sigalarm_handler(int signo) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci long new_time_ns = get_time_ns(); 2348c2ecf20Sopenharmony_ci long delta_ns = new_time_ns - last_time_ns; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci collect_measurements(delta_ns); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci last_time_ns = new_time_ns; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* set up periodic 1-second timer */ 2428c2ecf20Sopenharmony_cistatic void setup_timer() 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci static struct sigaction sigalarm_action = { 2458c2ecf20Sopenharmony_ci .sa_handler = sigalarm_handler, 2468c2ecf20Sopenharmony_ci }; 2478c2ecf20Sopenharmony_ci struct itimerval timer_settings = {}; 2488c2ecf20Sopenharmony_ci int err; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci last_time_ns = get_time_ns(); 2518c2ecf20Sopenharmony_ci err = sigaction(SIGALRM, &sigalarm_action, NULL); 2528c2ecf20Sopenharmony_ci if (err < 0) { 2538c2ecf20Sopenharmony_ci fprintf(stderr, "failed to install SIGALRM handler: %d\n", -errno); 2548c2ecf20Sopenharmony_ci exit(1); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci timer_settings.it_interval.tv_sec = 1; 2578c2ecf20Sopenharmony_ci timer_settings.it_value.tv_sec = 1; 2588c2ecf20Sopenharmony_ci err = setitimer(ITIMER_REAL, &timer_settings, NULL); 2598c2ecf20Sopenharmony_ci if (err < 0) { 2608c2ecf20Sopenharmony_ci fprintf(stderr, "failed to arm interval timer: %d\n", -errno); 2618c2ecf20Sopenharmony_ci exit(1); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void set_thread_affinity(pthread_t thread, int cpu) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci cpu_set_t cpuset; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci CPU_ZERO(&cpuset); 2708c2ecf20Sopenharmony_ci CPU_SET(cpu, &cpuset); 2718c2ecf20Sopenharmony_ci if (pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset)) { 2728c2ecf20Sopenharmony_ci fprintf(stderr, "setting affinity to CPU #%d failed: %d\n", 2738c2ecf20Sopenharmony_ci cpu, errno); 2748c2ecf20Sopenharmony_ci exit(1); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int next_cpu(struct cpu_set *cpu_set) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci if (cpu_set->cpus) { 2818c2ecf20Sopenharmony_ci int i; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* find next available CPU */ 2848c2ecf20Sopenharmony_ci for (i = cpu_set->next_cpu; i < cpu_set->cpus_len; i++) { 2858c2ecf20Sopenharmony_ci if (cpu_set->cpus[i]) { 2868c2ecf20Sopenharmony_ci cpu_set->next_cpu = i + 1; 2878c2ecf20Sopenharmony_ci return i; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci fprintf(stderr, "Not enough CPUs specified, need CPU #%d or higher.\n", i); 2918c2ecf20Sopenharmony_ci exit(1); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return cpu_set->next_cpu++; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic struct bench_state { 2988c2ecf20Sopenharmony_ci int res_cnt; 2998c2ecf20Sopenharmony_ci struct bench_res *results; 3008c2ecf20Sopenharmony_ci pthread_t *consumers; 3018c2ecf20Sopenharmony_ci pthread_t *producers; 3028c2ecf20Sopenharmony_ci} state; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciconst struct bench *bench = NULL; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ciextern const struct bench bench_count_global; 3078c2ecf20Sopenharmony_ciextern const struct bench bench_count_local; 3088c2ecf20Sopenharmony_ciextern const struct bench bench_rename_base; 3098c2ecf20Sopenharmony_ciextern const struct bench bench_rename_kprobe; 3108c2ecf20Sopenharmony_ciextern const struct bench bench_rename_kretprobe; 3118c2ecf20Sopenharmony_ciextern const struct bench bench_rename_rawtp; 3128c2ecf20Sopenharmony_ciextern const struct bench bench_rename_fentry; 3138c2ecf20Sopenharmony_ciextern const struct bench bench_rename_fexit; 3148c2ecf20Sopenharmony_ciextern const struct bench bench_trig_base; 3158c2ecf20Sopenharmony_ciextern const struct bench bench_trig_tp; 3168c2ecf20Sopenharmony_ciextern const struct bench bench_trig_rawtp; 3178c2ecf20Sopenharmony_ciextern const struct bench bench_trig_kprobe; 3188c2ecf20Sopenharmony_ciextern const struct bench bench_trig_fentry; 3198c2ecf20Sopenharmony_ciextern const struct bench bench_trig_fentry_sleep; 3208c2ecf20Sopenharmony_ciextern const struct bench bench_trig_fmodret; 3218c2ecf20Sopenharmony_ciextern const struct bench bench_rb_libbpf; 3228c2ecf20Sopenharmony_ciextern const struct bench bench_rb_custom; 3238c2ecf20Sopenharmony_ciextern const struct bench bench_pb_libbpf; 3248c2ecf20Sopenharmony_ciextern const struct bench bench_pb_custom; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic const struct bench *benchs[] = { 3278c2ecf20Sopenharmony_ci &bench_count_global, 3288c2ecf20Sopenharmony_ci &bench_count_local, 3298c2ecf20Sopenharmony_ci &bench_rename_base, 3308c2ecf20Sopenharmony_ci &bench_rename_kprobe, 3318c2ecf20Sopenharmony_ci &bench_rename_kretprobe, 3328c2ecf20Sopenharmony_ci &bench_rename_rawtp, 3338c2ecf20Sopenharmony_ci &bench_rename_fentry, 3348c2ecf20Sopenharmony_ci &bench_rename_fexit, 3358c2ecf20Sopenharmony_ci &bench_trig_base, 3368c2ecf20Sopenharmony_ci &bench_trig_tp, 3378c2ecf20Sopenharmony_ci &bench_trig_rawtp, 3388c2ecf20Sopenharmony_ci &bench_trig_kprobe, 3398c2ecf20Sopenharmony_ci &bench_trig_fentry, 3408c2ecf20Sopenharmony_ci &bench_trig_fentry_sleep, 3418c2ecf20Sopenharmony_ci &bench_trig_fmodret, 3428c2ecf20Sopenharmony_ci &bench_rb_libbpf, 3438c2ecf20Sopenharmony_ci &bench_rb_custom, 3448c2ecf20Sopenharmony_ci &bench_pb_libbpf, 3458c2ecf20Sopenharmony_ci &bench_pb_custom, 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic void setup_benchmark() 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci int i, err; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (!env.bench_name) { 3538c2ecf20Sopenharmony_ci fprintf(stderr, "benchmark name is not specified\n"); 3548c2ecf20Sopenharmony_ci exit(1); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(benchs); i++) { 3588c2ecf20Sopenharmony_ci if (strcmp(benchs[i]->name, env.bench_name) == 0) { 3598c2ecf20Sopenharmony_ci bench = benchs[i]; 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci if (!bench) { 3648c2ecf20Sopenharmony_ci fprintf(stderr, "benchmark '%s' not found\n", env.bench_name); 3658c2ecf20Sopenharmony_ci exit(1); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci printf("Setting up benchmark '%s'...\n", bench->name); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci state.producers = calloc(env.producer_cnt, sizeof(*state.producers)); 3718c2ecf20Sopenharmony_ci state.consumers = calloc(env.consumer_cnt, sizeof(*state.consumers)); 3728c2ecf20Sopenharmony_ci state.results = calloc(env.duration_sec + env.warmup_sec + 2, 3738c2ecf20Sopenharmony_ci sizeof(*state.results)); 3748c2ecf20Sopenharmony_ci if (!state.producers || !state.consumers || !state.results) 3758c2ecf20Sopenharmony_ci exit(1); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (bench->validate) 3788c2ecf20Sopenharmony_ci bench->validate(); 3798c2ecf20Sopenharmony_ci if (bench->setup) 3808c2ecf20Sopenharmony_ci bench->setup(); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci for (i = 0; i < env.consumer_cnt; i++) { 3838c2ecf20Sopenharmony_ci err = pthread_create(&state.consumers[i], NULL, 3848c2ecf20Sopenharmony_ci bench->consumer_thread, (void *)(long)i); 3858c2ecf20Sopenharmony_ci if (err) { 3868c2ecf20Sopenharmony_ci fprintf(stderr, "failed to create consumer thread #%d: %d\n", 3878c2ecf20Sopenharmony_ci i, -errno); 3888c2ecf20Sopenharmony_ci exit(1); 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci if (env.affinity) 3918c2ecf20Sopenharmony_ci set_thread_affinity(state.consumers[i], 3928c2ecf20Sopenharmony_ci next_cpu(&env.cons_cpus)); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* unless explicit producer CPU list is specified, continue after 3968c2ecf20Sopenharmony_ci * last consumer CPU 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci if (!env.prod_cpus.cpus) 3998c2ecf20Sopenharmony_ci env.prod_cpus.next_cpu = env.cons_cpus.next_cpu; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci for (i = 0; i < env.producer_cnt; i++) { 4028c2ecf20Sopenharmony_ci err = pthread_create(&state.producers[i], NULL, 4038c2ecf20Sopenharmony_ci bench->producer_thread, (void *)(long)i); 4048c2ecf20Sopenharmony_ci if (err) { 4058c2ecf20Sopenharmony_ci fprintf(stderr, "failed to create producer thread #%d: %d\n", 4068c2ecf20Sopenharmony_ci i, -errno); 4078c2ecf20Sopenharmony_ci exit(1); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci if (env.affinity) 4108c2ecf20Sopenharmony_ci set_thread_affinity(state.producers[i], 4118c2ecf20Sopenharmony_ci next_cpu(&env.prod_cpus)); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci printf("Benchmark '%s' started.\n", bench->name); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic pthread_mutex_t bench_done_mtx = PTHREAD_MUTEX_INITIALIZER; 4188c2ecf20Sopenharmony_cistatic pthread_cond_t bench_done = PTHREAD_COND_INITIALIZER; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void collect_measurements(long delta_ns) { 4218c2ecf20Sopenharmony_ci int iter = state.res_cnt++; 4228c2ecf20Sopenharmony_ci struct bench_res *res = &state.results[iter]; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci bench->measure(res); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (bench->report_progress) 4278c2ecf20Sopenharmony_ci bench->report_progress(iter, res, delta_ns); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (iter == env.duration_sec + env.warmup_sec) { 4308c2ecf20Sopenharmony_ci pthread_mutex_lock(&bench_done_mtx); 4318c2ecf20Sopenharmony_ci pthread_cond_signal(&bench_done); 4328c2ecf20Sopenharmony_ci pthread_mutex_unlock(&bench_done_mtx); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ciint main(int argc, char **argv) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci parse_cmdline_args(argc, argv); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (env.list) { 4418c2ecf20Sopenharmony_ci int i; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci printf("Available benchmarks:\n"); 4448c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(benchs); i++) { 4458c2ecf20Sopenharmony_ci printf("- %s\n", benchs[i]->name); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci setup_benchmark(); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci setup_timer(); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci pthread_mutex_lock(&bench_done_mtx); 4558c2ecf20Sopenharmony_ci pthread_cond_wait(&bench_done, &bench_done_mtx); 4568c2ecf20Sopenharmony_ci pthread_mutex_unlock(&bench_done_mtx); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (bench->report_final) 4598c2ecf20Sopenharmony_ci /* skip first sample */ 4608c2ecf20Sopenharmony_ci bench->report_final(state.results + env.warmup_sec, 4618c2ecf20Sopenharmony_ci state.res_cnt - env.warmup_sec); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci} 465