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