1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2629cc356SHitoshi Mitake /* 3629cc356SHitoshi Mitake * builtin-bench.c 4629cc356SHitoshi Mitake * 54157922aSIngo Molnar * General benchmarking collections provided by perf 6629cc356SHitoshi Mitake * 7629cc356SHitoshi Mitake * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 8629cc356SHitoshi Mitake */ 9629cc356SHitoshi Mitake 10629cc356SHitoshi Mitake /* 114157922aSIngo Molnar * Available benchmark collection list: 12629cc356SHitoshi Mitake * 134157922aSIngo Molnar * sched ... scheduler and IPC performance 14827f3b49SHitoshi Mitake * mem ... memory access performance 154157922aSIngo Molnar * numa ... NUMA scheduling and MM performance 16a0439711SDavidlohr Bueso * futex ... Futex performance 17121dd9eaSDavidlohr Bueso * epoll ... Event poll performance 18629cc356SHitoshi Mitake */ 194b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h> 20629cc356SHitoshi Mitake #include "builtin.h" 21629cc356SHitoshi Mitake #include "bench/bench.h" 22629cc356SHitoshi Mitake 23629cc356SHitoshi Mitake #include <stdio.h> 24629cc356SHitoshi Mitake #include <stdlib.h> 25629cc356SHitoshi Mitake #include <string.h> 264157922aSIngo Molnar #include <sys/prctl.h> 277f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 28629cc356SHitoshi Mitake 29b0ad8ea6SArnaldo Carvalho de Melo typedef int (*bench_fn_t)(int argc, const char **argv); 304157922aSIngo Molnar 314157922aSIngo Molnar struct bench { 32629cc356SHitoshi Mitake const char *name; 33629cc356SHitoshi Mitake const char *summary; 344157922aSIngo Molnar bench_fn_t fn; 35629cc356SHitoshi Mitake }; 36629cc356SHitoshi Mitake 3789fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT 384157922aSIngo Molnar static struct bench numa_benchmarks[] = { 394157922aSIngo Molnar { "mem", "Benchmark for NUMA workloads", bench_numa }, 40aa254af2SIngo Molnar { "all", "Run all NUMA benchmarks", NULL }, 414157922aSIngo Molnar { NULL, NULL, NULL } 421c13f3c9SIngo Molnar }; 4379d824e3SPeter Hurley #endif 441c13f3c9SIngo Molnar 454157922aSIngo Molnar static struct bench sched_benchmarks[] = { 464157922aSIngo Molnar { "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging }, 474157922aSIngo Molnar { "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe }, 48aa254af2SIngo Molnar { "all", "Run all scheduler benchmarks", NULL }, 494157922aSIngo Molnar { NULL, NULL, NULL } 50629cc356SHitoshi Mitake }; 51629cc356SHitoshi Mitake 524157922aSIngo Molnar static struct bench mem_benchmarks[] = { 5313b1fdceSIngo Molnar { "memcpy", "Benchmark for memcpy() functions", bench_mem_memcpy }, 5413b1fdceSIngo Molnar { "memset", "Benchmark for memset() functions", bench_mem_memset }, 55aa254af2SIngo Molnar { "all", "Run all memory access benchmarks", NULL }, 564157922aSIngo Molnar { NULL, NULL, NULL } 57827f3b49SHitoshi Mitake }; 58827f3b49SHitoshi Mitake 59a0439711SDavidlohr Bueso static struct bench futex_benchmarks[] = { 60a0439711SDavidlohr Bueso { "hash", "Benchmark for futex hash table", bench_futex_hash }, 6127db7830SDavidlohr Bueso { "wake", "Benchmark for futex wake calls", bench_futex_wake }, 62d65817b4SDavidlohr Bueso { "wake-parallel", "Benchmark for parallel futex wake calls", bench_futex_wake_parallel }, 630fb298cfSDavidlohr Bueso { "requeue", "Benchmark for futex requeue calls", bench_futex_requeue }, 64d2f3f5d2SDavidlohr Bueso /* pi-futexes */ 65d2f3f5d2SDavidlohr Bueso { "lock-pi", "Benchmark for futex lock_pi calls", bench_futex_lock_pi }, 66aa254af2SIngo Molnar { "all", "Run all futex benchmarks", NULL }, 67a0439711SDavidlohr Bueso { NULL, NULL, NULL } 68a0439711SDavidlohr Bueso }; 69a0439711SDavidlohr Bueso 70121dd9eaSDavidlohr Bueso #ifdef HAVE_EVENTFD 71121dd9eaSDavidlohr Bueso static struct bench epoll_benchmarks[] = { 72121dd9eaSDavidlohr Bueso { "wait", "Benchmark epoll concurrent epoll_waits", bench_epoll_wait }, 73231457ecSDavidlohr Bueso { "ctl", "Benchmark epoll concurrent epoll_ctls", bench_epoll_ctl }, 74121dd9eaSDavidlohr Bueso { "all", "Run all futex benchmarks", NULL }, 75121dd9eaSDavidlohr Bueso { NULL, NULL, NULL } 76121dd9eaSDavidlohr Bueso }; 77121dd9eaSDavidlohr Bueso #endif // HAVE_EVENTFD 78121dd9eaSDavidlohr Bueso 792a4b5166SIan Rogers static struct bench internals_benchmarks[] = { 802a4b5166SIan Rogers { "synthesize", "Benchmark perf event synthesis", bench_synthesize }, 81*51876bd4SIan Rogers { "kallsyms-parse", "Benchmark kallsyms parsing", bench_kallsyms_parse }, 822a4b5166SIan Rogers { NULL, NULL, NULL } 832a4b5166SIan Rogers }; 842a4b5166SIan Rogers 854157922aSIngo Molnar struct collection { 86629cc356SHitoshi Mitake const char *name; 87629cc356SHitoshi Mitake const char *summary; 884157922aSIngo Molnar struct bench *benchmarks; 89629cc356SHitoshi Mitake }; 90629cc356SHitoshi Mitake 914157922aSIngo Molnar static struct collection collections[] = { 924157922aSIngo Molnar { "sched", "Scheduler and IPC benchmarks", sched_benchmarks }, 934157922aSIngo Molnar { "mem", "Memory access benchmarks", mem_benchmarks }, 9489fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT 954157922aSIngo Molnar { "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks }, 9679d824e3SPeter Hurley #endif 97a0439711SDavidlohr Bueso {"futex", "Futex stressing benchmarks", futex_benchmarks }, 98121dd9eaSDavidlohr Bueso #ifdef HAVE_EVENTFD 99121dd9eaSDavidlohr Bueso {"epoll", "Epoll stressing benchmarks", epoll_benchmarks }, 100121dd9eaSDavidlohr Bueso #endif 1012a4b5166SIan Rogers { "internals", "Perf-internals benchmarks", internals_benchmarks }, 1024157922aSIngo Molnar { "all", "All benchmarks", NULL }, 1034157922aSIngo Molnar { NULL, NULL, NULL } 104629cc356SHitoshi Mitake }; 105629cc356SHitoshi Mitake 1064157922aSIngo Molnar /* Iterate over all benchmark collections: */ 1074157922aSIngo Molnar #define for_each_collection(coll) \ 1084157922aSIngo Molnar for (coll = collections; coll->name; coll++) 1094157922aSIngo Molnar 1104157922aSIngo Molnar /* Iterate over all benchmarks within a collection: */ 1114157922aSIngo Molnar #define for_each_bench(coll, bench) \ 1126eeefccdSPatrick Palka for (bench = coll->benchmarks; bench && bench->name; bench++) 1134157922aSIngo Molnar 1144157922aSIngo Molnar static void dump_benchmarks(struct collection *coll) 115629cc356SHitoshi Mitake { 1164157922aSIngo Molnar struct bench *bench; 117629cc356SHitoshi Mitake 1184157922aSIngo Molnar printf("\n # List of available benchmarks for collection '%s':\n\n", coll->name); 119629cc356SHitoshi Mitake 1204157922aSIngo Molnar for_each_bench(coll, bench) 1214157922aSIngo Molnar printf("%14s: %s\n", bench->name, bench->summary); 122629cc356SHitoshi Mitake 123629cc356SHitoshi Mitake printf("\n"); 124629cc356SHitoshi Mitake } 125629cc356SHitoshi Mitake 126edb7c60eSArnaldo Carvalho de Melo static const char *bench_format_str; 1274157922aSIngo Molnar 1284157922aSIngo Molnar /* Output/formatting style, exported to benchmark modules: */ 129386d7e9eSHitoshi Mitake int bench_format = BENCH_FORMAT_DEFAULT; 130b6f0629aSDavidlohr Bueso unsigned int bench_repeat = 10; /* default number of times to repeat the run */ 131629cc356SHitoshi Mitake 132386d7e9eSHitoshi Mitake static const struct option bench_options[] = { 1337a46a8fdSIngo Molnar OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"), 134b6f0629aSDavidlohr Bueso OPT_UINTEGER('r', "repeat", &bench_repeat, "Specify amount of times to repeat the run"), 135386d7e9eSHitoshi Mitake OPT_END() 136386d7e9eSHitoshi Mitake }; 137386d7e9eSHitoshi Mitake 138386d7e9eSHitoshi Mitake static const char * const bench_usage[] = { 1394157922aSIngo Molnar "perf bench [<common options>] <collection> <benchmark> [<options>]", 140386d7e9eSHitoshi Mitake NULL 141386d7e9eSHitoshi Mitake }; 142386d7e9eSHitoshi Mitake 143386d7e9eSHitoshi Mitake static void print_usage(void) 144386d7e9eSHitoshi Mitake { 1454157922aSIngo Molnar struct collection *coll; 146386d7e9eSHitoshi Mitake int i; 147386d7e9eSHitoshi Mitake 148386d7e9eSHitoshi Mitake printf("Usage: \n"); 149386d7e9eSHitoshi Mitake for (i = 0; bench_usage[i]; i++) 150386d7e9eSHitoshi Mitake printf("\t%s\n", bench_usage[i]); 151386d7e9eSHitoshi Mitake printf("\n"); 152386d7e9eSHitoshi Mitake 1534157922aSIngo Molnar printf(" # List of all available benchmark collections:\n\n"); 154629cc356SHitoshi Mitake 1554157922aSIngo Molnar for_each_collection(coll) 1564157922aSIngo Molnar printf("%14s: %s\n", coll->name, coll->summary); 157629cc356SHitoshi Mitake printf("\n"); 158386d7e9eSHitoshi Mitake } 159629cc356SHitoshi Mitake 160edb7c60eSArnaldo Carvalho de Melo static int bench_str2int(const char *str) 161386d7e9eSHitoshi Mitake { 162386d7e9eSHitoshi Mitake if (!str) 163386d7e9eSHitoshi Mitake return BENCH_FORMAT_DEFAULT; 164386d7e9eSHitoshi Mitake 165386d7e9eSHitoshi Mitake if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR)) 166386d7e9eSHitoshi Mitake return BENCH_FORMAT_DEFAULT; 167386d7e9eSHitoshi Mitake else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR)) 168386d7e9eSHitoshi Mitake return BENCH_FORMAT_SIMPLE; 169386d7e9eSHitoshi Mitake 170386d7e9eSHitoshi Mitake return BENCH_FORMAT_UNKNOWN; 171386d7e9eSHitoshi Mitake } 172386d7e9eSHitoshi Mitake 1734157922aSIngo Molnar /* 1744157922aSIngo Molnar * Run a specific benchmark but first rename the running task's ->comm[] 1754157922aSIngo Molnar * to something meaningful: 1764157922aSIngo Molnar */ 1774157922aSIngo Molnar static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn, 178b0ad8ea6SArnaldo Carvalho de Melo int argc, const char **argv) 1792044279dSHitoshi Mitake { 1804157922aSIngo Molnar int size; 1814157922aSIngo Molnar char *name; 1824157922aSIngo Molnar int ret; 1834157922aSIngo Molnar 1844157922aSIngo Molnar size = strlen(coll_name) + 1 + strlen(bench_name) + 1; 1854157922aSIngo Molnar 1864157922aSIngo Molnar name = zalloc(size); 1874157922aSIngo Molnar BUG_ON(!name); 1884157922aSIngo Molnar 1894157922aSIngo Molnar scnprintf(name, size, "%s-%s", coll_name, bench_name); 1904157922aSIngo Molnar 1914157922aSIngo Molnar prctl(PR_SET_NAME, name); 1924157922aSIngo Molnar argv[0] = name; 1934157922aSIngo Molnar 194b0ad8ea6SArnaldo Carvalho de Melo ret = fn(argc, argv); 1954157922aSIngo Molnar 1964157922aSIngo Molnar free(name); 1974157922aSIngo Molnar 1984157922aSIngo Molnar return ret; 1994157922aSIngo Molnar } 2004157922aSIngo Molnar 2014157922aSIngo Molnar static void run_collection(struct collection *coll) 2024157922aSIngo Molnar { 2034157922aSIngo Molnar struct bench *bench; 2042044279dSHitoshi Mitake const char *argv[2]; 2052044279dSHitoshi Mitake 2062044279dSHitoshi Mitake argv[1] = NULL; 2072044279dSHitoshi Mitake /* 2082044279dSHitoshi Mitake * TODO: 2094157922aSIngo Molnar * 2104157922aSIngo Molnar * Preparing preset parameters for 2112044279dSHitoshi Mitake * embedded, ordinary PC, HPC, etc... 2124157922aSIngo Molnar * would be helpful. 2132044279dSHitoshi Mitake */ 2144157922aSIngo Molnar for_each_bench(coll, bench) { 2154157922aSIngo Molnar if (!bench->fn) 2164157922aSIngo Molnar break; 2174157922aSIngo Molnar printf("# Running %s/%s benchmark...\n", coll->name, bench->name); 2189b494ea2SNamhyung Kim fflush(stdout); 2192044279dSHitoshi Mitake 2204157922aSIngo Molnar argv[1] = bench->name; 221b0ad8ea6SArnaldo Carvalho de Melo run_bench(coll->name, bench->name, bench->fn, 1, argv); 2222044279dSHitoshi Mitake printf("\n"); 2232044279dSHitoshi Mitake } 2242044279dSHitoshi Mitake } 2252044279dSHitoshi Mitake 2264157922aSIngo Molnar static void run_all_collections(void) 2272044279dSHitoshi Mitake { 2284157922aSIngo Molnar struct collection *coll; 2294157922aSIngo Molnar 2304157922aSIngo Molnar for_each_collection(coll) 2314157922aSIngo Molnar run_collection(coll); 2322044279dSHitoshi Mitake } 2332044279dSHitoshi Mitake 234b0ad8ea6SArnaldo Carvalho de Melo int cmd_bench(int argc, const char **argv) 235386d7e9eSHitoshi Mitake { 2364157922aSIngo Molnar struct collection *coll; 2374157922aSIngo Molnar int ret = 0; 238386d7e9eSHitoshi Mitake 239386d7e9eSHitoshi Mitake if (argc < 2) { 2404157922aSIngo Molnar /* No collection specified. */ 241386d7e9eSHitoshi Mitake print_usage(); 242386d7e9eSHitoshi Mitake goto end; 243386d7e9eSHitoshi Mitake } 244386d7e9eSHitoshi Mitake 245386d7e9eSHitoshi Mitake argc = parse_options(argc, argv, bench_options, bench_usage, 246386d7e9eSHitoshi Mitake PARSE_OPT_STOP_AT_NON_OPTION); 247386d7e9eSHitoshi Mitake 248386d7e9eSHitoshi Mitake bench_format = bench_str2int(bench_format_str); 249386d7e9eSHitoshi Mitake if (bench_format == BENCH_FORMAT_UNKNOWN) { 2504157922aSIngo Molnar printf("Unknown format descriptor: '%s'\n", bench_format_str); 251386d7e9eSHitoshi Mitake goto end; 252386d7e9eSHitoshi Mitake } 253386d7e9eSHitoshi Mitake 254b6f0629aSDavidlohr Bueso if (bench_repeat == 0) { 255b6f0629aSDavidlohr Bueso printf("Invalid repeat option: Must specify a positive value\n"); 256b6f0629aSDavidlohr Bueso goto end; 257b6f0629aSDavidlohr Bueso } 258b6f0629aSDavidlohr Bueso 259386d7e9eSHitoshi Mitake if (argc < 1) { 260386d7e9eSHitoshi Mitake print_usage(); 261629cc356SHitoshi Mitake goto end; 262629cc356SHitoshi Mitake } 263629cc356SHitoshi Mitake 2642044279dSHitoshi Mitake if (!strcmp(argv[0], "all")) { 2654157922aSIngo Molnar run_all_collections(); 2662044279dSHitoshi Mitake goto end; 2672044279dSHitoshi Mitake } 2682044279dSHitoshi Mitake 2694157922aSIngo Molnar for_each_collection(coll) { 2704157922aSIngo Molnar struct bench *bench; 2714157922aSIngo Molnar 2724157922aSIngo Molnar if (strcmp(coll->name, argv[0])) 273629cc356SHitoshi Mitake continue; 274629cc356SHitoshi Mitake 275386d7e9eSHitoshi Mitake if (argc < 2) { 2764157922aSIngo Molnar /* No bench specified. */ 2774157922aSIngo Molnar dump_benchmarks(coll); 278629cc356SHitoshi Mitake goto end; 279629cc356SHitoshi Mitake } 280629cc356SHitoshi Mitake 2812044279dSHitoshi Mitake if (!strcmp(argv[1], "all")) { 2824157922aSIngo Molnar run_collection(coll); 2832044279dSHitoshi Mitake goto end; 2842044279dSHitoshi Mitake } 2852044279dSHitoshi Mitake 2864157922aSIngo Molnar for_each_bench(coll, bench) { 2874157922aSIngo Molnar if (strcmp(bench->name, argv[1])) 288629cc356SHitoshi Mitake continue; 289629cc356SHitoshi Mitake 29079e295d4SHitoshi Mitake if (bench_format == BENCH_FORMAT_DEFAULT) 2914157922aSIngo Molnar printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name); 2929b494ea2SNamhyung Kim fflush(stdout); 293b0ad8ea6SArnaldo Carvalho de Melo ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1); 294629cc356SHitoshi Mitake goto end; 295629cc356SHitoshi Mitake } 296629cc356SHitoshi Mitake 297386d7e9eSHitoshi Mitake if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 2984157922aSIngo Molnar dump_benchmarks(coll); 299629cc356SHitoshi Mitake goto end; 300629cc356SHitoshi Mitake } 301629cc356SHitoshi Mitake 3024157922aSIngo Molnar printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]); 3034157922aSIngo Molnar ret = 1; 304629cc356SHitoshi Mitake goto end; 305629cc356SHitoshi Mitake } 306629cc356SHitoshi Mitake 3074157922aSIngo Molnar printf("Unknown collection: '%s'\n", argv[0]); 3084157922aSIngo Molnar ret = 1; 309629cc356SHitoshi Mitake 310629cc356SHitoshi Mitake end: 3114157922aSIngo Molnar return ret; 312629cc356SHitoshi Mitake } 313