1 // SPDX-License-Identifier: GPL-2.0
5 * General benchmarking collections provided by perf
7 * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
11 * Available benchmark collection list:
13 * sched ... scheduler and IPC performance
14 * syscall ... System call performance
15 * mem ... memory access performance
16 * numa ... NUMA scheduling and MM performance
17 * futex ... Futex performance
18 * epoll ... Event poll performance
20 #include <subcmd/parse-options.h>
22 #include "bench/bench.h"
28 #include <sys/prctl.h>
29 #include <linux/zalloc.h>
31 typedef int (*bench_fn_t
)(int argc
, const char **argv
);
39 #ifdef HAVE_LIBNUMA_SUPPORT
40 static struct bench numa_benchmarks
[] = {
41 { "mem", "Benchmark for NUMA workloads", bench_numa
},
42 { "all", "Run all NUMA benchmarks", NULL
},
47 static struct bench sched_benchmarks
[] = {
48 { "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging
},
49 { "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe
},
50 { "seccomp-notify", "Benchmark for seccomp user notify", bench_sched_seccomp_notify
},
51 { "all", "Run all scheduler benchmarks", NULL
},
55 static struct bench syscall_benchmarks
[] = {
56 { "basic", "Benchmark for basic getppid(2) calls", bench_syscall_basic
},
57 { "getpgid", "Benchmark for getpgid(2) calls", bench_syscall_getpgid
},
58 { "fork", "Benchmark for fork(2) calls", bench_syscall_fork
},
59 { "execve", "Benchmark for execve(2) calls", bench_syscall_execve
},
60 { "all", "Run all syscall benchmarks", NULL
},
64 static struct bench mem_benchmarks
[] = {
65 { "memcpy", "Benchmark for memcpy() functions", bench_mem_memcpy
},
66 { "memset", "Benchmark for memset() functions", bench_mem_memset
},
67 { "find_bit", "Benchmark for find_bit() functions", bench_mem_find_bit
},
68 { "all", "Run all memory access benchmarks", NULL
},
72 static struct bench futex_benchmarks
[] = {
73 { "hash", "Benchmark for futex hash table", bench_futex_hash
},
74 { "wake", "Benchmark for futex wake calls", bench_futex_wake
},
75 { "wake-parallel", "Benchmark for parallel futex wake calls", bench_futex_wake_parallel
},
76 { "requeue", "Benchmark for futex requeue calls", bench_futex_requeue
},
78 { "lock-pi", "Benchmark for futex lock_pi calls", bench_futex_lock_pi
},
79 { "all", "Run all futex benchmarks", NULL
},
83 #ifdef HAVE_EVENTFD_SUPPORT
84 static struct bench epoll_benchmarks
[] = {
85 { "wait", "Benchmark epoll concurrent epoll_waits", bench_epoll_wait
},
86 { "ctl", "Benchmark epoll concurrent epoll_ctls", bench_epoll_ctl
},
87 { "all", "Run all futex benchmarks", NULL
},
90 #endif // HAVE_EVENTFD_SUPPORT
92 static struct bench internals_benchmarks
[] = {
93 { "synthesize", "Benchmark perf event synthesis", bench_synthesize
},
94 { "kallsyms-parse", "Benchmark kallsyms parsing", bench_kallsyms_parse
},
95 { "inject-build-id", "Benchmark build-id injection", bench_inject_build_id
},
96 { "evlist-open-close", "Benchmark evlist open and close", bench_evlist_open_close
},
97 { "pmu-scan", "Benchmark sysfs PMU info scanning", bench_pmu_scan
},
101 static struct bench breakpoint_benchmarks
[] = {
102 { "thread", "Benchmark thread start/finish with breakpoints", bench_breakpoint_thread
},
103 { "enable", "Benchmark breakpoint enable/disable", bench_breakpoint_enable
},
104 { "all", "Run all breakpoint benchmarks", NULL
},
105 { NULL
, NULL
, NULL
},
108 static struct bench uprobe_benchmarks
[] = {
109 { "baseline", "Baseline libc usleep(1000) call", bench_uprobe_baseline
, },
110 { "empty", "Attach empty BPF prog to uprobe on usleep, system wide", bench_uprobe_empty
, },
111 { "trace_printk", "Attach trace_printk BPF prog to uprobe on usleep syswide", bench_uprobe_trace_printk
, },
112 { "empty_ret", "Attach empty BPF prog to uretprobe on usleep, system wide", bench_uprobe_empty_ret
, },
113 { "trace_printk_ret", "Attach trace_printk BPF prog to uretprobe on usleep syswide", bench_uprobe_trace_printk_ret
,},
114 { NULL
, NULL
, NULL
},
120 struct bench
*benchmarks
;
123 static struct collection collections
[] = {
124 { "sched", "Scheduler and IPC benchmarks", sched_benchmarks
},
125 { "syscall", "System call benchmarks", syscall_benchmarks
},
126 { "mem", "Memory access benchmarks", mem_benchmarks
},
127 #ifdef HAVE_LIBNUMA_SUPPORT
128 { "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks
},
130 {"futex", "Futex stressing benchmarks", futex_benchmarks
},
131 #ifdef HAVE_EVENTFD_SUPPORT
132 {"epoll", "Epoll stressing benchmarks", epoll_benchmarks
},
134 { "internals", "Perf-internals benchmarks", internals_benchmarks
},
135 { "breakpoint", "Breakpoint benchmarks", breakpoint_benchmarks
},
136 { "uprobe", "uprobe benchmarks", uprobe_benchmarks
},
137 { "all", "All benchmarks", NULL
},
141 /* Iterate over all benchmark collections: */
142 #define for_each_collection(coll) \
143 for (coll = collections; coll->name; coll++)
145 /* Iterate over all benchmarks within a collection: */
146 #define for_each_bench(coll, bench) \
147 for (bench = coll->benchmarks; bench && bench->name; bench++)
149 static void dump_benchmarks(struct collection
*coll
)
153 printf("\n # List of available benchmarks for collection '%s':\n\n", coll
->name
);
155 for_each_bench(coll
, bench
)
156 printf("%14s: %s\n", bench
->name
, bench
->summary
);
161 static const char *bench_format_str
;
163 /* Output/formatting style, exported to benchmark modules: */
164 int bench_format
= BENCH_FORMAT_DEFAULT
;
165 unsigned int bench_repeat
= 10; /* default number of times to repeat the run */
167 static const struct option bench_options
[] = {
168 OPT_STRING('f', "format", &bench_format_str
, "default|simple", "Specify the output formatting style"),
169 OPT_UINTEGER('r', "repeat", &bench_repeat
, "Specify number of times to repeat the run"),
173 static const char * const bench_usage
[] = {
174 "perf bench [<common options>] <collection> <benchmark> [<options>]",
178 static void print_usage(void)
180 struct collection
*coll
;
184 for (i
= 0; bench_usage
[i
]; i
++)
185 printf("\t%s\n", bench_usage
[i
]);
188 printf(" # List of all available benchmark collections:\n\n");
190 for_each_collection(coll
)
191 printf("%14s: %s\n", coll
->name
, coll
->summary
);
195 static int bench_str2int(const char *str
)
198 return BENCH_FORMAT_DEFAULT
;
200 if (!strcmp(str
, BENCH_FORMAT_DEFAULT_STR
))
201 return BENCH_FORMAT_DEFAULT
;
202 else if (!strcmp(str
, BENCH_FORMAT_SIMPLE_STR
))
203 return BENCH_FORMAT_SIMPLE
;
205 return BENCH_FORMAT_UNKNOWN
;
209 * Run a specific benchmark but first rename the running task's ->comm[]
210 * to something meaningful:
212 static int run_bench(const char *coll_name
, const char *bench_name
, bench_fn_t fn
,
213 int argc
, const char **argv
)
219 size
= strlen(coll_name
) + 1 + strlen(bench_name
) + 1;
224 scnprintf(name
, size
, "%s-%s", coll_name
, bench_name
);
226 prctl(PR_SET_NAME
, name
);
229 ret
= fn(argc
, argv
);
236 static void run_collection(struct collection
*coll
)
245 * Preparing preset parameters for
246 * embedded, ordinary PC, HPC, etc...
249 for_each_bench(coll
, bench
) {
252 printf("# Running %s/%s benchmark...\n", coll
->name
, bench
->name
);
254 argv
[1] = bench
->name
;
255 run_bench(coll
->name
, bench
->name
, bench
->fn
, 1, argv
);
260 static void run_all_collections(void)
262 struct collection
*coll
;
264 for_each_collection(coll
)
265 run_collection(coll
);
268 int cmd_bench(int argc
, const char **argv
)
270 struct collection
*coll
;
273 /* Unbuffered output */
274 setvbuf(stdout
, NULL
, _IONBF
, 0);
275 setlocale(LC_ALL
, "");
278 /* No collection specified. */
283 argc
= parse_options(argc
, argv
, bench_options
, bench_usage
,
284 PARSE_OPT_STOP_AT_NON_OPTION
);
286 bench_format
= bench_str2int(bench_format_str
);
287 if (bench_format
== BENCH_FORMAT_UNKNOWN
) {
288 printf("Unknown format descriptor: '%s'\n", bench_format_str
);
292 if (bench_repeat
== 0) {
293 printf("Invalid repeat option: Must specify a positive value\n");
302 if (!strcmp(argv
[0], "all")) {
303 run_all_collections();
307 for_each_collection(coll
) {
310 if (strcmp(coll
->name
, argv
[0]))
314 /* No bench specified. */
315 dump_benchmarks(coll
);
319 if (!strcmp(argv
[1], "all")) {
320 run_collection(coll
);
324 for_each_bench(coll
, bench
) {
325 if (strcmp(bench
->name
, argv
[1]))
328 if (bench_format
== BENCH_FORMAT_DEFAULT
)
329 printf("# Running '%s/%s' benchmark:\n", coll
->name
, bench
->name
);
330 ret
= run_bench(coll
->name
, bench
->name
, bench
->fn
, argc
-1, argv
+1);
334 if (!strcmp(argv
[1], "-h") || !strcmp(argv
[1], "--help")) {
335 dump_benchmarks(coll
);
339 printf("Unknown benchmark: '%s' for collection '%s'\n", argv
[1], argv
[0]);
344 printf("Unknown collection: '%s'\n", argv
[0]);