Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/perf/builtin-bench.c
26285 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
{ "all", "Run all memory access benchmarks", NULL },
69
{ NULL, NULL, NULL }
70
};
71
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 },
77
/* pi-futexes */
78
{ "lock-pi", "Benchmark for futex lock_pi calls", bench_futex_lock_pi },
79
{ "all", "Run all futex benchmarks", NULL },
80
{ NULL, NULL, NULL }
81
};
82
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 },
88
{ NULL, NULL, NULL }
89
};
90
#endif // HAVE_EVENTFD_SUPPORT
91
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 },
98
{ NULL, NULL, NULL }
99
};
100
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 },
106
};
107
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 },
115
};
116
117
struct collection {
118
const char *name;
119
const char *summary;
120
struct bench *benchmarks;
121
};
122
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 },
129
#endif
130
{"futex", "Futex stressing benchmarks", futex_benchmarks },
131
#ifdef HAVE_EVENTFD_SUPPORT
132
{"epoll", "Epoll stressing benchmarks", epoll_benchmarks },
133
#endif
134
{ "internals", "Perf-internals benchmarks", internals_benchmarks },
135
{ "breakpoint", "Breakpoint benchmarks", breakpoint_benchmarks },
136
{ "uprobe", "uprobe benchmarks", uprobe_benchmarks },
137
{ "all", "All benchmarks", NULL },
138
{ NULL, NULL, NULL }
139
};
140
141
/* Iterate over all benchmark collections: */
142
#define for_each_collection(coll) \
143
for (coll = collections; coll->name; coll++)
144
145
/* Iterate over all benchmarks within a collection: */
146
#define for_each_bench(coll, bench) \
147
for (bench = coll->benchmarks; bench && bench->name; bench++)
148
149
static void dump_benchmarks(struct collection *coll)
150
{
151
struct bench *bench;
152
153
printf("\n # List of available benchmarks for collection '%s':\n\n", coll->name);
154
155
for_each_bench(coll, bench)
156
printf("%14s: %s\n", bench->name, bench->summary);
157
158
printf("\n");
159
}
160
161
static const char *bench_format_str;
162
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 */
166
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"),
170
OPT_END()
171
};
172
173
static const char * const bench_usage[] = {
174
"perf bench [<common options>] <collection> <benchmark> [<options>]",
175
NULL
176
};
177
178
static void print_usage(void)
179
{
180
struct collection *coll;
181
int i;
182
183
printf("Usage: \n");
184
for (i = 0; bench_usage[i]; i++)
185
printf("\t%s\n", bench_usage[i]);
186
printf("\n");
187
188
printf(" # List of all available benchmark collections:\n\n");
189
190
for_each_collection(coll)
191
printf("%14s: %s\n", coll->name, coll->summary);
192
printf("\n");
193
}
194
195
static int bench_str2int(const char *str)
196
{
197
if (!str)
198
return BENCH_FORMAT_DEFAULT;
199
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;
204
205
return BENCH_FORMAT_UNKNOWN;
206
}
207
208
/*
209
* Run a specific benchmark but first rename the running task's ->comm[]
210
* to something meaningful:
211
*/
212
static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
213
int argc, const char **argv)
214
{
215
int size;
216
char *name;
217
int ret;
218
219
size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
220
221
name = zalloc(size);
222
BUG_ON(!name);
223
224
scnprintf(name, size, "%s-%s", coll_name, bench_name);
225
226
prctl(PR_SET_NAME, name);
227
argv[0] = name;
228
229
ret = fn(argc, argv);
230
231
free(name);
232
233
return ret;
234
}
235
236
static void run_collection(struct collection *coll)
237
{
238
struct bench *bench;
239
const char *argv[2];
240
241
argv[1] = NULL;
242
/*
243
* TODO:
244
*
245
* Preparing preset parameters for
246
* embedded, ordinary PC, HPC, etc...
247
* would be helpful.
248
*/
249
for_each_bench(coll, bench) {
250
if (!bench->fn)
251
break;
252
printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
253
254
argv[1] = bench->name;
255
run_bench(coll->name, bench->name, bench->fn, 1, argv);
256
printf("\n");
257
}
258
}
259
260
static void run_all_collections(void)
261
{
262
struct collection *coll;
263
264
for_each_collection(coll)
265
run_collection(coll);
266
}
267
268
int cmd_bench(int argc, const char **argv)
269
{
270
struct collection *coll;
271
int ret = 0;
272
273
/* Unbuffered output */
274
setvbuf(stdout, NULL, _IONBF, 0);
275
setlocale(LC_ALL, "");
276
277
if (argc < 2) {
278
/* No collection specified. */
279
print_usage();
280
goto end;
281
}
282
283
argc = parse_options(argc, argv, bench_options, bench_usage,
284
PARSE_OPT_STOP_AT_NON_OPTION);
285
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);
289
goto end;
290
}
291
292
if (bench_repeat == 0) {
293
printf("Invalid repeat option: Must specify a positive value\n");
294
goto end;
295
}
296
297
if (argc < 1) {
298
print_usage();
299
goto end;
300
}
301
302
if (!strcmp(argv[0], "all")) {
303
run_all_collections();
304
goto end;
305
}
306
307
for_each_collection(coll) {
308
struct bench *bench;
309
310
if (strcmp(coll->name, argv[0]))
311
continue;
312
313
if (argc < 2) {
314
/* No bench specified. */
315
dump_benchmarks(coll);
316
goto end;
317
}
318
319
if (!strcmp(argv[1], "all")) {
320
run_collection(coll);
321
goto end;
322
}
323
324
for_each_bench(coll, bench) {
325
if (strcmp(bench->name, argv[1]))
326
continue;
327
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);
331
goto end;
332
}
333
334
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
335
dump_benchmarks(coll);
336
goto end;
337
}
338
339
printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
340
ret = 1;
341
goto end;
342
}
343
344
printf("Unknown collection: '%s'\n", argv[0]);
345
ret = 1;
346
347
end:
348
return ret;
349
}
350
351