xref: /linux/tools/perf/builtin-bench.c (revision 16203e9cd01896b4244100a8e3fb9f6e612ab2b1)
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
14c2a08203SDavidlohr Bueso  *  syscall ... System call performance
15827f3b49SHitoshi Mitake  *  mem   ... memory access performance
164157922aSIngo Molnar  *  numa  ... NUMA scheduling and MM performance
17a0439711SDavidlohr Bueso  *  futex ... Futex performance
18121dd9eaSDavidlohr Bueso  *  epoll ... Event poll performance
19629cc356SHitoshi Mitake  */
204b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h>
21629cc356SHitoshi Mitake #include "builtin.h"
22629cc356SHitoshi Mitake #include "bench/bench.h"
23629cc356SHitoshi Mitake 
24*16203e9cSArnaldo Carvalho de Melo #include <locale.h>
25629cc356SHitoshi Mitake #include <stdio.h>
26629cc356SHitoshi Mitake #include <stdlib.h>
27629cc356SHitoshi Mitake #include <string.h>
284157922aSIngo Molnar #include <sys/prctl.h>
297f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
30629cc356SHitoshi Mitake 
31b0ad8ea6SArnaldo Carvalho de Melo typedef int (*bench_fn_t)(int argc, const char **argv);
324157922aSIngo Molnar 
334157922aSIngo Molnar struct bench {
34629cc356SHitoshi Mitake 	const char	*name;
35629cc356SHitoshi Mitake 	const char	*summary;
364157922aSIngo Molnar 	bench_fn_t	fn;
37629cc356SHitoshi Mitake };
38629cc356SHitoshi Mitake 
3989fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT
404157922aSIngo Molnar static struct bench numa_benchmarks[] = {
414157922aSIngo Molnar 	{ "mem",	"Benchmark for NUMA workloads",			bench_numa		},
42aa254af2SIngo Molnar 	{ "all",	"Run all NUMA benchmarks",			NULL			},
434157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
441c13f3c9SIngo Molnar };
4579d824e3SPeter Hurley #endif
461c13f3c9SIngo Molnar 
474157922aSIngo Molnar static struct bench sched_benchmarks[] = {
484157922aSIngo Molnar 	{ "messaging",	"Benchmark for scheduling and IPC",		bench_sched_messaging	},
494157922aSIngo Molnar 	{ "pipe",	"Benchmark for pipe() between two processes",	bench_sched_pipe	},
50aa254af2SIngo Molnar 	{ "all",	"Run all scheduler benchmarks",		NULL			},
514157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
52629cc356SHitoshi Mitake };
53629cc356SHitoshi Mitake 
54c2a08203SDavidlohr Bueso static struct bench syscall_benchmarks[] = {
55c2a08203SDavidlohr Bueso 	{ "basic",	"Benchmark for basic getppid(2) calls",		bench_syscall_basic	},
56391f84e5STiezhu Yang 	{ "getpgid",	"Benchmark for getpgid(2) calls",		bench_syscall_getpgid	},
57ece7f7c0STiezhu Yang 	{ "fork",	"Benchmark for fork(2) calls",			bench_syscall_fork	},
58540f8b56STiezhu Yang 	{ "execve",	"Benchmark for execve(2) calls",		bench_syscall_execve	},
59c2a08203SDavidlohr Bueso 	{ "all",	"Run all syscall benchmarks",			NULL			},
60c2a08203SDavidlohr Bueso 	{ NULL,		NULL,						NULL			},
61c2a08203SDavidlohr Bueso };
62c2a08203SDavidlohr Bueso 
634157922aSIngo Molnar static struct bench mem_benchmarks[] = {
6413b1fdceSIngo Molnar 	{ "memcpy",	"Benchmark for memcpy() functions",		bench_mem_memcpy	},
6513b1fdceSIngo Molnar 	{ "memset",	"Benchmark for memset() functions",		bench_mem_memset	},
667c43b0c1SIan Rogers 	{ "find_bit",	"Benchmark for find_bit() functions",		bench_mem_find_bit	},
67aa254af2SIngo Molnar 	{ "all",	"Run all memory access benchmarks",		NULL			},
684157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
69827f3b49SHitoshi Mitake };
70827f3b49SHitoshi Mitake 
71a0439711SDavidlohr Bueso static struct bench futex_benchmarks[] = {
72a0439711SDavidlohr Bueso 	{ "hash",	"Benchmark for futex hash table",               bench_futex_hash	},
7327db7830SDavidlohr Bueso 	{ "wake",	"Benchmark for futex wake calls",               bench_futex_wake	},
74d65817b4SDavidlohr Bueso 	{ "wake-parallel", "Benchmark for parallel futex wake calls",   bench_futex_wake_parallel },
750fb298cfSDavidlohr Bueso 	{ "requeue",	"Benchmark for futex requeue calls",            bench_futex_requeue	},
76d2f3f5d2SDavidlohr Bueso 	/* pi-futexes */
77d2f3f5d2SDavidlohr Bueso 	{ "lock-pi",	"Benchmark for futex lock_pi calls",            bench_futex_lock_pi	},
78aa254af2SIngo Molnar 	{ "all",	"Run all futex benchmarks",			NULL			},
79a0439711SDavidlohr Bueso 	{ NULL,		NULL,						NULL			}
80a0439711SDavidlohr Bueso };
81a0439711SDavidlohr Bueso 
82ba35fe93SArnaldo Carvalho de Melo #ifdef HAVE_EVENTFD_SUPPORT
83121dd9eaSDavidlohr Bueso static struct bench epoll_benchmarks[] = {
84121dd9eaSDavidlohr Bueso 	{ "wait",	"Benchmark epoll concurrent epoll_waits",       bench_epoll_wait	},
85231457ecSDavidlohr Bueso 	{ "ctl",	"Benchmark epoll concurrent epoll_ctls",        bench_epoll_ctl		},
86121dd9eaSDavidlohr Bueso 	{ "all",	"Run all futex benchmarks",			NULL			},
87121dd9eaSDavidlohr Bueso 	{ NULL,		NULL,						NULL			}
88121dd9eaSDavidlohr Bueso };
89ba35fe93SArnaldo Carvalho de Melo #endif // HAVE_EVENTFD_SUPPORT
90121dd9eaSDavidlohr Bueso 
912a4b5166SIan Rogers static struct bench internals_benchmarks[] = {
922a4b5166SIan Rogers 	{ "synthesize", "Benchmark perf event synthesis",	bench_synthesize	},
9351876bd4SIan Rogers 	{ "kallsyms-parse", "Benchmark kallsyms parsing",	bench_kallsyms_parse	},
940bf02a0dSNamhyung Kim 	{ "inject-build-id", "Benchmark build-id injection",	bench_inject_build_id	},
954241eabfSRiccardo Mancini 	{ "evlist-open-close", "Benchmark evlist open and close",	bench_evlist_open_close	},
96f6a7bbbfSNamhyung Kim 	{ "pmu-scan", "Benchmark sysfs PMU info scanning",	bench_pmu_scan		},
972a4b5166SIan Rogers 	{ NULL,		NULL,					NULL			}
982a4b5166SIan Rogers };
992a4b5166SIan Rogers 
10068a6772fSDmitry Vyukov static struct bench breakpoint_benchmarks[] = {
10168a6772fSDmitry Vyukov 	{ "thread", "Benchmark thread start/finish with breakpoints", bench_breakpoint_thread},
10268a6772fSDmitry Vyukov 	{ "enable", "Benchmark breakpoint enable/disable", bench_breakpoint_enable},
10368a6772fSDmitry Vyukov 	{ "all", "Run all breakpoint benchmarks", NULL},
10468a6772fSDmitry Vyukov 	{ NULL,	NULL, NULL },
10568a6772fSDmitry Vyukov };
10668a6772fSDmitry Vyukov 
1074157922aSIngo Molnar struct collection {
108629cc356SHitoshi Mitake 	const char	*name;
109629cc356SHitoshi Mitake 	const char	*summary;
1104157922aSIngo Molnar 	struct bench	*benchmarks;
111629cc356SHitoshi Mitake };
112629cc356SHitoshi Mitake 
1134157922aSIngo Molnar static struct collection collections[] = {
1144157922aSIngo Molnar 	{ "sched",	"Scheduler and IPC benchmarks",			sched_benchmarks	},
115c2a08203SDavidlohr Bueso 	{ "syscall",	"System call benchmarks",			syscall_benchmarks	},
1164157922aSIngo Molnar 	{ "mem",	"Memory access benchmarks",			mem_benchmarks		},
11789fe808aSIngo Molnar #ifdef HAVE_LIBNUMA_SUPPORT
1184157922aSIngo Molnar 	{ "numa",	"NUMA scheduling and MM benchmarks",		numa_benchmarks		},
11979d824e3SPeter Hurley #endif
120a0439711SDavidlohr Bueso 	{"futex",       "Futex stressing benchmarks",                   futex_benchmarks        },
121ba35fe93SArnaldo Carvalho de Melo #ifdef HAVE_EVENTFD_SUPPORT
122121dd9eaSDavidlohr Bueso 	{"epoll",       "Epoll stressing benchmarks",                   epoll_benchmarks        },
123121dd9eaSDavidlohr Bueso #endif
1242a4b5166SIan Rogers 	{ "internals",	"Perf-internals benchmarks",			internals_benchmarks	},
12568a6772fSDmitry Vyukov 	{ "breakpoint",	"Breakpoint benchmarks",			breakpoint_benchmarks	},
1264157922aSIngo Molnar 	{ "all",	"All benchmarks",				NULL			},
1274157922aSIngo Molnar 	{ NULL,		NULL,						NULL			}
128629cc356SHitoshi Mitake };
129629cc356SHitoshi Mitake 
1304157922aSIngo Molnar /* Iterate over all benchmark collections: */
1314157922aSIngo Molnar #define for_each_collection(coll) \
1324157922aSIngo Molnar 	for (coll = collections; coll->name; coll++)
1334157922aSIngo Molnar 
1344157922aSIngo Molnar /* Iterate over all benchmarks within a collection: */
1354157922aSIngo Molnar #define for_each_bench(coll, bench) \
1366eeefccdSPatrick Palka 	for (bench = coll->benchmarks; bench && bench->name; bench++)
1374157922aSIngo Molnar 
1384157922aSIngo Molnar static void dump_benchmarks(struct collection *coll)
139629cc356SHitoshi Mitake {
1404157922aSIngo Molnar 	struct bench *bench;
141629cc356SHitoshi Mitake 
1424157922aSIngo Molnar 	printf("\n        # List of available benchmarks for collection '%s':\n\n", coll->name);
143629cc356SHitoshi Mitake 
1444157922aSIngo Molnar 	for_each_bench(coll, bench)
1454157922aSIngo Molnar 		printf("%14s: %s\n", bench->name, bench->summary);
146629cc356SHitoshi Mitake 
147629cc356SHitoshi Mitake 	printf("\n");
148629cc356SHitoshi Mitake }
149629cc356SHitoshi Mitake 
150edb7c60eSArnaldo Carvalho de Melo static const char *bench_format_str;
1514157922aSIngo Molnar 
1524157922aSIngo Molnar /* Output/formatting style, exported to benchmark modules: */
153386d7e9eSHitoshi Mitake int bench_format = BENCH_FORMAT_DEFAULT;
154b6f0629aSDavidlohr Bueso unsigned int bench_repeat = 10; /* default number of times to repeat the run */
155629cc356SHitoshi Mitake 
156386d7e9eSHitoshi Mitake static const struct option bench_options[] = {
1577a46a8fdSIngo Molnar 	OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"),
158fc5d836cSDiederik de Haas 	OPT_UINTEGER('r', "repeat",  &bench_repeat,   "Specify number of times to repeat the run"),
159386d7e9eSHitoshi Mitake 	OPT_END()
160386d7e9eSHitoshi Mitake };
161386d7e9eSHitoshi Mitake 
162386d7e9eSHitoshi Mitake static const char * const bench_usage[] = {
1634157922aSIngo Molnar 	"perf bench [<common options>] <collection> <benchmark> [<options>]",
164386d7e9eSHitoshi Mitake 	NULL
165386d7e9eSHitoshi Mitake };
166386d7e9eSHitoshi Mitake 
167386d7e9eSHitoshi Mitake static void print_usage(void)
168386d7e9eSHitoshi Mitake {
1694157922aSIngo Molnar 	struct collection *coll;
170386d7e9eSHitoshi Mitake 	int i;
171386d7e9eSHitoshi Mitake 
172386d7e9eSHitoshi Mitake 	printf("Usage: \n");
173386d7e9eSHitoshi Mitake 	for (i = 0; bench_usage[i]; i++)
174386d7e9eSHitoshi Mitake 		printf("\t%s\n", bench_usage[i]);
175386d7e9eSHitoshi Mitake 	printf("\n");
176386d7e9eSHitoshi Mitake 
1774157922aSIngo Molnar 	printf("        # List of all available benchmark collections:\n\n");
178629cc356SHitoshi Mitake 
1794157922aSIngo Molnar 	for_each_collection(coll)
1804157922aSIngo Molnar 		printf("%14s: %s\n", coll->name, coll->summary);
181629cc356SHitoshi Mitake 	printf("\n");
182386d7e9eSHitoshi Mitake }
183629cc356SHitoshi Mitake 
184edb7c60eSArnaldo Carvalho de Melo static int bench_str2int(const char *str)
185386d7e9eSHitoshi Mitake {
186386d7e9eSHitoshi Mitake 	if (!str)
187386d7e9eSHitoshi Mitake 		return BENCH_FORMAT_DEFAULT;
188386d7e9eSHitoshi Mitake 
189386d7e9eSHitoshi Mitake 	if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
190386d7e9eSHitoshi Mitake 		return BENCH_FORMAT_DEFAULT;
191386d7e9eSHitoshi Mitake 	else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
192386d7e9eSHitoshi Mitake 		return BENCH_FORMAT_SIMPLE;
193386d7e9eSHitoshi Mitake 
194386d7e9eSHitoshi Mitake 	return BENCH_FORMAT_UNKNOWN;
195386d7e9eSHitoshi Mitake }
196386d7e9eSHitoshi Mitake 
1974157922aSIngo Molnar /*
1984157922aSIngo Molnar  * Run a specific benchmark but first rename the running task's ->comm[]
1994157922aSIngo Molnar  * to something meaningful:
2004157922aSIngo Molnar  */
2014157922aSIngo Molnar static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
202b0ad8ea6SArnaldo Carvalho de Melo 		     int argc, const char **argv)
2032044279dSHitoshi Mitake {
2044157922aSIngo Molnar 	int size;
2054157922aSIngo Molnar 	char *name;
2064157922aSIngo Molnar 	int ret;
2074157922aSIngo Molnar 
2084157922aSIngo Molnar 	size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
2094157922aSIngo Molnar 
2104157922aSIngo Molnar 	name = zalloc(size);
2114157922aSIngo Molnar 	BUG_ON(!name);
2124157922aSIngo Molnar 
2134157922aSIngo Molnar 	scnprintf(name, size, "%s-%s", coll_name, bench_name);
2144157922aSIngo Molnar 
2154157922aSIngo Molnar 	prctl(PR_SET_NAME, name);
2164157922aSIngo Molnar 	argv[0] = name;
2174157922aSIngo Molnar 
218b0ad8ea6SArnaldo Carvalho de Melo 	ret = fn(argc, argv);
2194157922aSIngo Molnar 
2204157922aSIngo Molnar 	free(name);
2214157922aSIngo Molnar 
2224157922aSIngo Molnar 	return ret;
2234157922aSIngo Molnar }
2244157922aSIngo Molnar 
2254157922aSIngo Molnar static void run_collection(struct collection *coll)
2264157922aSIngo Molnar {
2274157922aSIngo Molnar 	struct bench *bench;
2282044279dSHitoshi Mitake 	const char *argv[2];
2292044279dSHitoshi Mitake 
2302044279dSHitoshi Mitake 	argv[1] = NULL;
2312044279dSHitoshi Mitake 	/*
2322044279dSHitoshi Mitake 	 * TODO:
2334157922aSIngo Molnar 	 *
2344157922aSIngo Molnar 	 * Preparing preset parameters for
2352044279dSHitoshi Mitake 	 * embedded, ordinary PC, HPC, etc...
2364157922aSIngo Molnar 	 * would be helpful.
2372044279dSHitoshi Mitake 	 */
2384157922aSIngo Molnar 	for_each_bench(coll, bench) {
2394157922aSIngo Molnar 		if (!bench->fn)
2404157922aSIngo Molnar 			break;
2414157922aSIngo Molnar 		printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
2422044279dSHitoshi Mitake 
2434157922aSIngo Molnar 		argv[1] = bench->name;
244b0ad8ea6SArnaldo Carvalho de Melo 		run_bench(coll->name, bench->name, bench->fn, 1, argv);
2452044279dSHitoshi Mitake 		printf("\n");
2462044279dSHitoshi Mitake 	}
2472044279dSHitoshi Mitake }
2482044279dSHitoshi Mitake 
2494157922aSIngo Molnar static void run_all_collections(void)
2502044279dSHitoshi Mitake {
2514157922aSIngo Molnar 	struct collection *coll;
2524157922aSIngo Molnar 
2534157922aSIngo Molnar 	for_each_collection(coll)
2544157922aSIngo Molnar 		run_collection(coll);
2552044279dSHitoshi Mitake }
2562044279dSHitoshi Mitake 
257b0ad8ea6SArnaldo Carvalho de Melo int cmd_bench(int argc, const char **argv)
258386d7e9eSHitoshi Mitake {
2594157922aSIngo Molnar 	struct collection *coll;
2604157922aSIngo Molnar 	int ret = 0;
261386d7e9eSHitoshi Mitake 
262f0a29c96SSohaib Mohamed 	/* Unbuffered output */
263f0a29c96SSohaib Mohamed 	setvbuf(stdout, NULL, _IONBF, 0);
264*16203e9cSArnaldo Carvalho de Melo 	setlocale(LC_ALL, "");
265f0a29c96SSohaib Mohamed 
266386d7e9eSHitoshi Mitake 	if (argc < 2) {
2674157922aSIngo Molnar 		/* No collection specified. */
268386d7e9eSHitoshi Mitake 		print_usage();
269386d7e9eSHitoshi Mitake 		goto end;
270386d7e9eSHitoshi Mitake 	}
271386d7e9eSHitoshi Mitake 
272386d7e9eSHitoshi Mitake 	argc = parse_options(argc, argv, bench_options, bench_usage,
273386d7e9eSHitoshi Mitake 			     PARSE_OPT_STOP_AT_NON_OPTION);
274386d7e9eSHitoshi Mitake 
275386d7e9eSHitoshi Mitake 	bench_format = bench_str2int(bench_format_str);
276386d7e9eSHitoshi Mitake 	if (bench_format == BENCH_FORMAT_UNKNOWN) {
2774157922aSIngo Molnar 		printf("Unknown format descriptor: '%s'\n", bench_format_str);
278386d7e9eSHitoshi Mitake 		goto end;
279386d7e9eSHitoshi Mitake 	}
280386d7e9eSHitoshi Mitake 
281b6f0629aSDavidlohr Bueso 	if (bench_repeat == 0) {
282b6f0629aSDavidlohr Bueso 		printf("Invalid repeat option: Must specify a positive value\n");
283b6f0629aSDavidlohr Bueso 		goto end;
284b6f0629aSDavidlohr Bueso 	}
285b6f0629aSDavidlohr Bueso 
286386d7e9eSHitoshi Mitake 	if (argc < 1) {
287386d7e9eSHitoshi Mitake 		print_usage();
288629cc356SHitoshi Mitake 		goto end;
289629cc356SHitoshi Mitake 	}
290629cc356SHitoshi Mitake 
2912044279dSHitoshi Mitake 	if (!strcmp(argv[0], "all")) {
2924157922aSIngo Molnar 		run_all_collections();
2932044279dSHitoshi Mitake 		goto end;
2942044279dSHitoshi Mitake 	}
2952044279dSHitoshi Mitake 
2964157922aSIngo Molnar 	for_each_collection(coll) {
2974157922aSIngo Molnar 		struct bench *bench;
2984157922aSIngo Molnar 
2994157922aSIngo Molnar 		if (strcmp(coll->name, argv[0]))
300629cc356SHitoshi Mitake 			continue;
301629cc356SHitoshi Mitake 
302386d7e9eSHitoshi Mitake 		if (argc < 2) {
3034157922aSIngo Molnar 			/* No bench specified. */
3044157922aSIngo Molnar 			dump_benchmarks(coll);
305629cc356SHitoshi Mitake 			goto end;
306629cc356SHitoshi Mitake 		}
307629cc356SHitoshi Mitake 
3082044279dSHitoshi Mitake 		if (!strcmp(argv[1], "all")) {
3094157922aSIngo Molnar 			run_collection(coll);
3102044279dSHitoshi Mitake 			goto end;
3112044279dSHitoshi Mitake 		}
3122044279dSHitoshi Mitake 
3134157922aSIngo Molnar 		for_each_bench(coll, bench) {
3144157922aSIngo Molnar 			if (strcmp(bench->name, argv[1]))
315629cc356SHitoshi Mitake 				continue;
316629cc356SHitoshi Mitake 
31779e295d4SHitoshi Mitake 			if (bench_format == BENCH_FORMAT_DEFAULT)
3184157922aSIngo Molnar 				printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
319b0ad8ea6SArnaldo Carvalho de Melo 			ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
320629cc356SHitoshi Mitake 			goto end;
321629cc356SHitoshi Mitake 		}
322629cc356SHitoshi Mitake 
323386d7e9eSHitoshi Mitake 		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
3244157922aSIngo Molnar 			dump_benchmarks(coll);
325629cc356SHitoshi Mitake 			goto end;
326629cc356SHitoshi Mitake 		}
327629cc356SHitoshi Mitake 
3284157922aSIngo Molnar 		printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
3294157922aSIngo Molnar 		ret = 1;
330629cc356SHitoshi Mitake 		goto end;
331629cc356SHitoshi Mitake 	}
332629cc356SHitoshi Mitake 
3334157922aSIngo Molnar 	printf("Unknown collection: '%s'\n", argv[0]);
3344157922aSIngo Molnar 	ret = 1;
335629cc356SHitoshi Mitake 
336629cc356SHitoshi Mitake end:
3374157922aSIngo Molnar 	return ret;
338629cc356SHitoshi Mitake }
339