xref: /linux/tools/perf/builtin-bench.c (revision 51876bd45263f62083bbb823220bfb48909f313a)
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  */
194b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h>
20629cc356SHitoshi Mitake #include "builtin.h"
21629cc356SHitoshi Mitake #include "bench/bench.h"
22629cc356SHitoshi Mitake 
23629cc356SHitoshi Mitake #include <stdio.h>
24629cc356SHitoshi Mitake #include <stdlib.h>
25629cc356SHitoshi Mitake #include <string.h>
264157922aSIngo Molnar #include <sys/prctl.h>
277f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
28629cc356SHitoshi Mitake 
29b0ad8ea6SArnaldo Carvalho de Melo typedef int (*bench_fn_t)(int argc, const char **argv);
304157922aSIngo Molnar 
314157922aSIngo Molnar struct bench {
32629cc356SHitoshi Mitake 	const char	*name;
33629cc356SHitoshi Mitake 	const char	*summary;
344157922aSIngo Molnar 	bench_fn_t	fn;
35629cc356SHitoshi Mitake };
36629cc356SHitoshi Mitake 
3789fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT
384157922aSIngo Molnar static struct bench numa_benchmarks[] = {
394157922aSIngo Molnar 	{ "mem",	"Benchmark for NUMA workloads",			bench_numa		},
40aa254af2SIngo Molnar 	{ "all",	"Run all NUMA benchmarks",			NULL			},
414157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
421c13f3c9SIngo Molnar };
4379d824e3SPeter Hurley #endif
441c13f3c9SIngo Molnar 
454157922aSIngo Molnar static struct bench sched_benchmarks[] = {
464157922aSIngo Molnar 	{ "messaging",	"Benchmark for scheduling and IPC",		bench_sched_messaging	},
474157922aSIngo Molnar 	{ "pipe",	"Benchmark for pipe() between two processes",	bench_sched_pipe	},
48aa254af2SIngo Molnar 	{ "all",	"Run all scheduler benchmarks",		NULL			},
494157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
50629cc356SHitoshi Mitake };
51629cc356SHitoshi Mitake 
524157922aSIngo Molnar static struct bench mem_benchmarks[] = {
5313b1fdceSIngo Molnar 	{ "memcpy",	"Benchmark for memcpy() functions",		bench_mem_memcpy	},
5413b1fdceSIngo Molnar 	{ "memset",	"Benchmark for memset() functions",		bench_mem_memset	},
55aa254af2SIngo Molnar 	{ "all",	"Run all memory access benchmarks",		NULL			},
564157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
57827f3b49SHitoshi Mitake };
58827f3b49SHitoshi Mitake 
59a0439711SDavidlohr Bueso static struct bench futex_benchmarks[] = {
60a0439711SDavidlohr Bueso 	{ "hash",	"Benchmark for futex hash table",               bench_futex_hash	},
6127db7830SDavidlohr Bueso 	{ "wake",	"Benchmark for futex wake calls",               bench_futex_wake	},
62d65817b4SDavidlohr Bueso 	{ "wake-parallel", "Benchmark for parallel futex wake calls",   bench_futex_wake_parallel },
630fb298cfSDavidlohr Bueso 	{ "requeue",	"Benchmark for futex requeue calls",            bench_futex_requeue	},
64d2f3f5d2SDavidlohr Bueso 	/* pi-futexes */
65d2f3f5d2SDavidlohr Bueso 	{ "lock-pi",	"Benchmark for futex lock_pi calls",            bench_futex_lock_pi	},
66aa254af2SIngo Molnar 	{ "all",	"Run all futex benchmarks",			NULL			},
67a0439711SDavidlohr Bueso 	{ NULL,		NULL,						NULL			}
68a0439711SDavidlohr Bueso };
69a0439711SDavidlohr Bueso 
70121dd9eaSDavidlohr Bueso #ifdef HAVE_EVENTFD
71121dd9eaSDavidlohr Bueso static struct bench epoll_benchmarks[] = {
72121dd9eaSDavidlohr Bueso 	{ "wait",	"Benchmark epoll concurrent epoll_waits",       bench_epoll_wait	},
73231457ecSDavidlohr Bueso 	{ "ctl",	"Benchmark epoll concurrent epoll_ctls",        bench_epoll_ctl		},
74121dd9eaSDavidlohr Bueso 	{ "all",	"Run all futex benchmarks",			NULL			},
75121dd9eaSDavidlohr Bueso 	{ NULL,		NULL,						NULL			}
76121dd9eaSDavidlohr Bueso };
77121dd9eaSDavidlohr Bueso #endif // HAVE_EVENTFD
78121dd9eaSDavidlohr Bueso 
792a4b5166SIan Rogers static struct bench internals_benchmarks[] = {
802a4b5166SIan Rogers 	{ "synthesize", "Benchmark perf event synthesis",	bench_synthesize	},
81*51876bd4SIan Rogers 	{ "kallsyms-parse", "Benchmark kallsyms parsing",	bench_kallsyms_parse	},
822a4b5166SIan Rogers 	{ NULL,		NULL,					NULL			}
832a4b5166SIan Rogers };
842a4b5166SIan Rogers 
854157922aSIngo Molnar struct collection {
86629cc356SHitoshi Mitake 	const char	*name;
87629cc356SHitoshi Mitake 	const char	*summary;
884157922aSIngo Molnar 	struct bench	*benchmarks;
89629cc356SHitoshi Mitake };
90629cc356SHitoshi Mitake 
914157922aSIngo Molnar static struct collection collections[] = {
924157922aSIngo Molnar 	{ "sched",	"Scheduler and IPC benchmarks",			sched_benchmarks	},
934157922aSIngo Molnar 	{ "mem",	"Memory access benchmarks",			mem_benchmarks		},
9489fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT
954157922aSIngo Molnar 	{ "numa",	"NUMA scheduling and MM benchmarks",		numa_benchmarks		},
9679d824e3SPeter Hurley #endif
97a0439711SDavidlohr Bueso 	{"futex",       "Futex stressing benchmarks",                   futex_benchmarks        },
98121dd9eaSDavidlohr Bueso #ifdef HAVE_EVENTFD
99121dd9eaSDavidlohr Bueso 	{"epoll",       "Epoll stressing benchmarks",                   epoll_benchmarks        },
100121dd9eaSDavidlohr Bueso #endif
1012a4b5166SIan Rogers 	{ "internals",	"Perf-internals benchmarks",			internals_benchmarks	},
1024157922aSIngo Molnar 	{ "all",	"All benchmarks",				NULL			},
1034157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
104629cc356SHitoshi Mitake };
105629cc356SHitoshi Mitake 
1064157922aSIngo Molnar /* Iterate over all benchmark collections: */
1074157922aSIngo Molnar #define for_each_collection(coll) \
1084157922aSIngo Molnar 	for (coll = collections; coll->name; coll++)
1094157922aSIngo Molnar 
1104157922aSIngo Molnar /* Iterate over all benchmarks within a collection: */
1114157922aSIngo Molnar #define for_each_bench(coll, bench) \
1126eeefccdSPatrick Palka 	for (bench = coll->benchmarks; bench && bench->name; bench++)
1134157922aSIngo Molnar 
1144157922aSIngo Molnar static void dump_benchmarks(struct collection *coll)
115629cc356SHitoshi Mitake {
1164157922aSIngo Molnar 	struct bench *bench;
117629cc356SHitoshi Mitake 
1184157922aSIngo Molnar 	printf("\n        # List of available benchmarks for collection '%s':\n\n", coll->name);
119629cc356SHitoshi Mitake 
1204157922aSIngo Molnar 	for_each_bench(coll, bench)
1214157922aSIngo Molnar 		printf("%14s: %s\n", bench->name, bench->summary);
122629cc356SHitoshi Mitake 
123629cc356SHitoshi Mitake 	printf("\n");
124629cc356SHitoshi Mitake }
125629cc356SHitoshi Mitake 
126edb7c60eSArnaldo Carvalho de Melo static const char *bench_format_str;
1274157922aSIngo Molnar 
1284157922aSIngo Molnar /* Output/formatting style, exported to benchmark modules: */
129386d7e9eSHitoshi Mitake int bench_format = BENCH_FORMAT_DEFAULT;
130b6f0629aSDavidlohr Bueso unsigned int bench_repeat = 10; /* default number of times to repeat the run */
131629cc356SHitoshi Mitake 
132386d7e9eSHitoshi Mitake static const struct option bench_options[] = {
1337a46a8fdSIngo Molnar 	OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"),
134b6f0629aSDavidlohr Bueso 	OPT_UINTEGER('r', "repeat",  &bench_repeat,   "Specify amount of times to repeat the run"),
135386d7e9eSHitoshi Mitake 	OPT_END()
136386d7e9eSHitoshi Mitake };
137386d7e9eSHitoshi Mitake 
138386d7e9eSHitoshi Mitake static const char * const bench_usage[] = {
1394157922aSIngo Molnar 	"perf bench [<common options>] <collection> <benchmark> [<options>]",
140386d7e9eSHitoshi Mitake 	NULL
141386d7e9eSHitoshi Mitake };
142386d7e9eSHitoshi Mitake 
143386d7e9eSHitoshi Mitake static void print_usage(void)
144386d7e9eSHitoshi Mitake {
1454157922aSIngo Molnar 	struct collection *coll;
146386d7e9eSHitoshi Mitake 	int i;
147386d7e9eSHitoshi Mitake 
148386d7e9eSHitoshi Mitake 	printf("Usage: \n");
149386d7e9eSHitoshi Mitake 	for (i = 0; bench_usage[i]; i++)
150386d7e9eSHitoshi Mitake 		printf("\t%s\n", bench_usage[i]);
151386d7e9eSHitoshi Mitake 	printf("\n");
152386d7e9eSHitoshi Mitake 
1534157922aSIngo Molnar 	printf("        # List of all available benchmark collections:\n\n");
154629cc356SHitoshi Mitake 
1554157922aSIngo Molnar 	for_each_collection(coll)
1564157922aSIngo Molnar 		printf("%14s: %s\n", coll->name, coll->summary);
157629cc356SHitoshi Mitake 	printf("\n");
158386d7e9eSHitoshi Mitake }
159629cc356SHitoshi Mitake 
160edb7c60eSArnaldo Carvalho de Melo static int bench_str2int(const char *str)
161386d7e9eSHitoshi Mitake {
162386d7e9eSHitoshi Mitake 	if (!str)
163386d7e9eSHitoshi Mitake 		return BENCH_FORMAT_DEFAULT;
164386d7e9eSHitoshi Mitake 
165386d7e9eSHitoshi Mitake 	if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
166386d7e9eSHitoshi Mitake 		return BENCH_FORMAT_DEFAULT;
167386d7e9eSHitoshi Mitake 	else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
168386d7e9eSHitoshi Mitake 		return BENCH_FORMAT_SIMPLE;
169386d7e9eSHitoshi Mitake 
170386d7e9eSHitoshi Mitake 	return BENCH_FORMAT_UNKNOWN;
171386d7e9eSHitoshi Mitake }
172386d7e9eSHitoshi Mitake 
1734157922aSIngo Molnar /*
1744157922aSIngo Molnar  * Run a specific benchmark but first rename the running task's ->comm[]
1754157922aSIngo Molnar  * to something meaningful:
1764157922aSIngo Molnar  */
1774157922aSIngo Molnar static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
178b0ad8ea6SArnaldo Carvalho de Melo 		     int argc, const char **argv)
1792044279dSHitoshi Mitake {
1804157922aSIngo Molnar 	int size;
1814157922aSIngo Molnar 	char *name;
1824157922aSIngo Molnar 	int ret;
1834157922aSIngo Molnar 
1844157922aSIngo Molnar 	size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
1854157922aSIngo Molnar 
1864157922aSIngo Molnar 	name = zalloc(size);
1874157922aSIngo Molnar 	BUG_ON(!name);
1884157922aSIngo Molnar 
1894157922aSIngo Molnar 	scnprintf(name, size, "%s-%s", coll_name, bench_name);
1904157922aSIngo Molnar 
1914157922aSIngo Molnar 	prctl(PR_SET_NAME, name);
1924157922aSIngo Molnar 	argv[0] = name;
1934157922aSIngo Molnar 
194b0ad8ea6SArnaldo Carvalho de Melo 	ret = fn(argc, argv);
1954157922aSIngo Molnar 
1964157922aSIngo Molnar 	free(name);
1974157922aSIngo Molnar 
1984157922aSIngo Molnar 	return ret;
1994157922aSIngo Molnar }
2004157922aSIngo Molnar 
2014157922aSIngo Molnar static void run_collection(struct collection *coll)
2024157922aSIngo Molnar {
2034157922aSIngo Molnar 	struct bench *bench;
2042044279dSHitoshi Mitake 	const char *argv[2];
2052044279dSHitoshi Mitake 
2062044279dSHitoshi Mitake 	argv[1] = NULL;
2072044279dSHitoshi Mitake 	/*
2082044279dSHitoshi Mitake 	 * TODO:
2094157922aSIngo Molnar 	 *
2104157922aSIngo Molnar 	 * Preparing preset parameters for
2112044279dSHitoshi Mitake 	 * embedded, ordinary PC, HPC, etc...
2124157922aSIngo Molnar 	 * would be helpful.
2132044279dSHitoshi Mitake 	 */
2144157922aSIngo Molnar 	for_each_bench(coll, bench) {
2154157922aSIngo Molnar 		if (!bench->fn)
2164157922aSIngo Molnar 			break;
2174157922aSIngo Molnar 		printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
2189b494ea2SNamhyung Kim 		fflush(stdout);
2192044279dSHitoshi Mitake 
2204157922aSIngo Molnar 		argv[1] = bench->name;
221b0ad8ea6SArnaldo Carvalho de Melo 		run_bench(coll->name, bench->name, bench->fn, 1, argv);
2222044279dSHitoshi Mitake 		printf("\n");
2232044279dSHitoshi Mitake 	}
2242044279dSHitoshi Mitake }
2252044279dSHitoshi Mitake 
2264157922aSIngo Molnar static void run_all_collections(void)
2272044279dSHitoshi Mitake {
2284157922aSIngo Molnar 	struct collection *coll;
2294157922aSIngo Molnar 
2304157922aSIngo Molnar 	for_each_collection(coll)
2314157922aSIngo Molnar 		run_collection(coll);
2322044279dSHitoshi Mitake }
2332044279dSHitoshi Mitake 
234b0ad8ea6SArnaldo Carvalho de Melo int cmd_bench(int argc, const char **argv)
235386d7e9eSHitoshi Mitake {
2364157922aSIngo Molnar 	struct collection *coll;
2374157922aSIngo Molnar 	int ret = 0;
238386d7e9eSHitoshi Mitake 
239386d7e9eSHitoshi Mitake 	if (argc < 2) {
2404157922aSIngo Molnar 		/* No collection specified. */
241386d7e9eSHitoshi Mitake 		print_usage();
242386d7e9eSHitoshi Mitake 		goto end;
243386d7e9eSHitoshi Mitake 	}
244386d7e9eSHitoshi Mitake 
245386d7e9eSHitoshi Mitake 	argc = parse_options(argc, argv, bench_options, bench_usage,
246386d7e9eSHitoshi Mitake 			     PARSE_OPT_STOP_AT_NON_OPTION);
247386d7e9eSHitoshi Mitake 
248386d7e9eSHitoshi Mitake 	bench_format = bench_str2int(bench_format_str);
249386d7e9eSHitoshi Mitake 	if (bench_format == BENCH_FORMAT_UNKNOWN) {
2504157922aSIngo Molnar 		printf("Unknown format descriptor: '%s'\n", bench_format_str);
251386d7e9eSHitoshi Mitake 		goto end;
252386d7e9eSHitoshi Mitake 	}
253386d7e9eSHitoshi Mitake 
254b6f0629aSDavidlohr Bueso 	if (bench_repeat == 0) {
255b6f0629aSDavidlohr Bueso 		printf("Invalid repeat option: Must specify a positive value\n");
256b6f0629aSDavidlohr Bueso 		goto end;
257b6f0629aSDavidlohr Bueso 	}
258b6f0629aSDavidlohr Bueso 
259386d7e9eSHitoshi Mitake 	if (argc < 1) {
260386d7e9eSHitoshi Mitake 		print_usage();
261629cc356SHitoshi Mitake 		goto end;
262629cc356SHitoshi Mitake 	}
263629cc356SHitoshi Mitake 
2642044279dSHitoshi Mitake 	if (!strcmp(argv[0], "all")) {
2654157922aSIngo Molnar 		run_all_collections();
2662044279dSHitoshi Mitake 		goto end;
2672044279dSHitoshi Mitake 	}
2682044279dSHitoshi Mitake 
2694157922aSIngo Molnar 	for_each_collection(coll) {
2704157922aSIngo Molnar 		struct bench *bench;
2714157922aSIngo Molnar 
2724157922aSIngo Molnar 		if (strcmp(coll->name, argv[0]))
273629cc356SHitoshi Mitake 			continue;
274629cc356SHitoshi Mitake 
275386d7e9eSHitoshi Mitake 		if (argc < 2) {
2764157922aSIngo Molnar 			/* No bench specified. */
2774157922aSIngo Molnar 			dump_benchmarks(coll);
278629cc356SHitoshi Mitake 			goto end;
279629cc356SHitoshi Mitake 		}
280629cc356SHitoshi Mitake 
2812044279dSHitoshi Mitake 		if (!strcmp(argv[1], "all")) {
2824157922aSIngo Molnar 			run_collection(coll);
2832044279dSHitoshi Mitake 			goto end;
2842044279dSHitoshi Mitake 		}
2852044279dSHitoshi Mitake 
2864157922aSIngo Molnar 		for_each_bench(coll, bench) {
2874157922aSIngo Molnar 			if (strcmp(bench->name, argv[1]))
288629cc356SHitoshi Mitake 				continue;
289629cc356SHitoshi Mitake 
29079e295d4SHitoshi Mitake 			if (bench_format == BENCH_FORMAT_DEFAULT)
2914157922aSIngo Molnar 				printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
2929b494ea2SNamhyung Kim 			fflush(stdout);
293b0ad8ea6SArnaldo Carvalho de Melo 			ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
294629cc356SHitoshi Mitake 			goto end;
295629cc356SHitoshi Mitake 		}
296629cc356SHitoshi Mitake 
297386d7e9eSHitoshi Mitake 		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
2984157922aSIngo Molnar 			dump_benchmarks(coll);
299629cc356SHitoshi Mitake 			goto end;
300629cc356SHitoshi Mitake 		}
301629cc356SHitoshi Mitake 
3024157922aSIngo Molnar 		printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
3034157922aSIngo Molnar 		ret = 1;
304629cc356SHitoshi Mitake 		goto end;
305629cc356SHitoshi Mitake 	}
306629cc356SHitoshi Mitake 
3074157922aSIngo Molnar 	printf("Unknown collection: '%s'\n", argv[0]);
3084157922aSIngo Molnar 	ret = 1;
309629cc356SHitoshi Mitake 
310629cc356SHitoshi Mitake end:
3114157922aSIngo Molnar 	return ret;
312629cc356SHitoshi Mitake }
313