perf bench: Add event synthesis benchmark
[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  *  mem   ... memory access performance
15  *  numa  ... NUMA scheduling and MM performance
16  *  futex ... Futex performance
17  *  epoll ... Event poll performance
18  */
19 #include <subcmd/parse-options.h>
20 #include "builtin.h"
21 #include "bench/bench.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/prctl.h>
27 #include <linux/zalloc.h>
28
29 typedef int (*bench_fn_t)(int argc, const char **argv);
30
31 struct bench {
32         const char      *name;
33         const char      *summary;
34         bench_fn_t      fn;
35 };
36
37 #ifdef HAVE_LIBNUMA_SUPPORT
38 static struct bench numa_benchmarks[] = {
39         { "mem",        "Benchmark for NUMA workloads",                 bench_numa              },
40         { "all",        "Run all NUMA benchmarks",                      NULL                    },
41         { NULL,         NULL,                                           NULL                    }
42 };
43 #endif
44
45 static struct bench sched_benchmarks[] = {
46         { "messaging",  "Benchmark for scheduling and IPC",             bench_sched_messaging   },
47         { "pipe",       "Benchmark for pipe() between two processes",   bench_sched_pipe        },
48         { "all",        "Run all scheduler benchmarks",         NULL                    },
49         { NULL,         NULL,                                           NULL                    }
50 };
51
52 static struct bench mem_benchmarks[] = {
53         { "memcpy",     "Benchmark for memcpy() functions",             bench_mem_memcpy        },
54         { "memset",     "Benchmark for memset() functions",             bench_mem_memset        },
55         { "all",        "Run all memory access benchmarks",             NULL                    },
56         { NULL,         NULL,                                           NULL                    }
57 };
58
59 static struct bench futex_benchmarks[] = {
60         { "hash",       "Benchmark for futex hash table",               bench_futex_hash        },
61         { "wake",       "Benchmark for futex wake calls",               bench_futex_wake        },
62         { "wake-parallel", "Benchmark for parallel futex wake calls",   bench_futex_wake_parallel },
63         { "requeue",    "Benchmark for futex requeue calls",            bench_futex_requeue     },
64         /* pi-futexes */
65         { "lock-pi",    "Benchmark for futex lock_pi calls",            bench_futex_lock_pi     },
66         { "all",        "Run all futex benchmarks",                     NULL                    },
67         { NULL,         NULL,                                           NULL                    }
68 };
69
70 #ifdef HAVE_EVENTFD
71 static struct bench epoll_benchmarks[] = {
72         { "wait",       "Benchmark epoll concurrent epoll_waits",       bench_epoll_wait        },
73         { "ctl",        "Benchmark epoll concurrent epoll_ctls",        bench_epoll_ctl         },
74         { "all",        "Run all futex benchmarks",                     NULL                    },
75         { NULL,         NULL,                                           NULL                    }
76 };
77 #endif // HAVE_EVENTFD
78
79 static struct bench internals_benchmarks[] = {
80         { "synthesize", "Benchmark perf event synthesis",       bench_synthesize        },
81         { NULL,         NULL,                                   NULL                    }
82 };
83
84 struct collection {
85         const char      *name;
86         const char      *summary;
87         struct bench    *benchmarks;
88 };
89
90 static struct collection collections[] = {
91         { "sched",      "Scheduler and IPC benchmarks",                 sched_benchmarks        },
92         { "mem",        "Memory access benchmarks",                     mem_benchmarks          },
93 #ifdef HAVE_LIBNUMA_SUPPORT
94         { "numa",       "NUMA scheduling and MM benchmarks",            numa_benchmarks         },
95 #endif
96         {"futex",       "Futex stressing benchmarks",                   futex_benchmarks        },
97 #ifdef HAVE_EVENTFD
98         {"epoll",       "Epoll stressing benchmarks",                   epoll_benchmarks        },
99 #endif
100         { "internals",  "Perf-internals benchmarks",                    internals_benchmarks    },
101         { "all",        "All benchmarks",                               NULL                    },
102         { NULL,         NULL,                                           NULL                    }
103 };
104
105 /* Iterate over all benchmark collections: */
106 #define for_each_collection(coll) \
107         for (coll = collections; coll->name; coll++)
108
109 /* Iterate over all benchmarks within a collection: */
110 #define for_each_bench(coll, bench) \
111         for (bench = coll->benchmarks; bench && bench->name; bench++)
112
113 static void dump_benchmarks(struct collection *coll)
114 {
115         struct bench *bench;
116
117         printf("\n        # List of available benchmarks for collection '%s':\n\n", coll->name);
118
119         for_each_bench(coll, bench)
120                 printf("%14s: %s\n", bench->name, bench->summary);
121
122         printf("\n");
123 }
124
125 static const char *bench_format_str;
126
127 /* Output/formatting style, exported to benchmark modules: */
128 int bench_format = BENCH_FORMAT_DEFAULT;
129 unsigned int bench_repeat = 10; /* default number of times to repeat the run */
130
131 static const struct option bench_options[] = {
132         OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"),
133         OPT_UINTEGER('r', "repeat",  &bench_repeat,   "Specify amount of times to repeat the run"),
134         OPT_END()
135 };
136
137 static const char * const bench_usage[] = {
138         "perf bench [<common options>] <collection> <benchmark> [<options>]",
139         NULL
140 };
141
142 static void print_usage(void)
143 {
144         struct collection *coll;
145         int i;
146
147         printf("Usage: \n");
148         for (i = 0; bench_usage[i]; i++)
149                 printf("\t%s\n", bench_usage[i]);
150         printf("\n");
151
152         printf("        # List of all available benchmark collections:\n\n");
153
154         for_each_collection(coll)
155                 printf("%14s: %s\n", coll->name, coll->summary);
156         printf("\n");
157 }
158
159 static int bench_str2int(const char *str)
160 {
161         if (!str)
162                 return BENCH_FORMAT_DEFAULT;
163
164         if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
165                 return BENCH_FORMAT_DEFAULT;
166         else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
167                 return BENCH_FORMAT_SIMPLE;
168
169         return BENCH_FORMAT_UNKNOWN;
170 }
171
172 /*
173  * Run a specific benchmark but first rename the running task's ->comm[]
174  * to something meaningful:
175  */
176 static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
177                      int argc, const char **argv)
178 {
179         int size;
180         char *name;
181         int ret;
182
183         size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
184
185         name = zalloc(size);
186         BUG_ON(!name);
187
188         scnprintf(name, size, "%s-%s", coll_name, bench_name);
189
190         prctl(PR_SET_NAME, name);
191         argv[0] = name;
192
193         ret = fn(argc, argv);
194
195         free(name);
196
197         return ret;
198 }
199
200 static void run_collection(struct collection *coll)
201 {
202         struct bench *bench;
203         const char *argv[2];
204
205         argv[1] = NULL;
206         /*
207          * TODO:
208          *
209          * Preparing preset parameters for
210          * embedded, ordinary PC, HPC, etc...
211          * would be helpful.
212          */
213         for_each_bench(coll, bench) {
214                 if (!bench->fn)
215                         break;
216                 printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
217                 fflush(stdout);
218
219                 argv[1] = bench->name;
220                 run_bench(coll->name, bench->name, bench->fn, 1, argv);
221                 printf("\n");
222         }
223 }
224
225 static void run_all_collections(void)
226 {
227         struct collection *coll;
228
229         for_each_collection(coll)
230                 run_collection(coll);
231 }
232
233 int cmd_bench(int argc, const char **argv)
234 {
235         struct collection *coll;
236         int ret = 0;
237
238         if (argc < 2) {
239                 /* No collection specified. */
240                 print_usage();
241                 goto end;
242         }
243
244         argc = parse_options(argc, argv, bench_options, bench_usage,
245                              PARSE_OPT_STOP_AT_NON_OPTION);
246
247         bench_format = bench_str2int(bench_format_str);
248         if (bench_format == BENCH_FORMAT_UNKNOWN) {
249                 printf("Unknown format descriptor: '%s'\n", bench_format_str);
250                 goto end;
251         }
252
253         if (bench_repeat == 0) {
254                 printf("Invalid repeat option: Must specify a positive value\n");
255                 goto end;
256         }
257
258         if (argc < 1) {
259                 print_usage();
260                 goto end;
261         }
262
263         if (!strcmp(argv[0], "all")) {
264                 run_all_collections();
265                 goto end;
266         }
267
268         for_each_collection(coll) {
269                 struct bench *bench;
270
271                 if (strcmp(coll->name, argv[0]))
272                         continue;
273
274                 if (argc < 2) {
275                         /* No bench specified. */
276                         dump_benchmarks(coll);
277                         goto end;
278                 }
279
280                 if (!strcmp(argv[1], "all")) {
281                         run_collection(coll);
282                         goto end;
283                 }
284
285                 for_each_bench(coll, bench) {
286                         if (strcmp(bench->name, argv[1]))
287                                 continue;
288
289                         if (bench_format == BENCH_FORMAT_DEFAULT)
290                                 printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
291                         fflush(stdout);
292                         ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
293                         goto end;
294                 }
295
296                 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
297                         dump_benchmarks(coll);
298                         goto end;
299                 }
300
301                 printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
302                 ret = 1;
303                 goto end;
304         }
305
306         printf("Unknown collection: '%s'\n", argv[0]);
307         ret = 1;
308
309 end:
310         return ret;
311 }