Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/perf/builtin-bench.c
49657 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* builtin-bench.c
4
*
5
* General benchmarking collections provided by perf
6
*
7
* Copyright (C) 2009, Hitoshi Mitake <[email protected]>
8
*/
9
10
/*
11
* Available benchmark collection list:
12
*
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
19
*/
20
#include <subcmd/parse-options.h>
21
#include "builtin.h"
22
#include "bench/bench.h"
23
24
#include <locale.h>
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <sys/prctl.h>
29
#include <linux/zalloc.h>
30
31
typedef int (*bench_fn_t)(int argc, const char **argv);
32
33
struct bench {
34
const char *name;
35
const char *summary;
36
bench_fn_t fn;
37
};
38
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 },
43
{ NULL, NULL, NULL }
44
};
45
#endif
46
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 },
52
{ NULL, NULL, NULL }
53
};
54
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 },
61
{ NULL, NULL, NULL },
62
};
63
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
{ "mmap", "Benchmark for mmap() mappings", bench_mem_mmap },
69
{ "all", "Run all memory access benchmarks", NULL },
70
{ NULL, NULL, NULL }
71
};
72
73
static struct bench futex_benchmarks[] = {
74
{ "hash", "Benchmark for futex hash table", bench_futex_hash },
75
{ "wake", "Benchmark for futex wake calls", bench_futex_wake },
76
{ "wake-parallel", "Benchmark for parallel futex wake calls", bench_futex_wake_parallel },
77
{ "requeue", "Benchmark for futex requeue calls", bench_futex_requeue },
78
/* pi-futexes */
79
{ "lock-pi", "Benchmark for futex lock_pi calls", bench_futex_lock_pi },
80
{ "all", "Run all futex benchmarks", NULL },
81
{ NULL, NULL, NULL }
82
};
83
84
#ifdef HAVE_EVENTFD_SUPPORT
85
static struct bench epoll_benchmarks[] = {
86
{ "wait", "Benchmark epoll concurrent epoll_waits", bench_epoll_wait },
87
{ "ctl", "Benchmark epoll concurrent epoll_ctls", bench_epoll_ctl },
88
{ "all", "Run all futex benchmarks", NULL },
89
{ NULL, NULL, NULL }
90
};
91
#endif // HAVE_EVENTFD_SUPPORT
92
93
static struct bench internals_benchmarks[] = {
94
{ "synthesize", "Benchmark perf event synthesis", bench_synthesize },
95
{ "kallsyms-parse", "Benchmark kallsyms parsing", bench_kallsyms_parse },
96
{ "inject-build-id", "Benchmark build-id injection", bench_inject_build_id },
97
{ "evlist-open-close", "Benchmark evlist open and close", bench_evlist_open_close },
98
{ "pmu-scan", "Benchmark sysfs PMU info scanning", bench_pmu_scan },
99
{ NULL, NULL, NULL }
100
};
101
102
static struct bench breakpoint_benchmarks[] = {
103
{ "thread", "Benchmark thread start/finish with breakpoints", bench_breakpoint_thread},
104
{ "enable", "Benchmark breakpoint enable/disable", bench_breakpoint_enable},
105
{ "all", "Run all breakpoint benchmarks", NULL},
106
{ NULL, NULL, NULL },
107
};
108
109
static struct bench uprobe_benchmarks[] = {
110
{ "baseline", "Baseline libc usleep(1000) call", bench_uprobe_baseline, },
111
{ "empty", "Attach empty BPF prog to uprobe on usleep, system wide", bench_uprobe_empty, },
112
{ "trace_printk", "Attach trace_printk BPF prog to uprobe on usleep syswide", bench_uprobe_trace_printk, },
113
{ "empty_ret", "Attach empty BPF prog to uretprobe on usleep, system wide", bench_uprobe_empty_ret, },
114
{ "trace_printk_ret", "Attach trace_printk BPF prog to uretprobe on usleep syswide", bench_uprobe_trace_printk_ret,},
115
{ NULL, NULL, NULL },
116
};
117
118
struct collection {
119
const char *name;
120
const char *summary;
121
struct bench *benchmarks;
122
};
123
124
static struct collection collections[] = {
125
{ "sched", "Scheduler and IPC benchmarks", sched_benchmarks },
126
{ "syscall", "System call benchmarks", syscall_benchmarks },
127
{ "mem", "Memory access benchmarks", mem_benchmarks },
128
#ifdef HAVE_LIBNUMA_SUPPORT
129
{ "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
130
#endif
131
{"futex", "Futex stressing benchmarks", futex_benchmarks },
132
#ifdef HAVE_EVENTFD_SUPPORT
133
{"epoll", "Epoll stressing benchmarks", epoll_benchmarks },
134
#endif
135
{ "internals", "Perf-internals benchmarks", internals_benchmarks },
136
{ "breakpoint", "Breakpoint benchmarks", breakpoint_benchmarks },
137
{ "uprobe", "uprobe benchmarks", uprobe_benchmarks },
138
{ "all", "All benchmarks", NULL },
139
{ NULL, NULL, NULL }
140
};
141
142
/* Iterate over all benchmark collections: */
143
#define for_each_collection(coll) \
144
for (coll = collections; coll->name; coll++)
145
146
/* Iterate over all benchmarks within a collection: */
147
#define for_each_bench(coll, bench) \
148
for (bench = coll->benchmarks; bench && bench->name; bench++)
149
150
static void dump_benchmarks(struct collection *coll)
151
{
152
struct bench *bench;
153
154
printf("\n # List of available benchmarks for collection '%s':\n\n", coll->name);
155
156
for_each_bench(coll, bench)
157
printf("%14s: %s\n", bench->name, bench->summary);
158
159
printf("\n");
160
}
161
162
static const char *bench_format_str;
163
164
/* Output/formatting style, exported to benchmark modules: */
165
int bench_format = BENCH_FORMAT_DEFAULT;
166
unsigned int bench_repeat = 10; /* default number of times to repeat the run */
167
168
static const struct option bench_options[] = {
169
OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"),
170
OPT_UINTEGER('r', "repeat", &bench_repeat, "Specify number of times to repeat the run"),
171
OPT_END()
172
};
173
174
static const char * const bench_usage[] = {
175
"perf bench [<common options>] <collection> <benchmark> [<options>]",
176
NULL
177
};
178
179
static void print_usage(void)
180
{
181
struct collection *coll;
182
int i;
183
184
printf("Usage: \n");
185
for (i = 0; bench_usage[i]; i++)
186
printf("\t%s\n", bench_usage[i]);
187
printf("\n");
188
189
printf(" # List of all available benchmark collections:\n\n");
190
191
for_each_collection(coll)
192
printf("%14s: %s\n", coll->name, coll->summary);
193
printf("\n");
194
}
195
196
static int bench_str2int(const char *str)
197
{
198
if (!str)
199
return BENCH_FORMAT_DEFAULT;
200
201
if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
202
return BENCH_FORMAT_DEFAULT;
203
else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
204
return BENCH_FORMAT_SIMPLE;
205
206
return BENCH_FORMAT_UNKNOWN;
207
}
208
209
/*
210
* Run a specific benchmark but first rename the running task's ->comm[]
211
* to something meaningful:
212
*/
213
static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
214
int argc, const char **argv)
215
{
216
int size;
217
char *name;
218
int ret;
219
220
size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
221
222
name = zalloc(size);
223
BUG_ON(!name);
224
225
scnprintf(name, size, "%s-%s", coll_name, bench_name);
226
227
prctl(PR_SET_NAME, name);
228
argv[0] = name;
229
230
ret = fn(argc, argv);
231
232
free(name);
233
234
return ret;
235
}
236
237
static void run_collection(struct collection *coll)
238
{
239
struct bench *bench;
240
const char *argv[2];
241
242
argv[1] = NULL;
243
/*
244
* TODO:
245
*
246
* Preparing preset parameters for
247
* embedded, ordinary PC, HPC, etc...
248
* would be helpful.
249
*/
250
for_each_bench(coll, bench) {
251
if (!bench->fn)
252
break;
253
printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
254
255
argv[1] = bench->name;
256
run_bench(coll->name, bench->name, bench->fn, 1, argv);
257
printf("\n");
258
}
259
}
260
261
static void run_all_collections(void)
262
{
263
struct collection *coll;
264
265
for_each_collection(coll)
266
run_collection(coll);
267
}
268
269
int cmd_bench(int argc, const char **argv)
270
{
271
struct collection *coll;
272
int ret = 0;
273
274
/* Unbuffered output */
275
setvbuf(stdout, NULL, _IONBF, 0);
276
setlocale(LC_ALL, "");
277
278
if (argc < 2) {
279
/* No collection specified. */
280
print_usage();
281
goto end;
282
}
283
284
argc = parse_options(argc, argv, bench_options, bench_usage,
285
PARSE_OPT_STOP_AT_NON_OPTION);
286
287
bench_format = bench_str2int(bench_format_str);
288
if (bench_format == BENCH_FORMAT_UNKNOWN) {
289
printf("Unknown format descriptor: '%s'\n", bench_format_str);
290
goto end;
291
}
292
293
if (bench_repeat == 0) {
294
printf("Invalid repeat option: Must specify a positive value\n");
295
goto end;
296
}
297
298
if (argc < 1) {
299
print_usage();
300
goto end;
301
}
302
303
if (!strcmp(argv[0], "all")) {
304
run_all_collections();
305
goto end;
306
}
307
308
for_each_collection(coll) {
309
struct bench *bench;
310
311
if (strcmp(coll->name, argv[0]))
312
continue;
313
314
if (argc < 2) {
315
/* No bench specified. */
316
dump_benchmarks(coll);
317
goto end;
318
}
319
320
if (!strcmp(argv[1], "all")) {
321
run_collection(coll);
322
goto end;
323
}
324
325
for_each_bench(coll, bench) {
326
if (strcmp(bench->name, argv[1]))
327
continue;
328
329
if (bench_format == BENCH_FORMAT_DEFAULT)
330
printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
331
ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
332
goto end;
333
}
334
335
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
336
dump_benchmarks(coll);
337
goto end;
338
}
339
340
printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
341
ret = 1;
342
goto end;
343
}
344
345
printf("Unknown collection: '%s'\n", argv[0]);
346
ret = 1;
347
348
end:
349
return ret;
350
}
351
352