162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2020 Facebook */ 362306a36Sopenharmony_ci#define _GNU_SOURCE 462306a36Sopenharmony_ci#include <argp.h> 562306a36Sopenharmony_ci#include <linux/compiler.h> 662306a36Sopenharmony_ci#include <sys/time.h> 762306a36Sopenharmony_ci#include <sched.h> 862306a36Sopenharmony_ci#include <fcntl.h> 962306a36Sopenharmony_ci#include <pthread.h> 1062306a36Sopenharmony_ci#include <sys/sysinfo.h> 1162306a36Sopenharmony_ci#include <signal.h> 1262306a36Sopenharmony_ci#include "bench.h" 1362306a36Sopenharmony_ci#include "testing_helpers.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct env env = { 1662306a36Sopenharmony_ci .warmup_sec = 1, 1762306a36Sopenharmony_ci .duration_sec = 5, 1862306a36Sopenharmony_ci .affinity = false, 1962306a36Sopenharmony_ci .quiet = false, 2062306a36Sopenharmony_ci .consumer_cnt = 0, 2162306a36Sopenharmony_ci .producer_cnt = 1, 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int libbpf_print_fn(enum libbpf_print_level level, 2562306a36Sopenharmony_ci const char *format, va_list args) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci if (level == LIBBPF_DEBUG && !env.verbose) 2862306a36Sopenharmony_ci return 0; 2962306a36Sopenharmony_ci return vfprintf(stderr, format, args); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_civoid setup_libbpf(void) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci libbpf_set_strict_mode(LIBBPF_STRICT_ALL); 3562306a36Sopenharmony_ci libbpf_set_print(libbpf_print_fn); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_civoid false_hits_report_progress(int iter, struct bench_res *res, long delta_ns) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci long total = res->false_hits + res->hits + res->drops; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci printf("Iter %3d (%7.3lfus): ", 4362306a36Sopenharmony_ci iter, (delta_ns - 1000000000) / 1000.0); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci printf("%ld false hits of %ld total operations. Percentage = %2.2f %%\n", 4662306a36Sopenharmony_ci res->false_hits, total, ((float)res->false_hits / total) * 100); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_civoid false_hits_report_final(struct bench_res res[], int res_cnt) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci long total_hits = 0, total_drops = 0, total_false_hits = 0, total_ops = 0; 5262306a36Sopenharmony_ci int i; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) { 5562306a36Sopenharmony_ci total_hits += res[i].hits; 5662306a36Sopenharmony_ci total_false_hits += res[i].false_hits; 5762306a36Sopenharmony_ci total_drops += res[i].drops; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci total_ops = total_hits + total_false_hits + total_drops; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci printf("Summary: %ld false hits of %ld total operations. ", 6262306a36Sopenharmony_ci total_false_hits, total_ops); 6362306a36Sopenharmony_ci printf("Percentage = %2.2f %%\n", 6462306a36Sopenharmony_ci ((float)total_false_hits / total_ops) * 100); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_civoid hits_drops_report_progress(int iter, struct bench_res *res, long delta_ns) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci double hits_per_sec, drops_per_sec; 7062306a36Sopenharmony_ci double hits_per_prod; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci hits_per_sec = res->hits / 1000000.0 / (delta_ns / 1000000000.0); 7362306a36Sopenharmony_ci hits_per_prod = hits_per_sec / env.producer_cnt; 7462306a36Sopenharmony_ci drops_per_sec = res->drops / 1000000.0 / (delta_ns / 1000000000.0); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci printf("Iter %3d (%7.3lfus): ", 7762306a36Sopenharmony_ci iter, (delta_ns - 1000000000) / 1000.0); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci printf("hits %8.3lfM/s (%7.3lfM/prod), drops %8.3lfM/s, total operations %8.3lfM/s\n", 8062306a36Sopenharmony_ci hits_per_sec, hits_per_prod, drops_per_sec, hits_per_sec + drops_per_sec); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_civoid 8462306a36Sopenharmony_cigrace_period_latency_basic_stats(struct bench_res res[], int res_cnt, struct basic_stats *gp_stat) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci int i; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci memset(gp_stat, 0, sizeof(struct basic_stats)); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) 9162306a36Sopenharmony_ci gp_stat->mean += res[i].gp_ns / 1000.0 / (double)res[i].gp_ct / (0.0 + res_cnt); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define IT_MEAN_DIFF (res[i].gp_ns / 1000.0 / (double)res[i].gp_ct - gp_stat->mean) 9462306a36Sopenharmony_ci if (res_cnt > 1) { 9562306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) 9662306a36Sopenharmony_ci gp_stat->stddev += (IT_MEAN_DIFF * IT_MEAN_DIFF) / (res_cnt - 1.0); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci gp_stat->stddev = sqrt(gp_stat->stddev); 9962306a36Sopenharmony_ci#undef IT_MEAN_DIFF 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_civoid 10362306a36Sopenharmony_cigrace_period_ticks_basic_stats(struct bench_res res[], int res_cnt, struct basic_stats *gp_stat) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci int i; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci memset(gp_stat, 0, sizeof(struct basic_stats)); 10862306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) 10962306a36Sopenharmony_ci gp_stat->mean += res[i].stime / (double)res[i].gp_ct / (0.0 + res_cnt); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define IT_MEAN_DIFF (res[i].stime / (double)res[i].gp_ct - gp_stat->mean) 11262306a36Sopenharmony_ci if (res_cnt > 1) { 11362306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) 11462306a36Sopenharmony_ci gp_stat->stddev += (IT_MEAN_DIFF * IT_MEAN_DIFF) / (res_cnt - 1.0); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci gp_stat->stddev = sqrt(gp_stat->stddev); 11762306a36Sopenharmony_ci#undef IT_MEAN_DIFF 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_civoid hits_drops_report_final(struct bench_res res[], int res_cnt) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci int i; 12362306a36Sopenharmony_ci double hits_mean = 0.0, drops_mean = 0.0, total_ops_mean = 0.0; 12462306a36Sopenharmony_ci double hits_stddev = 0.0, drops_stddev = 0.0, total_ops_stddev = 0.0; 12562306a36Sopenharmony_ci double total_ops; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) { 12862306a36Sopenharmony_ci hits_mean += res[i].hits / 1000000.0 / (0.0 + res_cnt); 12962306a36Sopenharmony_ci drops_mean += res[i].drops / 1000000.0 / (0.0 + res_cnt); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci total_ops_mean = hits_mean + drops_mean; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (res_cnt > 1) { 13462306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) { 13562306a36Sopenharmony_ci hits_stddev += (hits_mean - res[i].hits / 1000000.0) * 13662306a36Sopenharmony_ci (hits_mean - res[i].hits / 1000000.0) / 13762306a36Sopenharmony_ci (res_cnt - 1.0); 13862306a36Sopenharmony_ci drops_stddev += (drops_mean - res[i].drops / 1000000.0) * 13962306a36Sopenharmony_ci (drops_mean - res[i].drops / 1000000.0) / 14062306a36Sopenharmony_ci (res_cnt - 1.0); 14162306a36Sopenharmony_ci total_ops = res[i].hits + res[i].drops; 14262306a36Sopenharmony_ci total_ops_stddev += (total_ops_mean - total_ops / 1000000.0) * 14362306a36Sopenharmony_ci (total_ops_mean - total_ops / 1000000.0) / 14462306a36Sopenharmony_ci (res_cnt - 1.0); 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci hits_stddev = sqrt(hits_stddev); 14762306a36Sopenharmony_ci drops_stddev = sqrt(drops_stddev); 14862306a36Sopenharmony_ci total_ops_stddev = sqrt(total_ops_stddev); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci printf("Summary: hits %8.3lf \u00B1 %5.3lfM/s (%7.3lfM/prod), ", 15162306a36Sopenharmony_ci hits_mean, hits_stddev, hits_mean / env.producer_cnt); 15262306a36Sopenharmony_ci printf("drops %8.3lf \u00B1 %5.3lfM/s, ", 15362306a36Sopenharmony_ci drops_mean, drops_stddev); 15462306a36Sopenharmony_ci printf("total operations %8.3lf \u00B1 %5.3lfM/s\n", 15562306a36Sopenharmony_ci total_ops_mean, total_ops_stddev); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_civoid ops_report_progress(int iter, struct bench_res *res, long delta_ns) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci double hits_per_sec, hits_per_prod; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci hits_per_sec = res->hits / 1000000.0 / (delta_ns / 1000000000.0); 16362306a36Sopenharmony_ci hits_per_prod = hits_per_sec / env.producer_cnt; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci printf("Iter %3d (%7.3lfus): ", iter, (delta_ns - 1000000000) / 1000.0); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci printf("hits %8.3lfM/s (%7.3lfM/prod)\n", hits_per_sec, hits_per_prod); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_civoid ops_report_final(struct bench_res res[], int res_cnt) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci double hits_mean = 0.0, hits_stddev = 0.0; 17362306a36Sopenharmony_ci int i; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) 17662306a36Sopenharmony_ci hits_mean += res[i].hits / 1000000.0 / (0.0 + res_cnt); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (res_cnt > 1) { 17962306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) 18062306a36Sopenharmony_ci hits_stddev += (hits_mean - res[i].hits / 1000000.0) * 18162306a36Sopenharmony_ci (hits_mean - res[i].hits / 1000000.0) / 18262306a36Sopenharmony_ci (res_cnt - 1.0); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci hits_stddev = sqrt(hits_stddev); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci printf("Summary: throughput %8.3lf \u00B1 %5.3lf M ops/s (%7.3lfM ops/prod), ", 18762306a36Sopenharmony_ci hits_mean, hits_stddev, hits_mean / env.producer_cnt); 18862306a36Sopenharmony_ci printf("latency %8.3lf ns/op\n", 1000.0 / hits_mean * env.producer_cnt); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_civoid local_storage_report_progress(int iter, struct bench_res *res, 19262306a36Sopenharmony_ci long delta_ns) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci double important_hits_per_sec, hits_per_sec; 19562306a36Sopenharmony_ci double delta_sec = delta_ns / 1000000000.0; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci hits_per_sec = res->hits / 1000000.0 / delta_sec; 19862306a36Sopenharmony_ci important_hits_per_sec = res->important_hits / 1000000.0 / delta_sec; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci printf("Iter %3d (%7.3lfus): ", iter, (delta_ns - 1000000000) / 1000.0); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci printf("hits %8.3lfM/s ", hits_per_sec); 20362306a36Sopenharmony_ci printf("important_hits %8.3lfM/s\n", important_hits_per_sec); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_civoid local_storage_report_final(struct bench_res res[], int res_cnt) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci double important_hits_mean = 0.0, important_hits_stddev = 0.0; 20962306a36Sopenharmony_ci double hits_mean = 0.0, hits_stddev = 0.0; 21062306a36Sopenharmony_ci int i; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) { 21362306a36Sopenharmony_ci hits_mean += res[i].hits / 1000000.0 / (0.0 + res_cnt); 21462306a36Sopenharmony_ci important_hits_mean += res[i].important_hits / 1000000.0 / (0.0 + res_cnt); 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (res_cnt > 1) { 21862306a36Sopenharmony_ci for (i = 0; i < res_cnt; i++) { 21962306a36Sopenharmony_ci hits_stddev += (hits_mean - res[i].hits / 1000000.0) * 22062306a36Sopenharmony_ci (hits_mean - res[i].hits / 1000000.0) / 22162306a36Sopenharmony_ci (res_cnt - 1.0); 22262306a36Sopenharmony_ci important_hits_stddev += 22362306a36Sopenharmony_ci (important_hits_mean - res[i].important_hits / 1000000.0) * 22462306a36Sopenharmony_ci (important_hits_mean - res[i].important_hits / 1000000.0) / 22562306a36Sopenharmony_ci (res_cnt - 1.0); 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci hits_stddev = sqrt(hits_stddev); 22962306a36Sopenharmony_ci important_hits_stddev = sqrt(important_hits_stddev); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci printf("Summary: hits throughput %8.3lf \u00B1 %5.3lf M ops/s, ", 23262306a36Sopenharmony_ci hits_mean, hits_stddev); 23362306a36Sopenharmony_ci printf("hits latency %8.3lf ns/op, ", 1000.0 / hits_mean); 23462306a36Sopenharmony_ci printf("important_hits throughput %8.3lf \u00B1 %5.3lf M ops/s\n", 23562306a36Sopenharmony_ci important_hits_mean, important_hits_stddev); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ciconst char *argp_program_version = "benchmark"; 23962306a36Sopenharmony_ciconst char *argp_program_bug_address = "<bpf@vger.kernel.org>"; 24062306a36Sopenharmony_ciconst char argp_program_doc[] = 24162306a36Sopenharmony_ci"benchmark Generic benchmarking framework.\n" 24262306a36Sopenharmony_ci"\n" 24362306a36Sopenharmony_ci"This tool runs benchmarks.\n" 24462306a36Sopenharmony_ci"\n" 24562306a36Sopenharmony_ci"USAGE: benchmark <bench-name>\n" 24662306a36Sopenharmony_ci"\n" 24762306a36Sopenharmony_ci"EXAMPLES:\n" 24862306a36Sopenharmony_ci" # run 'count-local' benchmark with 1 producer and 1 consumer\n" 24962306a36Sopenharmony_ci" benchmark count-local\n" 25062306a36Sopenharmony_ci" # run 'count-local' with 16 producer and 8 consumer thread, pinned to CPUs\n" 25162306a36Sopenharmony_ci" benchmark -p16 -c8 -a count-local\n"; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cienum { 25462306a36Sopenharmony_ci ARG_PROD_AFFINITY_SET = 1000, 25562306a36Sopenharmony_ci ARG_CONS_AFFINITY_SET = 1001, 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic const struct argp_option opts[] = { 25962306a36Sopenharmony_ci { "list", 'l', NULL, 0, "List available benchmarks"}, 26062306a36Sopenharmony_ci { "duration", 'd', "SEC", 0, "Duration of benchmark, seconds"}, 26162306a36Sopenharmony_ci { "warmup", 'w', "SEC", 0, "Warm-up period, seconds"}, 26262306a36Sopenharmony_ci { "producers", 'p', "NUM", 0, "Number of producer threads"}, 26362306a36Sopenharmony_ci { "consumers", 'c', "NUM", 0, "Number of consumer threads"}, 26462306a36Sopenharmony_ci { "verbose", 'v', NULL, 0, "Verbose debug output"}, 26562306a36Sopenharmony_ci { "affinity", 'a', NULL, 0, "Set consumer/producer thread affinity"}, 26662306a36Sopenharmony_ci { "quiet", 'q', NULL, 0, "Be more quiet"}, 26762306a36Sopenharmony_ci { "prod-affinity", ARG_PROD_AFFINITY_SET, "CPUSET", 0, 26862306a36Sopenharmony_ci "Set of CPUs for producer threads; implies --affinity"}, 26962306a36Sopenharmony_ci { "cons-affinity", ARG_CONS_AFFINITY_SET, "CPUSET", 0, 27062306a36Sopenharmony_ci "Set of CPUs for consumer threads; implies --affinity"}, 27162306a36Sopenharmony_ci {}, 27262306a36Sopenharmony_ci}; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ciextern struct argp bench_ringbufs_argp; 27562306a36Sopenharmony_ciextern struct argp bench_bloom_map_argp; 27662306a36Sopenharmony_ciextern struct argp bench_bpf_loop_argp; 27762306a36Sopenharmony_ciextern struct argp bench_local_storage_argp; 27862306a36Sopenharmony_ciextern struct argp bench_local_storage_rcu_tasks_trace_argp; 27962306a36Sopenharmony_ciextern struct argp bench_strncmp_argp; 28062306a36Sopenharmony_ciextern struct argp bench_hashmap_lookup_argp; 28162306a36Sopenharmony_ciextern struct argp bench_local_storage_create_argp; 28262306a36Sopenharmony_ciextern struct argp bench_htab_mem_argp; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic const struct argp_child bench_parsers[] = { 28562306a36Sopenharmony_ci { &bench_ringbufs_argp, 0, "Ring buffers benchmark", 0 }, 28662306a36Sopenharmony_ci { &bench_bloom_map_argp, 0, "Bloom filter map benchmark", 0 }, 28762306a36Sopenharmony_ci { &bench_bpf_loop_argp, 0, "bpf_loop helper benchmark", 0 }, 28862306a36Sopenharmony_ci { &bench_local_storage_argp, 0, "local_storage benchmark", 0 }, 28962306a36Sopenharmony_ci { &bench_strncmp_argp, 0, "bpf_strncmp helper benchmark", 0 }, 29062306a36Sopenharmony_ci { &bench_local_storage_rcu_tasks_trace_argp, 0, 29162306a36Sopenharmony_ci "local_storage RCU Tasks Trace slowdown benchmark", 0 }, 29262306a36Sopenharmony_ci { &bench_hashmap_lookup_argp, 0, "Hashmap lookup benchmark", 0 }, 29362306a36Sopenharmony_ci { &bench_local_storage_create_argp, 0, "local-storage-create benchmark", 0 }, 29462306a36Sopenharmony_ci { &bench_htab_mem_argp, 0, "hash map memory benchmark", 0 }, 29562306a36Sopenharmony_ci {}, 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/* Make pos_args global, so that we can run argp_parse twice, if necessary */ 29962306a36Sopenharmony_cistatic int pos_args; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic error_t parse_arg(int key, char *arg, struct argp_state *state) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci switch (key) { 30462306a36Sopenharmony_ci case 'v': 30562306a36Sopenharmony_ci env.verbose = true; 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci case 'l': 30862306a36Sopenharmony_ci env.list = true; 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci case 'd': 31162306a36Sopenharmony_ci env.duration_sec = strtol(arg, NULL, 10); 31262306a36Sopenharmony_ci if (env.duration_sec <= 0) { 31362306a36Sopenharmony_ci fprintf(stderr, "Invalid duration: %s\n", arg); 31462306a36Sopenharmony_ci argp_usage(state); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci case 'w': 31862306a36Sopenharmony_ci env.warmup_sec = strtol(arg, NULL, 10); 31962306a36Sopenharmony_ci if (env.warmup_sec <= 0) { 32062306a36Sopenharmony_ci fprintf(stderr, "Invalid warm-up duration: %s\n", arg); 32162306a36Sopenharmony_ci argp_usage(state); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci case 'p': 32562306a36Sopenharmony_ci env.producer_cnt = strtol(arg, NULL, 10); 32662306a36Sopenharmony_ci if (env.producer_cnt <= 0) { 32762306a36Sopenharmony_ci fprintf(stderr, "Invalid producer count: %s\n", arg); 32862306a36Sopenharmony_ci argp_usage(state); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci case 'c': 33262306a36Sopenharmony_ci env.consumer_cnt = strtol(arg, NULL, 10); 33362306a36Sopenharmony_ci if (env.consumer_cnt <= 0) { 33462306a36Sopenharmony_ci fprintf(stderr, "Invalid consumer count: %s\n", arg); 33562306a36Sopenharmony_ci argp_usage(state); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci case 'a': 33962306a36Sopenharmony_ci env.affinity = true; 34062306a36Sopenharmony_ci break; 34162306a36Sopenharmony_ci case 'q': 34262306a36Sopenharmony_ci env.quiet = true; 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci case ARG_PROD_AFFINITY_SET: 34562306a36Sopenharmony_ci env.affinity = true; 34662306a36Sopenharmony_ci if (parse_num_list(arg, &env.prod_cpus.cpus, 34762306a36Sopenharmony_ci &env.prod_cpus.cpus_len)) { 34862306a36Sopenharmony_ci fprintf(stderr, "Invalid format of CPU set for producers."); 34962306a36Sopenharmony_ci argp_usage(state); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case ARG_CONS_AFFINITY_SET: 35362306a36Sopenharmony_ci env.affinity = true; 35462306a36Sopenharmony_ci if (parse_num_list(arg, &env.cons_cpus.cpus, 35562306a36Sopenharmony_ci &env.cons_cpus.cpus_len)) { 35662306a36Sopenharmony_ci fprintf(stderr, "Invalid format of CPU set for consumers."); 35762306a36Sopenharmony_ci argp_usage(state); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci case ARGP_KEY_ARG: 36162306a36Sopenharmony_ci if (pos_args++) { 36262306a36Sopenharmony_ci fprintf(stderr, 36362306a36Sopenharmony_ci "Unrecognized positional argument: %s\n", arg); 36462306a36Sopenharmony_ci argp_usage(state); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci env.bench_name = strdup(arg); 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci default: 36962306a36Sopenharmony_ci return ARGP_ERR_UNKNOWN; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void parse_cmdline_args_init(int argc, char **argv) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci static const struct argp argp = { 37762306a36Sopenharmony_ci .options = opts, 37862306a36Sopenharmony_ci .parser = parse_arg, 37962306a36Sopenharmony_ci .doc = argp_program_doc, 38062306a36Sopenharmony_ci .children = bench_parsers, 38162306a36Sopenharmony_ci }; 38262306a36Sopenharmony_ci if (argp_parse(&argp, argc, argv, 0, NULL, NULL)) 38362306a36Sopenharmony_ci exit(1); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic void parse_cmdline_args_final(int argc, char **argv) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct argp_child bench_parsers[2] = {}; 38962306a36Sopenharmony_ci const struct argp argp = { 39062306a36Sopenharmony_ci .options = opts, 39162306a36Sopenharmony_ci .parser = parse_arg, 39262306a36Sopenharmony_ci .doc = argp_program_doc, 39362306a36Sopenharmony_ci .children = bench_parsers, 39462306a36Sopenharmony_ci }; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* Parse arguments the second time with the correct set of parsers */ 39762306a36Sopenharmony_ci if (bench->argp) { 39862306a36Sopenharmony_ci bench_parsers[0].argp = bench->argp; 39962306a36Sopenharmony_ci bench_parsers[0].header = bench->name; 40062306a36Sopenharmony_ci pos_args = 0; 40162306a36Sopenharmony_ci if (argp_parse(&argp, argc, argv, 0, NULL, NULL)) 40262306a36Sopenharmony_ci exit(1); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void collect_measurements(long delta_ns); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic __u64 last_time_ns; 40962306a36Sopenharmony_cistatic void sigalarm_handler(int signo) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci long new_time_ns = get_time_ns(); 41262306a36Sopenharmony_ci long delta_ns = new_time_ns - last_time_ns; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci collect_measurements(delta_ns); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci last_time_ns = new_time_ns; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/* set up periodic 1-second timer */ 42062306a36Sopenharmony_cistatic void setup_timer() 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci static struct sigaction sigalarm_action = { 42362306a36Sopenharmony_ci .sa_handler = sigalarm_handler, 42462306a36Sopenharmony_ci }; 42562306a36Sopenharmony_ci struct itimerval timer_settings = {}; 42662306a36Sopenharmony_ci int err; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci last_time_ns = get_time_ns(); 42962306a36Sopenharmony_ci err = sigaction(SIGALRM, &sigalarm_action, NULL); 43062306a36Sopenharmony_ci if (err < 0) { 43162306a36Sopenharmony_ci fprintf(stderr, "failed to install SIGALRM handler: %d\n", -errno); 43262306a36Sopenharmony_ci exit(1); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci timer_settings.it_interval.tv_sec = 1; 43562306a36Sopenharmony_ci timer_settings.it_value.tv_sec = 1; 43662306a36Sopenharmony_ci err = setitimer(ITIMER_REAL, &timer_settings, NULL); 43762306a36Sopenharmony_ci if (err < 0) { 43862306a36Sopenharmony_ci fprintf(stderr, "failed to arm interval timer: %d\n", -errno); 43962306a36Sopenharmony_ci exit(1); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic void set_thread_affinity(pthread_t thread, int cpu) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci cpu_set_t cpuset; 44662306a36Sopenharmony_ci int err; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci CPU_ZERO(&cpuset); 44962306a36Sopenharmony_ci CPU_SET(cpu, &cpuset); 45062306a36Sopenharmony_ci err = pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset); 45162306a36Sopenharmony_ci if (err) { 45262306a36Sopenharmony_ci fprintf(stderr, "setting affinity to CPU #%d failed: %d\n", 45362306a36Sopenharmony_ci cpu, -err); 45462306a36Sopenharmony_ci exit(1); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic int next_cpu(struct cpu_set *cpu_set) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci if (cpu_set->cpus) { 46162306a36Sopenharmony_ci int i; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* find next available CPU */ 46462306a36Sopenharmony_ci for (i = cpu_set->next_cpu; i < cpu_set->cpus_len; i++) { 46562306a36Sopenharmony_ci if (cpu_set->cpus[i]) { 46662306a36Sopenharmony_ci cpu_set->next_cpu = i + 1; 46762306a36Sopenharmony_ci return i; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci fprintf(stderr, "Not enough CPUs specified, need CPU #%d or higher.\n", i); 47162306a36Sopenharmony_ci exit(1); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return cpu_set->next_cpu++ % env.nr_cpus; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic struct bench_state { 47862306a36Sopenharmony_ci int res_cnt; 47962306a36Sopenharmony_ci struct bench_res *results; 48062306a36Sopenharmony_ci pthread_t *consumers; 48162306a36Sopenharmony_ci pthread_t *producers; 48262306a36Sopenharmony_ci} state; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ciconst struct bench *bench = NULL; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ciextern const struct bench bench_count_global; 48762306a36Sopenharmony_ciextern const struct bench bench_count_local; 48862306a36Sopenharmony_ciextern const struct bench bench_rename_base; 48962306a36Sopenharmony_ciextern const struct bench bench_rename_kprobe; 49062306a36Sopenharmony_ciextern const struct bench bench_rename_kretprobe; 49162306a36Sopenharmony_ciextern const struct bench bench_rename_rawtp; 49262306a36Sopenharmony_ciextern const struct bench bench_rename_fentry; 49362306a36Sopenharmony_ciextern const struct bench bench_rename_fexit; 49462306a36Sopenharmony_ciextern const struct bench bench_trig_base; 49562306a36Sopenharmony_ciextern const struct bench bench_trig_tp; 49662306a36Sopenharmony_ciextern const struct bench bench_trig_rawtp; 49762306a36Sopenharmony_ciextern const struct bench bench_trig_kprobe; 49862306a36Sopenharmony_ciextern const struct bench bench_trig_fentry; 49962306a36Sopenharmony_ciextern const struct bench bench_trig_fentry_sleep; 50062306a36Sopenharmony_ciextern const struct bench bench_trig_fmodret; 50162306a36Sopenharmony_ciextern const struct bench bench_trig_uprobe_base; 50262306a36Sopenharmony_ciextern const struct bench bench_trig_uprobe_with_nop; 50362306a36Sopenharmony_ciextern const struct bench bench_trig_uretprobe_with_nop; 50462306a36Sopenharmony_ciextern const struct bench bench_trig_uprobe_without_nop; 50562306a36Sopenharmony_ciextern const struct bench bench_trig_uretprobe_without_nop; 50662306a36Sopenharmony_ciextern const struct bench bench_rb_libbpf; 50762306a36Sopenharmony_ciextern const struct bench bench_rb_custom; 50862306a36Sopenharmony_ciextern const struct bench bench_pb_libbpf; 50962306a36Sopenharmony_ciextern const struct bench bench_pb_custom; 51062306a36Sopenharmony_ciextern const struct bench bench_bloom_lookup; 51162306a36Sopenharmony_ciextern const struct bench bench_bloom_update; 51262306a36Sopenharmony_ciextern const struct bench bench_bloom_false_positive; 51362306a36Sopenharmony_ciextern const struct bench bench_hashmap_without_bloom; 51462306a36Sopenharmony_ciextern const struct bench bench_hashmap_with_bloom; 51562306a36Sopenharmony_ciextern const struct bench bench_bpf_loop; 51662306a36Sopenharmony_ciextern const struct bench bench_strncmp_no_helper; 51762306a36Sopenharmony_ciextern const struct bench bench_strncmp_helper; 51862306a36Sopenharmony_ciextern const struct bench bench_bpf_hashmap_full_update; 51962306a36Sopenharmony_ciextern const struct bench bench_local_storage_cache_seq_get; 52062306a36Sopenharmony_ciextern const struct bench bench_local_storage_cache_interleaved_get; 52162306a36Sopenharmony_ciextern const struct bench bench_local_storage_cache_hashmap_control; 52262306a36Sopenharmony_ciextern const struct bench bench_local_storage_tasks_trace; 52362306a36Sopenharmony_ciextern const struct bench bench_bpf_hashmap_lookup; 52462306a36Sopenharmony_ciextern const struct bench bench_local_storage_create; 52562306a36Sopenharmony_ciextern const struct bench bench_htab_mem; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic const struct bench *benchs[] = { 52862306a36Sopenharmony_ci &bench_count_global, 52962306a36Sopenharmony_ci &bench_count_local, 53062306a36Sopenharmony_ci &bench_rename_base, 53162306a36Sopenharmony_ci &bench_rename_kprobe, 53262306a36Sopenharmony_ci &bench_rename_kretprobe, 53362306a36Sopenharmony_ci &bench_rename_rawtp, 53462306a36Sopenharmony_ci &bench_rename_fentry, 53562306a36Sopenharmony_ci &bench_rename_fexit, 53662306a36Sopenharmony_ci &bench_trig_base, 53762306a36Sopenharmony_ci &bench_trig_tp, 53862306a36Sopenharmony_ci &bench_trig_rawtp, 53962306a36Sopenharmony_ci &bench_trig_kprobe, 54062306a36Sopenharmony_ci &bench_trig_fentry, 54162306a36Sopenharmony_ci &bench_trig_fentry_sleep, 54262306a36Sopenharmony_ci &bench_trig_fmodret, 54362306a36Sopenharmony_ci &bench_trig_uprobe_base, 54462306a36Sopenharmony_ci &bench_trig_uprobe_with_nop, 54562306a36Sopenharmony_ci &bench_trig_uretprobe_with_nop, 54662306a36Sopenharmony_ci &bench_trig_uprobe_without_nop, 54762306a36Sopenharmony_ci &bench_trig_uretprobe_without_nop, 54862306a36Sopenharmony_ci &bench_rb_libbpf, 54962306a36Sopenharmony_ci &bench_rb_custom, 55062306a36Sopenharmony_ci &bench_pb_libbpf, 55162306a36Sopenharmony_ci &bench_pb_custom, 55262306a36Sopenharmony_ci &bench_bloom_lookup, 55362306a36Sopenharmony_ci &bench_bloom_update, 55462306a36Sopenharmony_ci &bench_bloom_false_positive, 55562306a36Sopenharmony_ci &bench_hashmap_without_bloom, 55662306a36Sopenharmony_ci &bench_hashmap_with_bloom, 55762306a36Sopenharmony_ci &bench_bpf_loop, 55862306a36Sopenharmony_ci &bench_strncmp_no_helper, 55962306a36Sopenharmony_ci &bench_strncmp_helper, 56062306a36Sopenharmony_ci &bench_bpf_hashmap_full_update, 56162306a36Sopenharmony_ci &bench_local_storage_cache_seq_get, 56262306a36Sopenharmony_ci &bench_local_storage_cache_interleaved_get, 56362306a36Sopenharmony_ci &bench_local_storage_cache_hashmap_control, 56462306a36Sopenharmony_ci &bench_local_storage_tasks_trace, 56562306a36Sopenharmony_ci &bench_bpf_hashmap_lookup, 56662306a36Sopenharmony_ci &bench_local_storage_create, 56762306a36Sopenharmony_ci &bench_htab_mem, 56862306a36Sopenharmony_ci}; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic void find_benchmark(void) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci int i; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (!env.bench_name) { 57562306a36Sopenharmony_ci fprintf(stderr, "benchmark name is not specified\n"); 57662306a36Sopenharmony_ci exit(1); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(benchs); i++) { 57962306a36Sopenharmony_ci if (strcmp(benchs[i]->name, env.bench_name) == 0) { 58062306a36Sopenharmony_ci bench = benchs[i]; 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci if (!bench) { 58562306a36Sopenharmony_ci fprintf(stderr, "benchmark '%s' not found\n", env.bench_name); 58662306a36Sopenharmony_ci exit(1); 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic void setup_benchmark(void) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci int i, err; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (!env.quiet) 59562306a36Sopenharmony_ci printf("Setting up benchmark '%s'...\n", bench->name); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci state.producers = calloc(env.producer_cnt, sizeof(*state.producers)); 59862306a36Sopenharmony_ci state.consumers = calloc(env.consumer_cnt, sizeof(*state.consumers)); 59962306a36Sopenharmony_ci state.results = calloc(env.duration_sec + env.warmup_sec + 2, 60062306a36Sopenharmony_ci sizeof(*state.results)); 60162306a36Sopenharmony_ci if (!state.producers || !state.consumers || !state.results) 60262306a36Sopenharmony_ci exit(1); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (bench->validate) 60562306a36Sopenharmony_ci bench->validate(); 60662306a36Sopenharmony_ci if (bench->setup) 60762306a36Sopenharmony_ci bench->setup(); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci for (i = 0; i < env.consumer_cnt; i++) { 61062306a36Sopenharmony_ci err = pthread_create(&state.consumers[i], NULL, 61162306a36Sopenharmony_ci bench->consumer_thread, (void *)(long)i); 61262306a36Sopenharmony_ci if (err) { 61362306a36Sopenharmony_ci fprintf(stderr, "failed to create consumer thread #%d: %d\n", 61462306a36Sopenharmony_ci i, -err); 61562306a36Sopenharmony_ci exit(1); 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci if (env.affinity) 61862306a36Sopenharmony_ci set_thread_affinity(state.consumers[i], 61962306a36Sopenharmony_ci next_cpu(&env.cons_cpus)); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* unless explicit producer CPU list is specified, continue after 62362306a36Sopenharmony_ci * last consumer CPU 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci if (!env.prod_cpus.cpus) 62662306a36Sopenharmony_ci env.prod_cpus.next_cpu = env.cons_cpus.next_cpu; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci for (i = 0; i < env.producer_cnt; i++) { 62962306a36Sopenharmony_ci err = pthread_create(&state.producers[i], NULL, 63062306a36Sopenharmony_ci bench->producer_thread, (void *)(long)i); 63162306a36Sopenharmony_ci if (err) { 63262306a36Sopenharmony_ci fprintf(stderr, "failed to create producer thread #%d: %d\n", 63362306a36Sopenharmony_ci i, -err); 63462306a36Sopenharmony_ci exit(1); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci if (env.affinity) 63762306a36Sopenharmony_ci set_thread_affinity(state.producers[i], 63862306a36Sopenharmony_ci next_cpu(&env.prod_cpus)); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (!env.quiet) 64262306a36Sopenharmony_ci printf("Benchmark '%s' started.\n", bench->name); 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic pthread_mutex_t bench_done_mtx = PTHREAD_MUTEX_INITIALIZER; 64662306a36Sopenharmony_cistatic pthread_cond_t bench_done = PTHREAD_COND_INITIALIZER; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic void collect_measurements(long delta_ns) { 64962306a36Sopenharmony_ci int iter = state.res_cnt++; 65062306a36Sopenharmony_ci struct bench_res *res = &state.results[iter]; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci bench->measure(res); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (bench->report_progress) 65562306a36Sopenharmony_ci bench->report_progress(iter, res, delta_ns); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (iter == env.duration_sec + env.warmup_sec) { 65862306a36Sopenharmony_ci pthread_mutex_lock(&bench_done_mtx); 65962306a36Sopenharmony_ci pthread_cond_signal(&bench_done); 66062306a36Sopenharmony_ci pthread_mutex_unlock(&bench_done_mtx); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ciint main(int argc, char **argv) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci env.nr_cpus = get_nprocs(); 66762306a36Sopenharmony_ci parse_cmdline_args_init(argc, argv); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (env.list) { 67062306a36Sopenharmony_ci int i; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci printf("Available benchmarks:\n"); 67362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(benchs); i++) { 67462306a36Sopenharmony_ci printf("- %s\n", benchs[i]->name); 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci return 0; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci find_benchmark(); 68062306a36Sopenharmony_ci parse_cmdline_args_final(argc, argv); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci setup_benchmark(); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci setup_timer(); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci pthread_mutex_lock(&bench_done_mtx); 68762306a36Sopenharmony_ci pthread_cond_wait(&bench_done, &bench_done_mtx); 68862306a36Sopenharmony_ci pthread_mutex_unlock(&bench_done_mtx); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (bench->report_final) 69162306a36Sopenharmony_ci /* skip first sample */ 69262306a36Sopenharmony_ci bench->report_final(state.results + env.warmup_sec, 69362306a36Sopenharmony_ci state.res_cnt - env.warmup_sec); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return 0; 69662306a36Sopenharmony_ci} 697