Merge tag 'ktest-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux...
[linux-2.6-microblaze.git] / tools / perf / builtin-bench.c
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 <mitake@dcl.info.waseda.ac.jp>
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         { NULL, NULL, NULL },
113 };
114
115 struct collection {
116         const char      *name;
117         const char      *summary;
118         struct bench    *benchmarks;
119 };
120
121 static struct collection collections[] = {
122         { "sched",      "Scheduler and IPC benchmarks",                 sched_benchmarks        },
123         { "syscall",    "System call benchmarks",                       syscall_benchmarks      },
124         { "mem",        "Memory access benchmarks",                     mem_benchmarks          },
125 #ifdef HAVE_LIBNUMA_SUPPORT
126         { "numa",       "NUMA scheduling and MM benchmarks",            numa_benchmarks         },
127 #endif
128         {"futex",       "Futex stressing benchmarks",                   futex_benchmarks        },
129 #ifdef HAVE_EVENTFD_SUPPORT
130         {"epoll",       "Epoll stressing benchmarks",                   epoll_benchmarks        },
131 #endif
132         { "internals",  "Perf-internals benchmarks",                    internals_benchmarks    },
133         { "breakpoint", "Breakpoint benchmarks",                        breakpoint_benchmarks   },
134         { "uprobe",     "uprobe benchmarks",                            uprobe_benchmarks       },
135         { "all",        "All benchmarks",                               NULL                    },
136         { NULL,         NULL,                                           NULL                    }
137 };
138
139 /* Iterate over all benchmark collections: */
140 #define for_each_collection(coll) \
141         for (coll = collections; coll->name; coll++)
142
143 /* Iterate over all benchmarks within a collection: */
144 #define for_each_bench(coll, bench) \
145         for (bench = coll->benchmarks; bench && bench->name; bench++)
146
147 static void dump_benchmarks(struct collection *coll)
148 {
149         struct bench *bench;
150
151         printf("\n        # List of available benchmarks for collection '%s':\n\n", coll->name);
152
153         for_each_bench(coll, bench)
154                 printf("%14s: %s\n", bench->name, bench->summary);
155
156         printf("\n");
157 }
158
159 static const char *bench_format_str;
160
161 /* Output/formatting style, exported to benchmark modules: */
162 int bench_format = BENCH_FORMAT_DEFAULT;
163 unsigned int bench_repeat = 10; /* default number of times to repeat the run */
164
165 static const struct option bench_options[] = {
166         OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"),
167         OPT_UINTEGER('r', "repeat",  &bench_repeat,   "Specify number of times to repeat the run"),
168         OPT_END()
169 };
170
171 static const char * const bench_usage[] = {
172         "perf bench [<common options>] <collection> <benchmark> [<options>]",
173         NULL
174 };
175
176 static void print_usage(void)
177 {
178         struct collection *coll;
179         int i;
180
181         printf("Usage: \n");
182         for (i = 0; bench_usage[i]; i++)
183                 printf("\t%s\n", bench_usage[i]);
184         printf("\n");
185
186         printf("        # List of all available benchmark collections:\n\n");
187
188         for_each_collection(coll)
189                 printf("%14s: %s\n", coll->name, coll->summary);
190         printf("\n");
191 }
192
193 static int bench_str2int(const char *str)
194 {
195         if (!str)
196                 return BENCH_FORMAT_DEFAULT;
197
198         if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
199                 return BENCH_FORMAT_DEFAULT;
200         else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
201                 return BENCH_FORMAT_SIMPLE;
202
203         return BENCH_FORMAT_UNKNOWN;
204 }
205
206 /*
207  * Run a specific benchmark but first rename the running task's ->comm[]
208  * to something meaningful:
209  */
210 static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
211                      int argc, const char **argv)
212 {
213         int size;
214         char *name;
215         int ret;
216
217         size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
218
219         name = zalloc(size);
220         BUG_ON(!name);
221
222         scnprintf(name, size, "%s-%s", coll_name, bench_name);
223
224         prctl(PR_SET_NAME, name);
225         argv[0] = name;
226
227         ret = fn(argc, argv);
228
229         free(name);
230
231         return ret;
232 }
233
234 static void run_collection(struct collection *coll)
235 {
236         struct bench *bench;
237         const char *argv[2];
238
239         argv[1] = NULL;
240         /*
241          * TODO:
242          *
243          * Preparing preset parameters for
244          * embedded, ordinary PC, HPC, etc...
245          * would be helpful.
246          */
247         for_each_bench(coll, bench) {
248                 if (!bench->fn)
249                         break;
250                 printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
251
252                 argv[1] = bench->name;
253                 run_bench(coll->name, bench->name, bench->fn, 1, argv);
254                 printf("\n");
255         }
256 }
257
258 static void run_all_collections(void)
259 {
260         struct collection *coll;
261
262         for_each_collection(coll)
263                 run_collection(coll);
264 }
265
266 int cmd_bench(int argc, const char **argv)
267 {
268         struct collection *coll;
269         int ret = 0;
270
271         /* Unbuffered output */
272         setvbuf(stdout, NULL, _IONBF, 0);
273         setlocale(LC_ALL, "");
274
275         if (argc < 2) {
276                 /* No collection specified. */
277                 print_usage();
278                 goto end;
279         }
280
281         argc = parse_options(argc, argv, bench_options, bench_usage,
282                              PARSE_OPT_STOP_AT_NON_OPTION);
283
284         bench_format = bench_str2int(bench_format_str);
285         if (bench_format == BENCH_FORMAT_UNKNOWN) {
286                 printf("Unknown format descriptor: '%s'\n", bench_format_str);
287                 goto end;
288         }
289
290         if (bench_repeat == 0) {
291                 printf("Invalid repeat option: Must specify a positive value\n");
292                 goto end;
293         }
294
295         if (argc < 1) {
296                 print_usage();
297                 goto end;
298         }
299
300         if (!strcmp(argv[0], "all")) {
301                 run_all_collections();
302                 goto end;
303         }
304
305         for_each_collection(coll) {
306                 struct bench *bench;
307
308                 if (strcmp(coll->name, argv[0]))
309                         continue;
310
311                 if (argc < 2) {
312                         /* No bench specified. */
313                         dump_benchmarks(coll);
314                         goto end;
315                 }
316
317                 if (!strcmp(argv[1], "all")) {
318                         run_collection(coll);
319                         goto end;
320                 }
321
322                 for_each_bench(coll, bench) {
323                         if (strcmp(bench->name, argv[1]))
324                                 continue;
325
326                         if (bench_format == BENCH_FORMAT_DEFAULT)
327                                 printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
328                         ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
329                         goto end;
330                 }
331
332                 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
333                         dump_benchmarks(coll);
334                         goto end;
335                 }
336
337                 printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
338                 ret = 1;
339                 goto end;
340         }
341
342         printf("Unknown collection: '%s'\n", argv[0]);
343         ret = 1;
344
345 end:
346         return ret;
347 }