xref: /linux/tools/perf/builtin-bench.c (revision 231457ec707475c71d4e538a3253f1ed9e294cf0)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2629cc356SHitoshi Mitake /*
3629cc356SHitoshi Mitake  * builtin-bench.c
4629cc356SHitoshi Mitake  *
54157922aSIngo Molnar  * General benchmarking collections provided by perf
6629cc356SHitoshi Mitake  *
7629cc356SHitoshi Mitake  * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
8629cc356SHitoshi Mitake  */
9629cc356SHitoshi Mitake 
10629cc356SHitoshi Mitake /*
114157922aSIngo Molnar  * Available benchmark collection list:
12629cc356SHitoshi Mitake  *
134157922aSIngo Molnar  *  sched ... scheduler and IPC performance
14827f3b49SHitoshi Mitake  *  mem   ... memory access performance
154157922aSIngo Molnar  *  numa  ... NUMA scheduling and MM performance
16a0439711SDavidlohr Bueso  *  futex ... Futex performance
17121dd9eaSDavidlohr Bueso  *  epoll ... Event poll performance
18629cc356SHitoshi Mitake  */
19629cc356SHitoshi Mitake #include "perf.h"
20629cc356SHitoshi Mitake #include "util/util.h"
214b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h>
22629cc356SHitoshi Mitake #include "builtin.h"
23629cc356SHitoshi Mitake #include "bench/bench.h"
24629cc356SHitoshi Mitake 
25629cc356SHitoshi Mitake #include <stdio.h>
26629cc356SHitoshi Mitake #include <stdlib.h>
27629cc356SHitoshi Mitake #include <string.h>
284157922aSIngo Molnar #include <sys/prctl.h>
29629cc356SHitoshi Mitake 
30b0ad8ea6SArnaldo Carvalho de Melo typedef int (*bench_fn_t)(int argc, const char **argv);
314157922aSIngo Molnar 
324157922aSIngo Molnar struct bench {
33629cc356SHitoshi Mitake 	const char	*name;
34629cc356SHitoshi Mitake 	const char	*summary;
354157922aSIngo Molnar 	bench_fn_t	fn;
36629cc356SHitoshi Mitake };
37629cc356SHitoshi Mitake 
3889fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT
394157922aSIngo Molnar static struct bench numa_benchmarks[] = {
404157922aSIngo Molnar 	{ "mem",	"Benchmark for NUMA workloads",			bench_numa		},
41aa254af2SIngo Molnar 	{ "all",	"Run all NUMA benchmarks",			NULL			},
424157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
431c13f3c9SIngo Molnar };
4479d824e3SPeter Hurley #endif
451c13f3c9SIngo Molnar 
464157922aSIngo Molnar static struct bench sched_benchmarks[] = {
474157922aSIngo Molnar 	{ "messaging",	"Benchmark for scheduling and IPC",		bench_sched_messaging	},
484157922aSIngo Molnar 	{ "pipe",	"Benchmark for pipe() between two processes",	bench_sched_pipe	},
49aa254af2SIngo Molnar 	{ "all",	"Run all scheduler benchmarks",		NULL			},
504157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
51629cc356SHitoshi Mitake };
52629cc356SHitoshi Mitake 
534157922aSIngo Molnar static struct bench mem_benchmarks[] = {
5413b1fdceSIngo Molnar 	{ "memcpy",	"Benchmark for memcpy() functions",		bench_mem_memcpy	},
5513b1fdceSIngo Molnar 	{ "memset",	"Benchmark for memset() functions",		bench_mem_memset	},
56aa254af2SIngo Molnar 	{ "all",	"Run all memory access benchmarks",		NULL			},
574157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
58827f3b49SHitoshi Mitake };
59827f3b49SHitoshi Mitake 
60a0439711SDavidlohr Bueso static struct bench futex_benchmarks[] = {
61a0439711SDavidlohr Bueso 	{ "hash",	"Benchmark for futex hash table",               bench_futex_hash	},
6227db7830SDavidlohr Bueso 	{ "wake",	"Benchmark for futex wake calls",               bench_futex_wake	},
63d65817b4SDavidlohr Bueso 	{ "wake-parallel", "Benchmark for parallel futex wake calls",   bench_futex_wake_parallel },
640fb298cfSDavidlohr Bueso 	{ "requeue",	"Benchmark for futex requeue calls",            bench_futex_requeue	},
65d2f3f5d2SDavidlohr Bueso 	/* pi-futexes */
66d2f3f5d2SDavidlohr Bueso 	{ "lock-pi",	"Benchmark for futex lock_pi calls",            bench_futex_lock_pi	},
67aa254af2SIngo Molnar 	{ "all",	"Run all futex benchmarks",			NULL			},
68a0439711SDavidlohr Bueso 	{ NULL,		NULL,						NULL			}
69a0439711SDavidlohr Bueso };
70a0439711SDavidlohr Bueso 
71121dd9eaSDavidlohr Bueso #ifdef HAVE_EVENTFD
72121dd9eaSDavidlohr Bueso static struct bench epoll_benchmarks[] = {
73121dd9eaSDavidlohr Bueso 	{ "wait",	"Benchmark epoll concurrent epoll_waits",       bench_epoll_wait	},
74*231457ecSDavidlohr Bueso 	{ "ctl",	"Benchmark epoll concurrent epoll_ctls",        bench_epoll_ctl		},
75121dd9eaSDavidlohr Bueso 	{ "all",	"Run all futex benchmarks",			NULL			},
76121dd9eaSDavidlohr Bueso 	{ NULL,		NULL,						NULL			}
77121dd9eaSDavidlohr Bueso };
78121dd9eaSDavidlohr Bueso #endif // HAVE_EVENTFD
79121dd9eaSDavidlohr Bueso 
804157922aSIngo Molnar struct collection {
81629cc356SHitoshi Mitake 	const char	*name;
82629cc356SHitoshi Mitake 	const char	*summary;
834157922aSIngo Molnar 	struct bench	*benchmarks;
84629cc356SHitoshi Mitake };
85629cc356SHitoshi Mitake 
864157922aSIngo Molnar static struct collection collections[] = {
874157922aSIngo Molnar 	{ "sched",	"Scheduler and IPC benchmarks",			sched_benchmarks	},
884157922aSIngo Molnar 	{ "mem",	"Memory access benchmarks",			mem_benchmarks		},
8989fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT
904157922aSIngo Molnar 	{ "numa",	"NUMA scheduling and MM benchmarks",		numa_benchmarks		},
9179d824e3SPeter Hurley #endif
92a0439711SDavidlohr Bueso 	{"futex",       "Futex stressing benchmarks",                   futex_benchmarks        },
93121dd9eaSDavidlohr Bueso #ifdef HAVE_EVENTFD
94121dd9eaSDavidlohr Bueso 	{"epoll",       "Epoll stressing benchmarks",                   epoll_benchmarks        },
95121dd9eaSDavidlohr Bueso #endif
964157922aSIngo Molnar 	{ "all",	"All benchmarks",				NULL			},
974157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
98629cc356SHitoshi Mitake };
99629cc356SHitoshi Mitake 
1004157922aSIngo Molnar /* Iterate over all benchmark collections: */
1014157922aSIngo Molnar #define for_each_collection(coll) \
1024157922aSIngo Molnar 	for (coll = collections; coll->name; coll++)
1034157922aSIngo Molnar 
1044157922aSIngo Molnar /* Iterate over all benchmarks within a collection: */
1054157922aSIngo Molnar #define for_each_bench(coll, bench) \
1066eeefccdSPatrick Palka 	for (bench = coll->benchmarks; bench && bench->name; bench++)
1074157922aSIngo Molnar 
1084157922aSIngo Molnar static void dump_benchmarks(struct collection *coll)
109629cc356SHitoshi Mitake {
1104157922aSIngo Molnar 	struct bench *bench;
111629cc356SHitoshi Mitake 
1124157922aSIngo Molnar 	printf("\n        # List of available benchmarks for collection '%s':\n\n", coll->name);
113629cc356SHitoshi Mitake 
1144157922aSIngo Molnar 	for_each_bench(coll, bench)
1154157922aSIngo Molnar 		printf("%14s: %s\n", bench->name, bench->summary);
116629cc356SHitoshi Mitake 
117629cc356SHitoshi Mitake 	printf("\n");
118629cc356SHitoshi Mitake }
119629cc356SHitoshi Mitake 
120edb7c60eSArnaldo Carvalho de Melo static const char *bench_format_str;
1214157922aSIngo Molnar 
1224157922aSIngo Molnar /* Output/formatting style, exported to benchmark modules: */
123386d7e9eSHitoshi Mitake int bench_format = BENCH_FORMAT_DEFAULT;
124b6f0629aSDavidlohr Bueso unsigned int bench_repeat = 10; /* default number of times to repeat the run */
125629cc356SHitoshi Mitake 
126386d7e9eSHitoshi Mitake static const struct option bench_options[] = {
1277a46a8fdSIngo Molnar 	OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"),
128b6f0629aSDavidlohr Bueso 	OPT_UINTEGER('r', "repeat",  &bench_repeat,   "Specify amount of times to repeat the run"),
129386d7e9eSHitoshi Mitake 	OPT_END()
130386d7e9eSHitoshi Mitake };
131386d7e9eSHitoshi Mitake 
132386d7e9eSHitoshi Mitake static const char * const bench_usage[] = {
1334157922aSIngo Molnar 	"perf bench [<common options>] <collection> <benchmark> [<options>]",
134386d7e9eSHitoshi Mitake 	NULL
135386d7e9eSHitoshi Mitake };
136386d7e9eSHitoshi Mitake 
137386d7e9eSHitoshi Mitake static void print_usage(void)
138386d7e9eSHitoshi Mitake {
1394157922aSIngo Molnar 	struct collection *coll;
140386d7e9eSHitoshi Mitake 	int i;
141386d7e9eSHitoshi Mitake 
142386d7e9eSHitoshi Mitake 	printf("Usage: \n");
143386d7e9eSHitoshi Mitake 	for (i = 0; bench_usage[i]; i++)
144386d7e9eSHitoshi Mitake 		printf("\t%s\n", bench_usage[i]);
145386d7e9eSHitoshi Mitake 	printf("\n");
146386d7e9eSHitoshi Mitake 
1474157922aSIngo Molnar 	printf("        # List of all available benchmark collections:\n\n");
148629cc356SHitoshi Mitake 
1494157922aSIngo Molnar 	for_each_collection(coll)
1504157922aSIngo Molnar 		printf("%14s: %s\n", coll->name, coll->summary);
151629cc356SHitoshi Mitake 	printf("\n");
152386d7e9eSHitoshi Mitake }
153629cc356SHitoshi Mitake 
154edb7c60eSArnaldo Carvalho de Melo static int bench_str2int(const char *str)
155386d7e9eSHitoshi Mitake {
156386d7e9eSHitoshi Mitake 	if (!str)
157386d7e9eSHitoshi Mitake 		return BENCH_FORMAT_DEFAULT;
158386d7e9eSHitoshi Mitake 
159386d7e9eSHitoshi Mitake 	if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
160386d7e9eSHitoshi Mitake 		return BENCH_FORMAT_DEFAULT;
161386d7e9eSHitoshi Mitake 	else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
162386d7e9eSHitoshi Mitake 		return BENCH_FORMAT_SIMPLE;
163386d7e9eSHitoshi Mitake 
164386d7e9eSHitoshi Mitake 	return BENCH_FORMAT_UNKNOWN;
165386d7e9eSHitoshi Mitake }
166386d7e9eSHitoshi Mitake 
1674157922aSIngo Molnar /*
1684157922aSIngo Molnar  * Run a specific benchmark but first rename the running task's ->comm[]
1694157922aSIngo Molnar  * to something meaningful:
1704157922aSIngo Molnar  */
1714157922aSIngo Molnar static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
172b0ad8ea6SArnaldo Carvalho de Melo 		     int argc, const char **argv)
1732044279dSHitoshi Mitake {
1744157922aSIngo Molnar 	int size;
1754157922aSIngo Molnar 	char *name;
1764157922aSIngo Molnar 	int ret;
1774157922aSIngo Molnar 
1784157922aSIngo Molnar 	size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
1794157922aSIngo Molnar 
1804157922aSIngo Molnar 	name = zalloc(size);
1814157922aSIngo Molnar 	BUG_ON(!name);
1824157922aSIngo Molnar 
1834157922aSIngo Molnar 	scnprintf(name, size, "%s-%s", coll_name, bench_name);
1844157922aSIngo Molnar 
1854157922aSIngo Molnar 	prctl(PR_SET_NAME, name);
1864157922aSIngo Molnar 	argv[0] = name;
1874157922aSIngo Molnar 
188b0ad8ea6SArnaldo Carvalho de Melo 	ret = fn(argc, argv);
1894157922aSIngo Molnar 
1904157922aSIngo Molnar 	free(name);
1914157922aSIngo Molnar 
1924157922aSIngo Molnar 	return ret;
1934157922aSIngo Molnar }
1944157922aSIngo Molnar 
1954157922aSIngo Molnar static void run_collection(struct collection *coll)
1964157922aSIngo Molnar {
1974157922aSIngo Molnar 	struct bench *bench;
1982044279dSHitoshi Mitake 	const char *argv[2];
1992044279dSHitoshi Mitake 
2002044279dSHitoshi Mitake 	argv[1] = NULL;
2012044279dSHitoshi Mitake 	/*
2022044279dSHitoshi Mitake 	 * TODO:
2034157922aSIngo Molnar 	 *
2044157922aSIngo Molnar 	 * Preparing preset parameters for
2052044279dSHitoshi Mitake 	 * embedded, ordinary PC, HPC, etc...
2064157922aSIngo Molnar 	 * would be helpful.
2072044279dSHitoshi Mitake 	 */
2084157922aSIngo Molnar 	for_each_bench(coll, bench) {
2094157922aSIngo Molnar 		if (!bench->fn)
2104157922aSIngo Molnar 			break;
2114157922aSIngo Molnar 		printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
2129b494ea2SNamhyung Kim 		fflush(stdout);
2132044279dSHitoshi Mitake 
2144157922aSIngo Molnar 		argv[1] = bench->name;
215b0ad8ea6SArnaldo Carvalho de Melo 		run_bench(coll->name, bench->name, bench->fn, 1, argv);
2162044279dSHitoshi Mitake 		printf("\n");
2172044279dSHitoshi Mitake 	}
2182044279dSHitoshi Mitake }
2192044279dSHitoshi Mitake 
2204157922aSIngo Molnar static void run_all_collections(void)
2212044279dSHitoshi Mitake {
2224157922aSIngo Molnar 	struct collection *coll;
2234157922aSIngo Molnar 
2244157922aSIngo Molnar 	for_each_collection(coll)
2254157922aSIngo Molnar 		run_collection(coll);
2262044279dSHitoshi Mitake }
2272044279dSHitoshi Mitake 
228b0ad8ea6SArnaldo Carvalho de Melo int cmd_bench(int argc, const char **argv)
229386d7e9eSHitoshi Mitake {
2304157922aSIngo Molnar 	struct collection *coll;
2314157922aSIngo Molnar 	int ret = 0;
232386d7e9eSHitoshi Mitake 
233386d7e9eSHitoshi Mitake 	if (argc < 2) {
2344157922aSIngo Molnar 		/* No collection specified. */
235386d7e9eSHitoshi Mitake 		print_usage();
236386d7e9eSHitoshi Mitake 		goto end;
237386d7e9eSHitoshi Mitake 	}
238386d7e9eSHitoshi Mitake 
239386d7e9eSHitoshi Mitake 	argc = parse_options(argc, argv, bench_options, bench_usage,
240386d7e9eSHitoshi Mitake 			     PARSE_OPT_STOP_AT_NON_OPTION);
241386d7e9eSHitoshi Mitake 
242386d7e9eSHitoshi Mitake 	bench_format = bench_str2int(bench_format_str);
243386d7e9eSHitoshi Mitake 	if (bench_format == BENCH_FORMAT_UNKNOWN) {
2444157922aSIngo Molnar 		printf("Unknown format descriptor: '%s'\n", bench_format_str);
245386d7e9eSHitoshi Mitake 		goto end;
246386d7e9eSHitoshi Mitake 	}
247386d7e9eSHitoshi Mitake 
248b6f0629aSDavidlohr Bueso 	if (bench_repeat == 0) {
249b6f0629aSDavidlohr Bueso 		printf("Invalid repeat option: Must specify a positive value\n");
250b6f0629aSDavidlohr Bueso 		goto end;
251b6f0629aSDavidlohr Bueso 	}
252b6f0629aSDavidlohr Bueso 
253386d7e9eSHitoshi Mitake 	if (argc < 1) {
254386d7e9eSHitoshi Mitake 		print_usage();
255629cc356SHitoshi Mitake 		goto end;
256629cc356SHitoshi Mitake 	}
257629cc356SHitoshi Mitake 
2582044279dSHitoshi Mitake 	if (!strcmp(argv[0], "all")) {
2594157922aSIngo Molnar 		run_all_collections();
2602044279dSHitoshi Mitake 		goto end;
2612044279dSHitoshi Mitake 	}
2622044279dSHitoshi Mitake 
2634157922aSIngo Molnar 	for_each_collection(coll) {
2644157922aSIngo Molnar 		struct bench *bench;
2654157922aSIngo Molnar 
2664157922aSIngo Molnar 		if (strcmp(coll->name, argv[0]))
267629cc356SHitoshi Mitake 			continue;
268629cc356SHitoshi Mitake 
269386d7e9eSHitoshi Mitake 		if (argc < 2) {
2704157922aSIngo Molnar 			/* No bench specified. */
2714157922aSIngo Molnar 			dump_benchmarks(coll);
272629cc356SHitoshi Mitake 			goto end;
273629cc356SHitoshi Mitake 		}
274629cc356SHitoshi Mitake 
2752044279dSHitoshi Mitake 		if (!strcmp(argv[1], "all")) {
2764157922aSIngo Molnar 			run_collection(coll);
2772044279dSHitoshi Mitake 			goto end;
2782044279dSHitoshi Mitake 		}
2792044279dSHitoshi Mitake 
2804157922aSIngo Molnar 		for_each_bench(coll, bench) {
2814157922aSIngo Molnar 			if (strcmp(bench->name, argv[1]))
282629cc356SHitoshi Mitake 				continue;
283629cc356SHitoshi Mitake 
28479e295d4SHitoshi Mitake 			if (bench_format == BENCH_FORMAT_DEFAULT)
2854157922aSIngo Molnar 				printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
2869b494ea2SNamhyung Kim 			fflush(stdout);
287b0ad8ea6SArnaldo Carvalho de Melo 			ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
288629cc356SHitoshi Mitake 			goto end;
289629cc356SHitoshi Mitake 		}
290629cc356SHitoshi Mitake 
291386d7e9eSHitoshi Mitake 		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
2924157922aSIngo Molnar 			dump_benchmarks(coll);
293629cc356SHitoshi Mitake 			goto end;
294629cc356SHitoshi Mitake 		}
295629cc356SHitoshi Mitake 
2964157922aSIngo Molnar 		printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
2974157922aSIngo Molnar 		ret = 1;
298629cc356SHitoshi Mitake 		goto end;
299629cc356SHitoshi Mitake 	}
300629cc356SHitoshi Mitake 
3014157922aSIngo Molnar 	printf("Unknown collection: '%s'\n", argv[0]);
3024157922aSIngo Molnar 	ret = 1;
303629cc356SHitoshi Mitake 
304629cc356SHitoshi Mitake end:
3054157922aSIngo Molnar 	return ret;
306629cc356SHitoshi Mitake }
307