162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * perf.c
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Performance analysis utility.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This is the main hub from which the sub-commands (perf stat,
762306a36Sopenharmony_ci * perf top, perf record, perf report, etc.) are started.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include "builtin.h"
1062306a36Sopenharmony_ci#include "perf.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "util/build-id.h"
1362306a36Sopenharmony_ci#include "util/cache.h"
1462306a36Sopenharmony_ci#include "util/env.h"
1562306a36Sopenharmony_ci#include <internal/lib.h> // page_size
1662306a36Sopenharmony_ci#include <subcmd/exec-cmd.h>
1762306a36Sopenharmony_ci#include "util/config.h"
1862306a36Sopenharmony_ci#include <subcmd/run-command.h>
1962306a36Sopenharmony_ci#include "util/parse-events.h"
2062306a36Sopenharmony_ci#include <subcmd/parse-options.h>
2162306a36Sopenharmony_ci#include "util/debug.h"
2262306a36Sopenharmony_ci#include "util/event.h"
2362306a36Sopenharmony_ci#include "util/util.h" // usage()
2462306a36Sopenharmony_ci#include "ui/ui.h"
2562306a36Sopenharmony_ci#include "perf-sys.h"
2662306a36Sopenharmony_ci#include <api/fs/fs.h>
2762306a36Sopenharmony_ci#include <api/fs/tracing_path.h>
2862306a36Sopenharmony_ci#include <perf/core.h>
2962306a36Sopenharmony_ci#include <errno.h>
3062306a36Sopenharmony_ci#include <pthread.h>
3162306a36Sopenharmony_ci#include <signal.h>
3262306a36Sopenharmony_ci#include <stdlib.h>
3362306a36Sopenharmony_ci#include <time.h>
3462306a36Sopenharmony_ci#include <sys/types.h>
3562306a36Sopenharmony_ci#include <sys/stat.h>
3662306a36Sopenharmony_ci#include <unistd.h>
3762306a36Sopenharmony_ci#include <linux/kernel.h>
3862306a36Sopenharmony_ci#include <linux/string.h>
3962306a36Sopenharmony_ci#include <linux/zalloc.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic int use_pager = -1;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct cmd_struct {
4462306a36Sopenharmony_ci	const char *cmd;
4562306a36Sopenharmony_ci	int (*fn)(int, const char **);
4662306a36Sopenharmony_ci	int option;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct cmd_struct commands[] = {
5062306a36Sopenharmony_ci	{ "archive",	NULL,	0 },
5162306a36Sopenharmony_ci	{ "buildid-cache", cmd_buildid_cache, 0 },
5262306a36Sopenharmony_ci	{ "buildid-list", cmd_buildid_list, 0 },
5362306a36Sopenharmony_ci	{ "config",	cmd_config,	0 },
5462306a36Sopenharmony_ci	{ "c2c",	cmd_c2c,	0 },
5562306a36Sopenharmony_ci	{ "diff",	cmd_diff,	0 },
5662306a36Sopenharmony_ci	{ "evlist",	cmd_evlist,	0 },
5762306a36Sopenharmony_ci	{ "help",	cmd_help,	0 },
5862306a36Sopenharmony_ci	{ "iostat",	NULL,	0 },
5962306a36Sopenharmony_ci	{ "kallsyms",	cmd_kallsyms,	0 },
6062306a36Sopenharmony_ci	{ "list",	cmd_list,	0 },
6162306a36Sopenharmony_ci	{ "record",	cmd_record,	0 },
6262306a36Sopenharmony_ci	{ "report",	cmd_report,	0 },
6362306a36Sopenharmony_ci	{ "bench",	cmd_bench,	0 },
6462306a36Sopenharmony_ci	{ "stat",	cmd_stat,	0 },
6562306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
6662306a36Sopenharmony_ci	{ "timechart",	cmd_timechart,	0 },
6762306a36Sopenharmony_ci#endif
6862306a36Sopenharmony_ci	{ "top",	cmd_top,	0 },
6962306a36Sopenharmony_ci	{ "annotate",	cmd_annotate,	0 },
7062306a36Sopenharmony_ci	{ "version",	cmd_version,	0 },
7162306a36Sopenharmony_ci	{ "script",	cmd_script,	0 },
7262306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
7362306a36Sopenharmony_ci	{ "sched",	cmd_sched,	0 },
7462306a36Sopenharmony_ci#endif
7562306a36Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT
7662306a36Sopenharmony_ci	{ "probe",	cmd_probe,	0 },
7762306a36Sopenharmony_ci#endif
7862306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
7962306a36Sopenharmony_ci	{ "kmem",	cmd_kmem,	0 },
8062306a36Sopenharmony_ci	{ "lock",	cmd_lock,	0 },
8162306a36Sopenharmony_ci#endif
8262306a36Sopenharmony_ci	{ "kvm",	cmd_kvm,	0 },
8362306a36Sopenharmony_ci	{ "test",	cmd_test,	0 },
8462306a36Sopenharmony_ci#if defined(HAVE_LIBTRACEEVENT) && (defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT))
8562306a36Sopenharmony_ci	{ "trace",	cmd_trace,	0 },
8662306a36Sopenharmony_ci#endif
8762306a36Sopenharmony_ci	{ "inject",	cmd_inject,	0 },
8862306a36Sopenharmony_ci	{ "mem",	cmd_mem,	0 },
8962306a36Sopenharmony_ci	{ "data",	cmd_data,	0 },
9062306a36Sopenharmony_ci	{ "ftrace",	cmd_ftrace,	0 },
9162306a36Sopenharmony_ci	{ "daemon",	cmd_daemon,	0 },
9262306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
9362306a36Sopenharmony_ci	{ "kwork",	cmd_kwork,	0 },
9462306a36Sopenharmony_ci#endif
9562306a36Sopenharmony_ci};
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistruct pager_config {
9862306a36Sopenharmony_ci	const char *cmd;
9962306a36Sopenharmony_ci	int val;
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic bool same_cmd_with_prefix(const char *var, struct pager_config *c,
10362306a36Sopenharmony_ci				  const char *header)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	return (strstarts(var, header) && !strcmp(var + strlen(header), c->cmd));
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic int pager_command_config(const char *var, const char *value, void *data)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct pager_config *c = data;
11162306a36Sopenharmony_ci	if (same_cmd_with_prefix(var, c, "pager."))
11262306a36Sopenharmony_ci		c->val = perf_config_bool(var, value);
11362306a36Sopenharmony_ci	return 0;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
11762306a36Sopenharmony_cistatic int check_pager_config(const char *cmd)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	int err;
12062306a36Sopenharmony_ci	struct pager_config c;
12162306a36Sopenharmony_ci	c.cmd = cmd;
12262306a36Sopenharmony_ci	c.val = -1;
12362306a36Sopenharmony_ci	err = perf_config(pager_command_config, &c);
12462306a36Sopenharmony_ci	return err ?: c.val;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int browser_command_config(const char *var, const char *value, void *data)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct pager_config *c = data;
13062306a36Sopenharmony_ci	if (same_cmd_with_prefix(var, c, "tui."))
13162306a36Sopenharmony_ci		c->val = perf_config_bool(var, value);
13262306a36Sopenharmony_ci	if (same_cmd_with_prefix(var, c, "gtk."))
13362306a36Sopenharmony_ci		c->val = perf_config_bool(var, value) ? 2 : 0;
13462306a36Sopenharmony_ci	return 0;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*
13862306a36Sopenharmony_ci * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk",
13962306a36Sopenharmony_ci * and -1 for "not specified"
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_cistatic int check_browser_config(const char *cmd)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	int err;
14462306a36Sopenharmony_ci	struct pager_config c;
14562306a36Sopenharmony_ci	c.cmd = cmd;
14662306a36Sopenharmony_ci	c.val = -1;
14762306a36Sopenharmony_ci	err = perf_config(browser_command_config, &c);
14862306a36Sopenharmony_ci	return err ?: c.val;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void commit_pager_choice(void)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	switch (use_pager) {
15462306a36Sopenharmony_ci	case 0:
15562306a36Sopenharmony_ci		setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
15662306a36Sopenharmony_ci		break;
15762306a36Sopenharmony_ci	case 1:
15862306a36Sopenharmony_ci		/* setup_pager(); */
15962306a36Sopenharmony_ci		break;
16062306a36Sopenharmony_ci	default:
16162306a36Sopenharmony_ci		break;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistruct option options[] = {
16662306a36Sopenharmony_ci	OPT_ARGUMENT("help", "help"),
16762306a36Sopenharmony_ci	OPT_ARGUMENT("version", "version"),
16862306a36Sopenharmony_ci	OPT_ARGUMENT("exec-path", "exec-path"),
16962306a36Sopenharmony_ci	OPT_ARGUMENT("html-path", "html-path"),
17062306a36Sopenharmony_ci	OPT_ARGUMENT("paginate", "paginate"),
17162306a36Sopenharmony_ci	OPT_ARGUMENT("no-pager", "no-pager"),
17262306a36Sopenharmony_ci	OPT_ARGUMENT("debugfs-dir", "debugfs-dir"),
17362306a36Sopenharmony_ci	OPT_ARGUMENT("buildid-dir", "buildid-dir"),
17462306a36Sopenharmony_ci	OPT_ARGUMENT("list-cmds", "list-cmds"),
17562306a36Sopenharmony_ci	OPT_ARGUMENT("list-opts", "list-opts"),
17662306a36Sopenharmony_ci	OPT_ARGUMENT("debug", "debug"),
17762306a36Sopenharmony_ci	OPT_END()
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic int handle_options(const char ***argv, int *argc, int *envchanged)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	int handled = 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	while (*argc > 0) {
18562306a36Sopenharmony_ci		const char *cmd = (*argv)[0];
18662306a36Sopenharmony_ci		if (cmd[0] != '-')
18762306a36Sopenharmony_ci			break;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		/*
19062306a36Sopenharmony_ci		 * For legacy reasons, the "version" and "help"
19162306a36Sopenharmony_ci		 * commands can be written with "--" prepended
19262306a36Sopenharmony_ci		 * to make them look like flags.
19362306a36Sopenharmony_ci		 */
19462306a36Sopenharmony_ci		if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
19562306a36Sopenharmony_ci			break;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		/*
19862306a36Sopenharmony_ci		 * Shortcut for '-h' and '-v' options to invoke help
19962306a36Sopenharmony_ci		 * and version command.
20062306a36Sopenharmony_ci		 */
20162306a36Sopenharmony_ci		if (!strcmp(cmd, "-h")) {
20262306a36Sopenharmony_ci			(*argv)[0] = "--help";
20362306a36Sopenharmony_ci			break;
20462306a36Sopenharmony_ci		}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		if (!strcmp(cmd, "-v")) {
20762306a36Sopenharmony_ci			(*argv)[0] = "--version";
20862306a36Sopenharmony_ci			break;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		if (!strcmp(cmd, "-vv")) {
21262306a36Sopenharmony_ci			(*argv)[0] = "version";
21362306a36Sopenharmony_ci			verbose = 1;
21462306a36Sopenharmony_ci			break;
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		/*
21862306a36Sopenharmony_ci		 * Check remaining flags.
21962306a36Sopenharmony_ci		 */
22062306a36Sopenharmony_ci		if (strstarts(cmd, CMD_EXEC_PATH)) {
22162306a36Sopenharmony_ci			cmd += strlen(CMD_EXEC_PATH);
22262306a36Sopenharmony_ci			if (*cmd == '=')
22362306a36Sopenharmony_ci				set_argv_exec_path(cmd + 1);
22462306a36Sopenharmony_ci			else {
22562306a36Sopenharmony_ci				puts(get_argv_exec_path());
22662306a36Sopenharmony_ci				exit(0);
22762306a36Sopenharmony_ci			}
22862306a36Sopenharmony_ci		} else if (!strcmp(cmd, "--html-path")) {
22962306a36Sopenharmony_ci			puts(system_path(PERF_HTML_PATH));
23062306a36Sopenharmony_ci			exit(0);
23162306a36Sopenharmony_ci		} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
23262306a36Sopenharmony_ci			use_pager = 1;
23362306a36Sopenharmony_ci		} else if (!strcmp(cmd, "--no-pager")) {
23462306a36Sopenharmony_ci			use_pager = 0;
23562306a36Sopenharmony_ci			if (envchanged)
23662306a36Sopenharmony_ci				*envchanged = 1;
23762306a36Sopenharmony_ci		} else if (!strcmp(cmd, "--debugfs-dir")) {
23862306a36Sopenharmony_ci			if (*argc < 2) {
23962306a36Sopenharmony_ci				fprintf(stderr, "No directory given for --debugfs-dir.\n");
24062306a36Sopenharmony_ci				usage(perf_usage_string);
24162306a36Sopenharmony_ci			}
24262306a36Sopenharmony_ci			tracing_path_set((*argv)[1]);
24362306a36Sopenharmony_ci			if (envchanged)
24462306a36Sopenharmony_ci				*envchanged = 1;
24562306a36Sopenharmony_ci			(*argv)++;
24662306a36Sopenharmony_ci			(*argc)--;
24762306a36Sopenharmony_ci		} else if (!strcmp(cmd, "--buildid-dir")) {
24862306a36Sopenharmony_ci			if (*argc < 2) {
24962306a36Sopenharmony_ci				fprintf(stderr, "No directory given for --buildid-dir.\n");
25062306a36Sopenharmony_ci				usage(perf_usage_string);
25162306a36Sopenharmony_ci			}
25262306a36Sopenharmony_ci			set_buildid_dir((*argv)[1]);
25362306a36Sopenharmony_ci			if (envchanged)
25462306a36Sopenharmony_ci				*envchanged = 1;
25562306a36Sopenharmony_ci			(*argv)++;
25662306a36Sopenharmony_ci			(*argc)--;
25762306a36Sopenharmony_ci		} else if (strstarts(cmd, CMD_DEBUGFS_DIR)) {
25862306a36Sopenharmony_ci			tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR));
25962306a36Sopenharmony_ci			fprintf(stderr, "dir: %s\n", tracing_path_mount());
26062306a36Sopenharmony_ci			if (envchanged)
26162306a36Sopenharmony_ci				*envchanged = 1;
26262306a36Sopenharmony_ci		} else if (!strcmp(cmd, "--list-cmds")) {
26362306a36Sopenharmony_ci			unsigned int i;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(commands); i++) {
26662306a36Sopenharmony_ci				struct cmd_struct *p = commands+i;
26762306a36Sopenharmony_ci				printf("%s ", p->cmd);
26862306a36Sopenharmony_ci			}
26962306a36Sopenharmony_ci			putchar('\n');
27062306a36Sopenharmony_ci			exit(0);
27162306a36Sopenharmony_ci		} else if (!strcmp(cmd, "--list-opts")) {
27262306a36Sopenharmony_ci			unsigned int i;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(options)-1; i++) {
27562306a36Sopenharmony_ci				struct option *p = options+i;
27662306a36Sopenharmony_ci				printf("--%s ", p->long_name);
27762306a36Sopenharmony_ci			}
27862306a36Sopenharmony_ci			putchar('\n');
27962306a36Sopenharmony_ci			exit(0);
28062306a36Sopenharmony_ci		} else if (!strcmp(cmd, "--debug")) {
28162306a36Sopenharmony_ci			if (*argc < 2) {
28262306a36Sopenharmony_ci				fprintf(stderr, "No variable specified for --debug.\n");
28362306a36Sopenharmony_ci				usage(perf_usage_string);
28462306a36Sopenharmony_ci			}
28562306a36Sopenharmony_ci			if (perf_debug_option((*argv)[1]))
28662306a36Sopenharmony_ci				usage(perf_usage_string);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci			(*argv)++;
28962306a36Sopenharmony_ci			(*argc)--;
29062306a36Sopenharmony_ci		} else {
29162306a36Sopenharmony_ci			fprintf(stderr, "Unknown option: %s\n", cmd);
29262306a36Sopenharmony_ci			usage(perf_usage_string);
29362306a36Sopenharmony_ci		}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		(*argv)++;
29662306a36Sopenharmony_ci		(*argc)--;
29762306a36Sopenharmony_ci		handled++;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci	return handled;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci#define RUN_SETUP	(1<<0)
30362306a36Sopenharmony_ci#define USE_PAGER	(1<<1)
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic int run_builtin(struct cmd_struct *p, int argc, const char **argv)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	int status;
30862306a36Sopenharmony_ci	struct stat st;
30962306a36Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (use_browser == -1)
31262306a36Sopenharmony_ci		use_browser = check_browser_config(p->cmd);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (use_pager == -1 && p->option & RUN_SETUP)
31562306a36Sopenharmony_ci		use_pager = check_pager_config(p->cmd);
31662306a36Sopenharmony_ci	if (use_pager == -1 && p->option & USE_PAGER)
31762306a36Sopenharmony_ci		use_pager = 1;
31862306a36Sopenharmony_ci	commit_pager_choice();
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	perf_env__init(&perf_env);
32162306a36Sopenharmony_ci	perf_env__set_cmdline(&perf_env, argc, argv);
32262306a36Sopenharmony_ci	status = p->fn(argc, argv);
32362306a36Sopenharmony_ci	perf_config__exit();
32462306a36Sopenharmony_ci	exit_browser(status);
32562306a36Sopenharmony_ci	perf_env__exit(&perf_env);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (status)
32862306a36Sopenharmony_ci		return status & 0xff;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Somebody closed stdout? */
33162306a36Sopenharmony_ci	if (fstat(fileno(stdout), &st))
33262306a36Sopenharmony_ci		return 0;
33362306a36Sopenharmony_ci	/* Ignore write errors for pipes and sockets.. */
33462306a36Sopenharmony_ci	if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
33562306a36Sopenharmony_ci		return 0;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	status = 1;
33862306a36Sopenharmony_ci	/* Check for ENOSPC and EIO errors.. */
33962306a36Sopenharmony_ci	if (fflush(stdout)) {
34062306a36Sopenharmony_ci		fprintf(stderr, "write failure on standard output: %s",
34162306a36Sopenharmony_ci			str_error_r(errno, sbuf, sizeof(sbuf)));
34262306a36Sopenharmony_ci		goto out;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	if (ferror(stdout)) {
34562306a36Sopenharmony_ci		fprintf(stderr, "unknown write failure on standard output");
34662306a36Sopenharmony_ci		goto out;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci	if (fclose(stdout)) {
34962306a36Sopenharmony_ci		fprintf(stderr, "close failed on standard output: %s",
35062306a36Sopenharmony_ci			str_error_r(errno, sbuf, sizeof(sbuf)));
35162306a36Sopenharmony_ci		goto out;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci	status = 0;
35462306a36Sopenharmony_ciout:
35562306a36Sopenharmony_ci	return status;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic void handle_internal_command(int argc, const char **argv)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	const char *cmd = argv[0];
36162306a36Sopenharmony_ci	unsigned int i;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* Turn "perf cmd --help" into "perf help cmd" */
36462306a36Sopenharmony_ci	if (argc > 1 && !strcmp(argv[1], "--help")) {
36562306a36Sopenharmony_ci		argv[1] = argv[0];
36662306a36Sopenharmony_ci		argv[0] = cmd = "help";
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(commands); i++) {
37062306a36Sopenharmony_ci		struct cmd_struct *p = commands+i;
37162306a36Sopenharmony_ci		if (p->fn == NULL)
37262306a36Sopenharmony_ci			continue;
37362306a36Sopenharmony_ci		if (strcmp(p->cmd, cmd))
37462306a36Sopenharmony_ci			continue;
37562306a36Sopenharmony_ci		exit(run_builtin(p, argc, argv));
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic void execv_dashed_external(const char **argv)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	char *cmd;
38262306a36Sopenharmony_ci	const char *tmp;
38362306a36Sopenharmony_ci	int status;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
38662306a36Sopenharmony_ci		goto do_die;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/*
38962306a36Sopenharmony_ci	 * argv[0] must be the perf command, but the argv array
39062306a36Sopenharmony_ci	 * belongs to the caller, and may be reused in
39162306a36Sopenharmony_ci	 * subsequent loop iterations. Save argv[0] and
39262306a36Sopenharmony_ci	 * restore it on error.
39362306a36Sopenharmony_ci	 */
39462306a36Sopenharmony_ci	tmp = argv[0];
39562306a36Sopenharmony_ci	argv[0] = cmd;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/*
39862306a36Sopenharmony_ci	 * if we fail because the command is not found, it is
39962306a36Sopenharmony_ci	 * OK to return. Otherwise, we just pass along the status code.
40062306a36Sopenharmony_ci	 */
40162306a36Sopenharmony_ci	status = run_command_v_opt(argv, 0);
40262306a36Sopenharmony_ci	if (status != -ERR_RUN_COMMAND_EXEC) {
40362306a36Sopenharmony_ci		if (IS_RUN_COMMAND_ERR(status)) {
40462306a36Sopenharmony_cido_die:
40562306a36Sopenharmony_ci			pr_err("FATAL: unable to run '%s'", argv[0]);
40662306a36Sopenharmony_ci			status = -128;
40762306a36Sopenharmony_ci		}
40862306a36Sopenharmony_ci		exit(-status);
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci	errno = ENOENT; /* as if we called execvp */
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	argv[0] = tmp;
41362306a36Sopenharmony_ci	zfree(&cmd);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic int run_argv(int *argcp, const char ***argv)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	/* See if it's an internal command */
41962306a36Sopenharmony_ci	handle_internal_command(*argcp, *argv);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/* .. then try the external ones */
42262306a36Sopenharmony_ci	execv_dashed_external(*argv);
42362306a36Sopenharmony_ci	return 0;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic int libperf_print(enum libperf_print_level level,
42762306a36Sopenharmony_ci			 const char *fmt, va_list ap)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	return veprintf(level, verbose, fmt, ap);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ciint main(int argc, const char **argv)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	int err;
43562306a36Sopenharmony_ci	const char *cmd;
43662306a36Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	perf_debug_setup();
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	/* libsubcmd init */
44162306a36Sopenharmony_ci	exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
44262306a36Sopenharmony_ci	pager_init(PERF_PAGER_ENVIRONMENT);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	libperf_init(libperf_print);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	cmd = extract_argv0_path(argv[0]);
44762306a36Sopenharmony_ci	if (!cmd)
44862306a36Sopenharmony_ci		cmd = "perf-help";
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	srandom(time(NULL));
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	/* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
45362306a36Sopenharmony_ci	config_exclusive_filename = getenv("PERF_CONFIG");
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	err = perf_config(perf_default_config, NULL);
45662306a36Sopenharmony_ci	if (err)
45762306a36Sopenharmony_ci		return err;
45862306a36Sopenharmony_ci	set_buildid_dir(NULL);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/*
46162306a36Sopenharmony_ci	 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
46262306a36Sopenharmony_ci	 *
46362306a36Sopenharmony_ci	 *  - cannot take flags in between the "perf" and the "xxxx".
46462306a36Sopenharmony_ci	 *  - cannot execute it externally (since it would just do
46562306a36Sopenharmony_ci	 *    the same thing over again)
46662306a36Sopenharmony_ci	 *
46762306a36Sopenharmony_ci	 * So we just directly call the internal command handler. If that one
46862306a36Sopenharmony_ci	 * fails to handle this, then maybe we just run a renamed perf binary
46962306a36Sopenharmony_ci	 * that contains a dash in its name. To handle this scenario, we just
47062306a36Sopenharmony_ci	 * fall through and ignore the "xxxx" part of the command string.
47162306a36Sopenharmony_ci	 */
47262306a36Sopenharmony_ci	if (strstarts(cmd, "perf-")) {
47362306a36Sopenharmony_ci		cmd += 5;
47462306a36Sopenharmony_ci		argv[0] = cmd;
47562306a36Sopenharmony_ci		handle_internal_command(argc, argv);
47662306a36Sopenharmony_ci		/*
47762306a36Sopenharmony_ci		 * If the command is handled, the above function does not
47862306a36Sopenharmony_ci		 * return undo changes and fall through in such a case.
47962306a36Sopenharmony_ci		 */
48062306a36Sopenharmony_ci		cmd -= 5;
48162306a36Sopenharmony_ci		argv[0] = cmd;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci	if (strstarts(cmd, "trace")) {
48462306a36Sopenharmony_ci#ifndef HAVE_LIBTRACEEVENT
48562306a36Sopenharmony_ci		fprintf(stderr,
48662306a36Sopenharmony_ci			"trace command not available: missing libtraceevent devel package at build time.\n");
48762306a36Sopenharmony_ci		goto out;
48862306a36Sopenharmony_ci#elif !defined(HAVE_LIBAUDIT_SUPPORT) && !defined(HAVE_SYSCALL_TABLE_SUPPORT)
48962306a36Sopenharmony_ci		fprintf(stderr,
49062306a36Sopenharmony_ci			"trace command not available: missing audit-libs devel package at build time.\n");
49162306a36Sopenharmony_ci		goto out;
49262306a36Sopenharmony_ci#else
49362306a36Sopenharmony_ci		setup_path();
49462306a36Sopenharmony_ci		argv[0] = "trace";
49562306a36Sopenharmony_ci		return cmd_trace(argc, argv);
49662306a36Sopenharmony_ci#endif
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci	/* Look for flags.. */
49962306a36Sopenharmony_ci	argv++;
50062306a36Sopenharmony_ci	argc--;
50162306a36Sopenharmony_ci	handle_options(&argv, &argc, NULL);
50262306a36Sopenharmony_ci	commit_pager_choice();
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (argc > 0) {
50562306a36Sopenharmony_ci		if (strstarts(argv[0], "--"))
50662306a36Sopenharmony_ci			argv[0] += 2;
50762306a36Sopenharmony_ci	} else {
50862306a36Sopenharmony_ci		/* The user didn't specify a command; give them help */
50962306a36Sopenharmony_ci		printf("\n usage: %s\n\n", perf_usage_string);
51062306a36Sopenharmony_ci		list_common_cmds_help();
51162306a36Sopenharmony_ci		printf("\n %s\n\n", perf_more_info_string);
51262306a36Sopenharmony_ci		goto out;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci	cmd = argv[0];
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	test_attr__init();
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/*
51962306a36Sopenharmony_ci	 * We use PATH to find perf commands, but we prepend some higher
52062306a36Sopenharmony_ci	 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
52162306a36Sopenharmony_ci	 * environment, and the $(perfexecdir) from the Makefile at build
52262306a36Sopenharmony_ci	 * time.
52362306a36Sopenharmony_ci	 */
52462306a36Sopenharmony_ci	setup_path();
52562306a36Sopenharmony_ci	/*
52662306a36Sopenharmony_ci	 * Block SIGWINCH notifications so that the thread that wants it can
52762306a36Sopenharmony_ci	 * unblock and get syscalls like select interrupted instead of waiting
52862306a36Sopenharmony_ci	 * forever while the signal goes to some other non interested thread.
52962306a36Sopenharmony_ci	 */
53062306a36Sopenharmony_ci	pthread__block_sigwinch();
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	while (1) {
53362306a36Sopenharmony_ci		static int done_help;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		run_argv(&argc, &argv);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		if (errno != ENOENT)
53862306a36Sopenharmony_ci			break;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		if (!done_help) {
54162306a36Sopenharmony_ci			cmd = argv[0] = help_unknown_cmd(cmd);
54262306a36Sopenharmony_ci			done_help = 1;
54362306a36Sopenharmony_ci		} else
54462306a36Sopenharmony_ci			break;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	fprintf(stderr, "Failed to run command '%s': %s\n",
54862306a36Sopenharmony_ci		cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
54962306a36Sopenharmony_ciout:
55062306a36Sopenharmony_ci	return 1;
55162306a36Sopenharmony_ci}
552