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
14c2a08203SDavidlohr Bueso * syscall ... System call performance
15827f3b49SHitoshi Mitake * mem ... memory access performance
164157922aSIngo Molnar * numa ... NUMA scheduling and MM performance
17a0439711SDavidlohr Bueso * futex ... Futex performance
18121dd9eaSDavidlohr Bueso * epoll ... Event poll performance
19629cc356SHitoshi Mitake */
204b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h>
21629cc356SHitoshi Mitake #include "builtin.h"
22629cc356SHitoshi Mitake #include "bench/bench.h"
23629cc356SHitoshi Mitake
2416203e9cSArnaldo Carvalho de Melo #include <locale.h>
25629cc356SHitoshi Mitake #include <stdio.h>
26629cc356SHitoshi Mitake #include <stdlib.h>
27629cc356SHitoshi Mitake #include <string.h>
284157922aSIngo Molnar #include <sys/prctl.h>
297f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
30629cc356SHitoshi Mitake
31b0ad8ea6SArnaldo Carvalho de Melo typedef int (*bench_fn_t)(int argc, const char **argv);
324157922aSIngo Molnar
334157922aSIngo Molnar struct bench {
34629cc356SHitoshi Mitake const char *name;
35629cc356SHitoshi Mitake const char *summary;
364157922aSIngo Molnar bench_fn_t fn;
37629cc356SHitoshi Mitake };
38629cc356SHitoshi Mitake
3989fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT
404157922aSIngo Molnar static struct bench numa_benchmarks[] = {
414157922aSIngo Molnar { "mem", "Benchmark for NUMA workloads", bench_numa },
42aa254af2SIngo Molnar { "all", "Run all NUMA benchmarks", NULL },
434157922aSIngo Molnar { NULL, NULL, NULL }
441c13f3c9SIngo Molnar };
4579d824e3SPeter Hurley #endif
461c13f3c9SIngo Molnar
474157922aSIngo Molnar static struct bench sched_benchmarks[] = {
484157922aSIngo Molnar { "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging },
494157922aSIngo Molnar { "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe },
507d5cb68aSAndrei Vagin { "seccomp-notify", "Benchmark for seccomp user notify", bench_sched_seccomp_notify},
51aa254af2SIngo Molnar { "all", "Run all scheduler benchmarks", NULL },
524157922aSIngo Molnar { NULL, NULL, NULL }
53629cc356SHitoshi Mitake };
54629cc356SHitoshi Mitake
55c2a08203SDavidlohr Bueso static struct bench syscall_benchmarks[] = {
56c2a08203SDavidlohr Bueso { "basic", "Benchmark for basic getppid(2) calls", bench_syscall_basic },
57391f84e5STiezhu Yang { "getpgid", "Benchmark for getpgid(2) calls", bench_syscall_getpgid },
58ece7f7c0STiezhu Yang { "fork", "Benchmark for fork(2) calls", bench_syscall_fork },
59540f8b56STiezhu Yang { "execve", "Benchmark for execve(2) calls", bench_syscall_execve },
60c2a08203SDavidlohr Bueso { "all", "Run all syscall benchmarks", NULL },
61c2a08203SDavidlohr Bueso { NULL, NULL, NULL },
62c2a08203SDavidlohr Bueso };
63c2a08203SDavidlohr Bueso
644157922aSIngo Molnar static struct bench mem_benchmarks[] = {
6513b1fdceSIngo Molnar { "memcpy", "Benchmark for memcpy() functions", bench_mem_memcpy },
6613b1fdceSIngo Molnar { "memset", "Benchmark for memset() functions", bench_mem_memset },
677c43b0c1SIan Rogers { "find_bit", "Benchmark for find_bit() functions", bench_mem_find_bit },
68aa254af2SIngo Molnar { "all", "Run all memory access benchmarks", NULL },
694157922aSIngo Molnar { NULL, NULL, NULL }
70827f3b49SHitoshi Mitake };
71827f3b49SHitoshi Mitake
72a0439711SDavidlohr Bueso static struct bench futex_benchmarks[] = {
73a0439711SDavidlohr Bueso { "hash", "Benchmark for futex hash table", bench_futex_hash },
7427db7830SDavidlohr Bueso { "wake", "Benchmark for futex wake calls", bench_futex_wake },
75d65817b4SDavidlohr Bueso { "wake-parallel", "Benchmark for parallel futex wake calls", bench_futex_wake_parallel },
760fb298cfSDavidlohr Bueso { "requeue", "Benchmark for futex requeue calls", bench_futex_requeue },
77d2f3f5d2SDavidlohr Bueso /* pi-futexes */
78d2f3f5d2SDavidlohr Bueso { "lock-pi", "Benchmark for futex lock_pi calls", bench_futex_lock_pi },
79aa254af2SIngo Molnar { "all", "Run all futex benchmarks", NULL },
80a0439711SDavidlohr Bueso { NULL, NULL, NULL }
81a0439711SDavidlohr Bueso };
82a0439711SDavidlohr Bueso
83ba35fe93SArnaldo Carvalho de Melo #ifdef HAVE_EVENTFD_SUPPORT
84121dd9eaSDavidlohr Bueso static struct bench epoll_benchmarks[] = {
85121dd9eaSDavidlohr Bueso { "wait", "Benchmark epoll concurrent epoll_waits", bench_epoll_wait },
86231457ecSDavidlohr Bueso { "ctl", "Benchmark epoll concurrent epoll_ctls", bench_epoll_ctl },
87121dd9eaSDavidlohr Bueso { "all", "Run all futex benchmarks", NULL },
88121dd9eaSDavidlohr Bueso { NULL, NULL, NULL }
89121dd9eaSDavidlohr Bueso };
90ba35fe93SArnaldo Carvalho de Melo #endif // HAVE_EVENTFD_SUPPORT
91121dd9eaSDavidlohr Bueso
922a4b5166SIan Rogers static struct bench internals_benchmarks[] = {
932a4b5166SIan Rogers { "synthesize", "Benchmark perf event synthesis", bench_synthesize },
9451876bd4SIan Rogers { "kallsyms-parse", "Benchmark kallsyms parsing", bench_kallsyms_parse },
950bf02a0dSNamhyung Kim { "inject-build-id", "Benchmark build-id injection", bench_inject_build_id },
964241eabfSRiccardo Mancini { "evlist-open-close", "Benchmark evlist open and close", bench_evlist_open_close },
97f6a7bbbfSNamhyung Kim { "pmu-scan", "Benchmark sysfs PMU info scanning", bench_pmu_scan },
982a4b5166SIan Rogers { NULL, NULL, NULL }
992a4b5166SIan Rogers };
1002a4b5166SIan Rogers
10168a6772fSDmitry Vyukov static struct bench breakpoint_benchmarks[] = {
10268a6772fSDmitry Vyukov { "thread", "Benchmark thread start/finish with breakpoints", bench_breakpoint_thread},
10368a6772fSDmitry Vyukov { "enable", "Benchmark breakpoint enable/disable", bench_breakpoint_enable},
10468a6772fSDmitry Vyukov { "all", "Run all breakpoint benchmarks", NULL},
10568a6772fSDmitry Vyukov { NULL, NULL, NULL },
10668a6772fSDmitry Vyukov };
10768a6772fSDmitry Vyukov
1082df27071SArnaldo Carvalho de Melo static struct bench uprobe_benchmarks[] = {
1092df27071SArnaldo Carvalho de Melo { "baseline", "Baseline libc usleep(1000) call", bench_uprobe_baseline, },
1106af5e4cfSArnaldo Carvalho de Melo { "empty", "Attach empty BPF prog to uprobe on usleep, system wide", bench_uprobe_empty, },
111*7b47623bSArnaldo Carvalho de Melo { "trace_printk", "Attach trace_printk BPF prog to uprobe on usleep syswide", bench_uprobe_trace_printk, },
1122df27071SArnaldo Carvalho de Melo { NULL, NULL, NULL },
1132df27071SArnaldo Carvalho de Melo };
1142df27071SArnaldo Carvalho de Melo
1154157922aSIngo Molnar struct collection {
116629cc356SHitoshi Mitake const char *name;
117629cc356SHitoshi Mitake const char *summary;
1184157922aSIngo Molnar struct bench *benchmarks;
119629cc356SHitoshi Mitake };
120629cc356SHitoshi Mitake
1214157922aSIngo Molnar static struct collection collections[] = {
1224157922aSIngo Molnar { "sched", "Scheduler and IPC benchmarks", sched_benchmarks },
123c2a08203SDavidlohr Bueso { "syscall", "System call benchmarks", syscall_benchmarks },
1244157922aSIngo Molnar { "mem", "Memory access benchmarks", mem_benchmarks },
12589fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT
1264157922aSIngo Molnar { "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
12779d824e3SPeter Hurley #endif
128a0439711SDavidlohr Bueso {"futex", "Futex stressing benchmarks", futex_benchmarks },
129ba35fe93SArnaldo Carvalho de Melo #ifdef HAVE_EVENTFD_SUPPORT
130121dd9eaSDavidlohr Bueso {"epoll", "Epoll stressing benchmarks", epoll_benchmarks },
131121dd9eaSDavidlohr Bueso #endif
1322a4b5166SIan Rogers { "internals", "Perf-internals benchmarks", internals_benchmarks },
13368a6772fSDmitry Vyukov { "breakpoint", "Breakpoint benchmarks", breakpoint_benchmarks },
1342df27071SArnaldo Carvalho de Melo { "uprobe", "uprobe benchmarks", uprobe_benchmarks },
1354157922aSIngo Molnar { "all", "All benchmarks", NULL },
1364157922aSIngo Molnar { NULL, NULL, NULL }
137629cc356SHitoshi Mitake };
138629cc356SHitoshi Mitake
1394157922aSIngo Molnar /* Iterate over all benchmark collections: */
1404157922aSIngo Molnar #define for_each_collection(coll) \
1414157922aSIngo Molnar for (coll = collections; coll->name; coll++)
1424157922aSIngo Molnar
1434157922aSIngo Molnar /* Iterate over all benchmarks within a collection: */
1444157922aSIngo Molnar #define for_each_bench(coll, bench) \
1456eeefccdSPatrick Palka for (bench = coll->benchmarks; bench && bench->name; bench++)
1464157922aSIngo Molnar
dump_benchmarks(struct collection * coll)1474157922aSIngo Molnar static void dump_benchmarks(struct collection *coll)
148629cc356SHitoshi Mitake {
1494157922aSIngo Molnar struct bench *bench;
150629cc356SHitoshi Mitake
1514157922aSIngo Molnar printf("\n # List of available benchmarks for collection '%s':\n\n", coll->name);
152629cc356SHitoshi Mitake
1534157922aSIngo Molnar for_each_bench(coll, bench)
1544157922aSIngo Molnar printf("%14s: %s\n", bench->name, bench->summary);
155629cc356SHitoshi Mitake
156629cc356SHitoshi Mitake printf("\n");
157629cc356SHitoshi Mitake }
158629cc356SHitoshi Mitake
159edb7c60eSArnaldo Carvalho de Melo static const char *bench_format_str;
1604157922aSIngo Molnar
1614157922aSIngo Molnar /* Output/formatting style, exported to benchmark modules: */
162386d7e9eSHitoshi Mitake int bench_format = BENCH_FORMAT_DEFAULT;
163b6f0629aSDavidlohr Bueso unsigned int bench_repeat = 10; /* default number of times to repeat the run */
164629cc356SHitoshi Mitake
165386d7e9eSHitoshi Mitake static const struct option bench_options[] = {
1667a46a8fdSIngo Molnar OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"),
167fc5d836cSDiederik de Haas OPT_UINTEGER('r', "repeat", &bench_repeat, "Specify number of times to repeat the run"),
168386d7e9eSHitoshi Mitake OPT_END()
169386d7e9eSHitoshi Mitake };
170386d7e9eSHitoshi Mitake
171386d7e9eSHitoshi Mitake static const char * const bench_usage[] = {
1724157922aSIngo Molnar "perf bench [<common options>] <collection> <benchmark> [<options>]",
173386d7e9eSHitoshi Mitake NULL
174386d7e9eSHitoshi Mitake };
175386d7e9eSHitoshi Mitake
print_usage(void)176386d7e9eSHitoshi Mitake static void print_usage(void)
177386d7e9eSHitoshi Mitake {
1784157922aSIngo Molnar struct collection *coll;
179386d7e9eSHitoshi Mitake int i;
180386d7e9eSHitoshi Mitake
181386d7e9eSHitoshi Mitake printf("Usage: \n");
182386d7e9eSHitoshi Mitake for (i = 0; bench_usage[i]; i++)
183386d7e9eSHitoshi Mitake printf("\t%s\n", bench_usage[i]);
184386d7e9eSHitoshi Mitake printf("\n");
185386d7e9eSHitoshi Mitake
1864157922aSIngo Molnar printf(" # List of all available benchmark collections:\n\n");
187629cc356SHitoshi Mitake
1884157922aSIngo Molnar for_each_collection(coll)
1894157922aSIngo Molnar printf("%14s: %s\n", coll->name, coll->summary);
190629cc356SHitoshi Mitake printf("\n");
191386d7e9eSHitoshi Mitake }
192629cc356SHitoshi Mitake
bench_str2int(const char * str)193edb7c60eSArnaldo Carvalho de Melo static int bench_str2int(const char *str)
194386d7e9eSHitoshi Mitake {
195386d7e9eSHitoshi Mitake if (!str)
196386d7e9eSHitoshi Mitake return BENCH_FORMAT_DEFAULT;
197386d7e9eSHitoshi Mitake
198386d7e9eSHitoshi Mitake if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
199386d7e9eSHitoshi Mitake return BENCH_FORMAT_DEFAULT;
200386d7e9eSHitoshi Mitake else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
201386d7e9eSHitoshi Mitake return BENCH_FORMAT_SIMPLE;
202386d7e9eSHitoshi Mitake
203386d7e9eSHitoshi Mitake return BENCH_FORMAT_UNKNOWN;
204386d7e9eSHitoshi Mitake }
205386d7e9eSHitoshi Mitake
2064157922aSIngo Molnar /*
2074157922aSIngo Molnar * Run a specific benchmark but first rename the running task's ->comm[]
2084157922aSIngo Molnar * to something meaningful:
2094157922aSIngo Molnar */
run_bench(const char * coll_name,const char * bench_name,bench_fn_t fn,int argc,const char ** argv)2104157922aSIngo Molnar static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
211b0ad8ea6SArnaldo Carvalho de Melo int argc, const char **argv)
2122044279dSHitoshi Mitake {
2134157922aSIngo Molnar int size;
2144157922aSIngo Molnar char *name;
2154157922aSIngo Molnar int ret;
2164157922aSIngo Molnar
2174157922aSIngo Molnar size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
2184157922aSIngo Molnar
2194157922aSIngo Molnar name = zalloc(size);
2204157922aSIngo Molnar BUG_ON(!name);
2214157922aSIngo Molnar
2224157922aSIngo Molnar scnprintf(name, size, "%s-%s", coll_name, bench_name);
2234157922aSIngo Molnar
2244157922aSIngo Molnar prctl(PR_SET_NAME, name);
2254157922aSIngo Molnar argv[0] = name;
2264157922aSIngo Molnar
227b0ad8ea6SArnaldo Carvalho de Melo ret = fn(argc, argv);
2284157922aSIngo Molnar
2294157922aSIngo Molnar free(name);
2304157922aSIngo Molnar
2314157922aSIngo Molnar return ret;
2324157922aSIngo Molnar }
2334157922aSIngo Molnar
run_collection(struct collection * coll)2344157922aSIngo Molnar static void run_collection(struct collection *coll)
2354157922aSIngo Molnar {
2364157922aSIngo Molnar struct bench *bench;
2372044279dSHitoshi Mitake const char *argv[2];
2382044279dSHitoshi Mitake
2392044279dSHitoshi Mitake argv[1] = NULL;
2402044279dSHitoshi Mitake /*
2412044279dSHitoshi Mitake * TODO:
2424157922aSIngo Molnar *
2434157922aSIngo Molnar * Preparing preset parameters for
2442044279dSHitoshi Mitake * embedded, ordinary PC, HPC, etc...
2454157922aSIngo Molnar * would be helpful.
2462044279dSHitoshi Mitake */
2474157922aSIngo Molnar for_each_bench(coll, bench) {
2484157922aSIngo Molnar if (!bench->fn)
2494157922aSIngo Molnar break;
2504157922aSIngo Molnar printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
2512044279dSHitoshi Mitake
2524157922aSIngo Molnar argv[1] = bench->name;
253b0ad8ea6SArnaldo Carvalho de Melo run_bench(coll->name, bench->name, bench->fn, 1, argv);
2542044279dSHitoshi Mitake printf("\n");
2552044279dSHitoshi Mitake }
2562044279dSHitoshi Mitake }
2572044279dSHitoshi Mitake
run_all_collections(void)2584157922aSIngo Molnar static void run_all_collections(void)
2592044279dSHitoshi Mitake {
2604157922aSIngo Molnar struct collection *coll;
2614157922aSIngo Molnar
2624157922aSIngo Molnar for_each_collection(coll)
2634157922aSIngo Molnar run_collection(coll);
2642044279dSHitoshi Mitake }
2652044279dSHitoshi Mitake
cmd_bench(int argc,const char ** argv)266b0ad8ea6SArnaldo Carvalho de Melo int cmd_bench(int argc, const char **argv)
267386d7e9eSHitoshi Mitake {
2684157922aSIngo Molnar struct collection *coll;
2694157922aSIngo Molnar int ret = 0;
270386d7e9eSHitoshi Mitake
271f0a29c96SSohaib Mohamed /* Unbuffered output */
272f0a29c96SSohaib Mohamed setvbuf(stdout, NULL, _IONBF, 0);
27316203e9cSArnaldo Carvalho de Melo setlocale(LC_ALL, "");
274f0a29c96SSohaib Mohamed
275386d7e9eSHitoshi Mitake if (argc < 2) {
2764157922aSIngo Molnar /* No collection specified. */
277386d7e9eSHitoshi Mitake print_usage();
278386d7e9eSHitoshi Mitake goto end;
279386d7e9eSHitoshi Mitake }
280386d7e9eSHitoshi Mitake
281386d7e9eSHitoshi Mitake argc = parse_options(argc, argv, bench_options, bench_usage,
282386d7e9eSHitoshi Mitake PARSE_OPT_STOP_AT_NON_OPTION);
283386d7e9eSHitoshi Mitake
284386d7e9eSHitoshi Mitake bench_format = bench_str2int(bench_format_str);
285386d7e9eSHitoshi Mitake if (bench_format == BENCH_FORMAT_UNKNOWN) {
2864157922aSIngo Molnar printf("Unknown format descriptor: '%s'\n", bench_format_str);
287386d7e9eSHitoshi Mitake goto end;
288386d7e9eSHitoshi Mitake }
289386d7e9eSHitoshi Mitake
290b6f0629aSDavidlohr Bueso if (bench_repeat == 0) {
291b6f0629aSDavidlohr Bueso printf("Invalid repeat option: Must specify a positive value\n");
292b6f0629aSDavidlohr Bueso goto end;
293b6f0629aSDavidlohr Bueso }
294b6f0629aSDavidlohr Bueso
295386d7e9eSHitoshi Mitake if (argc < 1) {
296386d7e9eSHitoshi Mitake print_usage();
297629cc356SHitoshi Mitake goto end;
298629cc356SHitoshi Mitake }
299629cc356SHitoshi Mitake
3002044279dSHitoshi Mitake if (!strcmp(argv[0], "all")) {
3014157922aSIngo Molnar run_all_collections();
3022044279dSHitoshi Mitake goto end;
3032044279dSHitoshi Mitake }
3042044279dSHitoshi Mitake
3054157922aSIngo Molnar for_each_collection(coll) {
3064157922aSIngo Molnar struct bench *bench;
3074157922aSIngo Molnar
3084157922aSIngo Molnar if (strcmp(coll->name, argv[0]))
309629cc356SHitoshi Mitake continue;
310629cc356SHitoshi Mitake
311386d7e9eSHitoshi Mitake if (argc < 2) {
3124157922aSIngo Molnar /* No bench specified. */
3134157922aSIngo Molnar dump_benchmarks(coll);
314629cc356SHitoshi Mitake goto end;
315629cc356SHitoshi Mitake }
316629cc356SHitoshi Mitake
3172044279dSHitoshi Mitake if (!strcmp(argv[1], "all")) {
3184157922aSIngo Molnar run_collection(coll);
3192044279dSHitoshi Mitake goto end;
3202044279dSHitoshi Mitake }
3212044279dSHitoshi Mitake
3224157922aSIngo Molnar for_each_bench(coll, bench) {
3234157922aSIngo Molnar if (strcmp(bench->name, argv[1]))
324629cc356SHitoshi Mitake continue;
325629cc356SHitoshi Mitake
32679e295d4SHitoshi Mitake if (bench_format == BENCH_FORMAT_DEFAULT)
3274157922aSIngo Molnar printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
328b0ad8ea6SArnaldo Carvalho de Melo ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
329629cc356SHitoshi Mitake goto end;
330629cc356SHitoshi Mitake }
331629cc356SHitoshi Mitake
332386d7e9eSHitoshi Mitake if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
3334157922aSIngo Molnar dump_benchmarks(coll);
334629cc356SHitoshi Mitake goto end;
335629cc356SHitoshi Mitake }
336629cc356SHitoshi Mitake
3374157922aSIngo Molnar printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
3384157922aSIngo Molnar ret = 1;
339629cc356SHitoshi Mitake goto end;
340629cc356SHitoshi Mitake }
341629cc356SHitoshi Mitake
3424157922aSIngo Molnar printf("Unknown collection: '%s'\n", argv[0]);
3434157922aSIngo Molnar ret = 1;
344629cc356SHitoshi Mitake
345629cc356SHitoshi Mitake end:
3464157922aSIngo Molnar return ret;
347629cc356SHitoshi Mitake }
348