1/*
2 * perf.c
3 *
4 * Performance analysis utility.
5 *
6 * This is the main hub from which the sub-commands (perf stat,
7 * perf top, perf record, perf report, etc.) are started.
8 */
9#include "builtin.h"
10#include "perf.h"
11
12#include "util/build-id.h"
13#include "util/cache.h"
14#include "util/env.h"
15#include <internal/lib.h> // page_size
16#include <subcmd/exec-cmd.h>
17#include "util/config.h"
18#include <subcmd/run-command.h>
19#include "util/parse-events.h"
20#include <subcmd/parse-options.h>
21#include <subcmd/help.h>
22#include "util/debug.h"
23#include "util/event.h"
24#include "util/util.h" // usage()
25#include "ui/ui.h"
26#include "perf-sys.h"
27#include <api/fs/fs.h>
28#include <api/fs/tracing_path.h>
29#include <perf/core.h>
30#include <errno.h>
31#include <pthread.h>
32#include <signal.h>
33#include <stdlib.h>
34#include <time.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <unistd.h>
38#include <linux/kernel.h>
39#include <linux/string.h>
40#include <linux/zalloc.h>
41
42static int use_pager = -1;
43static FILE *debug_fp = NULL;
44
45struct cmd_struct {
46	const char *cmd;
47	int (*fn)(int, const char **);
48	int option;
49};
50
51static struct cmd_struct commands[] = {
52	{ "archive",	NULL,	0 },
53	{ "buildid-cache", cmd_buildid_cache, 0 },
54	{ "buildid-list", cmd_buildid_list, 0 },
55	{ "config",	cmd_config,	0 },
56	{ "c2c",	cmd_c2c,	0 },
57	{ "diff",	cmd_diff,	0 },
58	{ "evlist",	cmd_evlist,	0 },
59	{ "help",	cmd_help,	0 },
60	{ "iostat",	NULL,	0 },
61	{ "kallsyms",	cmd_kallsyms,	0 },
62	{ "list",	cmd_list,	0 },
63	{ "record",	cmd_record,	0 },
64	{ "report",	cmd_report,	0 },
65	{ "bench",	cmd_bench,	0 },
66	{ "stat",	cmd_stat,	0 },
67#ifdef HAVE_LIBTRACEEVENT
68	{ "timechart",	cmd_timechart,	0 },
69#endif
70	{ "top",	cmd_top,	0 },
71	{ "annotate",	cmd_annotate,	0 },
72	{ "version",	cmd_version,	0 },
73	{ "script",	cmd_script,	0 },
74#ifdef HAVE_LIBTRACEEVENT
75	{ "sched",	cmd_sched,	0 },
76#endif
77#ifdef HAVE_LIBELF_SUPPORT
78	{ "probe",	cmd_probe,	0 },
79#endif
80#ifdef HAVE_LIBTRACEEVENT
81	{ "kmem",	cmd_kmem,	0 },
82	{ "lock",	cmd_lock,	0 },
83#endif
84	{ "kvm",	cmd_kvm,	0 },
85	{ "test",	cmd_test,	0 },
86#if defined(HAVE_LIBTRACEEVENT) && (defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT))
87	{ "trace",	cmd_trace,	0 },
88#endif
89	{ "inject",	cmd_inject,	0 },
90	{ "mem",	cmd_mem,	0 },
91	{ "data",	cmd_data,	0 },
92	{ "ftrace",	cmd_ftrace,	0 },
93	{ "daemon",	cmd_daemon,	0 },
94#ifdef HAVE_LIBTRACEEVENT
95	{ "kwork",	cmd_kwork,	0 },
96#endif
97};
98
99struct pager_config {
100	const char *cmd;
101	int val;
102};
103
104static bool same_cmd_with_prefix(const char *var, struct pager_config *c,
105				  const char *header)
106{
107	return (strstarts(var, header) && !strcmp(var + strlen(header), c->cmd));
108}
109
110static int pager_command_config(const char *var, const char *value, void *data)
111{
112	struct pager_config *c = data;
113	if (same_cmd_with_prefix(var, c, "pager."))
114		c->val = perf_config_bool(var, value);
115	return 0;
116}
117
118/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
119static int check_pager_config(const char *cmd)
120{
121	int err;
122	struct pager_config c;
123	c.cmd = cmd;
124	c.val = -1;
125	err = perf_config(pager_command_config, &c);
126	return err ?: c.val;
127}
128
129static int browser_command_config(const char *var, const char *value, void *data)
130{
131	struct pager_config *c = data;
132	if (same_cmd_with_prefix(var, c, "tui."))
133		c->val = perf_config_bool(var, value);
134	if (same_cmd_with_prefix(var, c, "gtk."))
135		c->val = perf_config_bool(var, value) ? 2 : 0;
136	return 0;
137}
138
139/*
140 * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk",
141 * and -1 for "not specified"
142 */
143static int check_browser_config(const char *cmd)
144{
145	int err;
146	struct pager_config c;
147	c.cmd = cmd;
148	c.val = -1;
149	err = perf_config(browser_command_config, &c);
150	return err ?: c.val;
151}
152
153static void commit_pager_choice(void)
154{
155	switch (use_pager) {
156	case 0:
157		setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
158		break;
159	case 1:
160		/* setup_pager(); */
161		break;
162	default:
163		break;
164	}
165}
166
167static int set_debug_file(const char *path)
168{
169	debug_fp = fopen(path, "w");
170	if (!debug_fp) {
171		fprintf(stderr, "Open debug file '%s' failed: %s\n",
172			path, strerror(errno));
173		return -1;
174	}
175
176	debug_set_file(debug_fp);
177	return 0;
178}
179
180struct option options[] = {
181	OPT_ARGUMENT("help", "help"),
182	OPT_ARGUMENT("version", "version"),
183	OPT_ARGUMENT("exec-path", "exec-path"),
184	OPT_ARGUMENT("html-path", "html-path"),
185	OPT_ARGUMENT("paginate", "paginate"),
186	OPT_ARGUMENT("no-pager", "no-pager"),
187	OPT_ARGUMENT("debugfs-dir", "debugfs-dir"),
188	OPT_ARGUMENT("buildid-dir", "buildid-dir"),
189	OPT_ARGUMENT("list-cmds", "list-cmds"),
190	OPT_ARGUMENT("list-opts", "list-opts"),
191	OPT_ARGUMENT("debug", "debug"),
192	OPT_ARGUMENT("debug-file", "debug-file"),
193	OPT_END()
194};
195
196static int handle_options(const char ***argv, int *argc, int *envchanged)
197{
198	int handled = 0;
199
200	while (*argc > 0) {
201		const char *cmd = (*argv)[0];
202		if (cmd[0] != '-')
203			break;
204
205		/*
206		 * For legacy reasons, the "version" and "help"
207		 * commands can be written with "--" prepended
208		 * to make them look like flags.
209		 */
210		if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
211			break;
212
213		/*
214		 * Shortcut for '-h' and '-v' options to invoke help
215		 * and version command.
216		 */
217		if (!strcmp(cmd, "-h")) {
218			(*argv)[0] = "--help";
219			break;
220		}
221
222		if (!strcmp(cmd, "-v")) {
223			(*argv)[0] = "--version";
224			break;
225		}
226
227		if (!strcmp(cmd, "-vv")) {
228			(*argv)[0] = "version";
229			verbose = 1;
230			break;
231		}
232
233		/*
234		 * Check remaining flags.
235		 */
236		if (strstarts(cmd, CMD_EXEC_PATH)) {
237			cmd += strlen(CMD_EXEC_PATH);
238			if (*cmd == '=')
239				set_argv_exec_path(cmd + 1);
240			else {
241				puts(get_argv_exec_path());
242				exit(0);
243			}
244		} else if (!strcmp(cmd, "--html-path")) {
245			puts(system_path(PERF_HTML_PATH));
246			exit(0);
247		} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
248			use_pager = 1;
249		} else if (!strcmp(cmd, "--no-pager")) {
250			use_pager = 0;
251			if (envchanged)
252				*envchanged = 1;
253		} else if (!strcmp(cmd, "--debugfs-dir")) {
254			if (*argc < 2) {
255				fprintf(stderr, "No directory given for --debugfs-dir.\n");
256				usage(perf_usage_string);
257			}
258			tracing_path_set((*argv)[1]);
259			if (envchanged)
260				*envchanged = 1;
261			(*argv)++;
262			(*argc)--;
263		} else if (!strcmp(cmd, "--buildid-dir")) {
264			if (*argc < 2) {
265				fprintf(stderr, "No directory given for --buildid-dir.\n");
266				usage(perf_usage_string);
267			}
268			set_buildid_dir((*argv)[1]);
269			if (envchanged)
270				*envchanged = 1;
271			(*argv)++;
272			(*argc)--;
273		} else if (strstarts(cmd, CMD_DEBUGFS_DIR)) {
274			tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR));
275			fprintf(stderr, "dir: %s\n", tracing_path_mount());
276			if (envchanged)
277				*envchanged = 1;
278		} else if (!strcmp(cmd, "--list-cmds")) {
279			unsigned int i;
280
281			for (i = 0; i < ARRAY_SIZE(commands); i++) {
282				struct cmd_struct *p = commands+i;
283				printf("%s ", p->cmd);
284			}
285			putchar('\n');
286			exit(0);
287		} else if (!strcmp(cmd, "--list-opts")) {
288			unsigned int i;
289
290			for (i = 0; i < ARRAY_SIZE(options)-1; i++) {
291				struct option *p = options+i;
292				printf("--%s ", p->long_name);
293			}
294			putchar('\n');
295			exit(0);
296		} else if (!strcmp(cmd, "--debug")) {
297			if (*argc < 2) {
298				fprintf(stderr, "No variable specified for --debug.\n");
299				usage(perf_usage_string);
300			}
301			if (perf_debug_option((*argv)[1]))
302				usage(perf_usage_string);
303
304			(*argv)++;
305			(*argc)--;
306		} else if (!strcmp(cmd, "--debug-file")) {
307			if (*argc < 2) {
308				fprintf(stderr, "No path given for --debug-file.\n");
309				usage(perf_usage_string);
310			}
311
312			if (set_debug_file((*argv)[1]))
313				usage(perf_usage_string);
314
315			(*argv)++;
316			(*argc)--;
317
318		} else {
319			fprintf(stderr, "Unknown option: %s\n", cmd);
320			usage(perf_usage_string);
321		}
322
323		(*argv)++;
324		(*argc)--;
325		handled++;
326	}
327	return handled;
328}
329
330#define RUN_SETUP	(1<<0)
331#define USE_PAGER	(1<<1)
332
333static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
334{
335	int status;
336	struct stat st;
337	char sbuf[STRERR_BUFSIZE];
338
339	if (use_browser == -1)
340		use_browser = check_browser_config(p->cmd);
341
342	if (use_pager == -1 && p->option & RUN_SETUP)
343		use_pager = check_pager_config(p->cmd);
344	if (use_pager == -1 && p->option & USE_PAGER)
345		use_pager = 1;
346	commit_pager_choice();
347
348	perf_env__init(&perf_env);
349	perf_env__set_cmdline(&perf_env, argc, argv);
350	status = p->fn(argc, argv);
351	perf_config__exit();
352	exit_browser(status);
353	perf_env__exit(&perf_env);
354
355	if (status)
356		return status & 0xff;
357
358	/* Somebody closed stdout? */
359	if (fstat(fileno(stdout), &st))
360		return 0;
361	/* Ignore write errors for pipes and sockets.. */
362	if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
363		return 0;
364
365	status = 1;
366	/* Check for ENOSPC and EIO errors.. */
367	if (fflush(stdout)) {
368		fprintf(stderr, "write failure on standard output: %s",
369			str_error_r(errno, sbuf, sizeof(sbuf)));
370		goto out;
371	}
372	if (ferror(stdout)) {
373		fprintf(stderr, "unknown write failure on standard output");
374		goto out;
375	}
376	if (fclose(stdout)) {
377		fprintf(stderr, "close failed on standard output: %s",
378			str_error_r(errno, sbuf, sizeof(sbuf)));
379		goto out;
380	}
381	status = 0;
382out:
383	return status;
384}
385
386static void handle_internal_command(int argc, const char **argv)
387{
388	const char *cmd = argv[0];
389	unsigned int i;
390
391	/* Turn "perf cmd --help" into "perf help cmd" */
392	if (argc > 1 && !strcmp(argv[1], "--help")) {
393		argv[1] = argv[0];
394		argv[0] = cmd = "help";
395	}
396
397	for (i = 0; i < ARRAY_SIZE(commands); i++) {
398		struct cmd_struct *p = commands+i;
399		if (p->fn == NULL)
400			continue;
401		if (strcmp(p->cmd, cmd))
402			continue;
403		exit(run_builtin(p, argc, argv));
404	}
405}
406
407static void execv_dashed_external(const char **argv)
408{
409	char *cmd;
410	const char *tmp;
411	int status;
412
413	if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
414		goto do_die;
415
416	/*
417	 * argv[0] must be the perf command, but the argv array
418	 * belongs to the caller, and may be reused in
419	 * subsequent loop iterations. Save argv[0] and
420	 * restore it on error.
421	 */
422	tmp = argv[0];
423	argv[0] = cmd;
424
425	/*
426	 * if we fail because the command is not found, it is
427	 * OK to return. Otherwise, we just pass along the status code.
428	 */
429	status = run_command_v_opt(argv, 0);
430	if (status != -ERR_RUN_COMMAND_EXEC) {
431		if (IS_RUN_COMMAND_ERR(status)) {
432do_die:
433			pr_err("FATAL: unable to run '%s'", argv[0]);
434			status = -128;
435		}
436		exit(-status);
437	}
438	errno = ENOENT; /* as if we called execvp */
439
440	argv[0] = tmp;
441	zfree(&cmd);
442}
443
444static int run_argv(int *argcp, const char ***argv)
445{
446	/* See if it's an internal command */
447	handle_internal_command(*argcp, *argv);
448
449	/* .. then try the external ones */
450	execv_dashed_external(*argv);
451	return 0;
452}
453
454static int libperf_print(enum libperf_print_level level,
455			 const char *fmt, va_list ap)
456{
457	return veprintf(level, verbose, fmt, ap);
458}
459
460int main(int argc, const char **argv)
461{
462	int err, done_help = 0;
463	const char *cmd;
464	char sbuf[STRERR_BUFSIZE];
465
466	perf_debug_setup();
467
468	/* libsubcmd init */
469	exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
470	pager_init(PERF_PAGER_ENVIRONMENT);
471
472	libperf_init(libperf_print);
473
474	cmd = extract_argv0_path(argv[0]);
475	if (!cmd)
476		cmd = "perf-help";
477
478	srandom(time(NULL));
479
480	/* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
481	config_exclusive_filename = getenv("PERF_CONFIG");
482
483	err = perf_config(perf_default_config, NULL);
484	if (err)
485		return err;
486	set_buildid_dir(NULL);
487
488	/*
489	 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
490	 *
491	 *  - cannot take flags in between the "perf" and the "xxxx".
492	 *  - cannot execute it externally (since it would just do
493	 *    the same thing over again)
494	 *
495	 * So we just directly call the internal command handler. If that one
496	 * fails to handle this, then maybe we just run a renamed perf binary
497	 * that contains a dash in its name. To handle this scenario, we just
498	 * fall through and ignore the "xxxx" part of the command string.
499	 */
500	if (strstarts(cmd, "perf-")) {
501		cmd += 5;
502		argv[0] = cmd;
503		handle_internal_command(argc, argv);
504		/*
505		 * If the command is handled, the above function does not
506		 * return undo changes and fall through in such a case.
507		 */
508		cmd -= 5;
509		argv[0] = cmd;
510	}
511	if (strstarts(cmd, "trace")) {
512#ifndef HAVE_LIBTRACEEVENT
513		fprintf(stderr,
514			"trace command not available: missing libtraceevent devel package at build time.\n");
515		goto out;
516#elif !defined(HAVE_LIBAUDIT_SUPPORT) && !defined(HAVE_SYSCALL_TABLE_SUPPORT)
517		fprintf(stderr,
518			"trace command not available: missing audit-libs devel package at build time.\n");
519		goto out;
520#else
521		setup_path();
522		argv[0] = "trace";
523		return cmd_trace(argc, argv);
524#endif
525	}
526	/* Look for flags.. */
527	argv++;
528	argc--;
529	handle_options(&argv, &argc, NULL);
530	commit_pager_choice();
531
532	if (argc > 0) {
533		if (strstarts(argv[0], "--"))
534			argv[0] += 2;
535	} else {
536		/* The user didn't specify a command; give them help */
537		printf("\n usage: %s\n\n", perf_usage_string);
538		list_common_cmds_help();
539		printf("\n %s\n\n", perf_more_info_string);
540		goto out;
541	}
542	cmd = argv[0];
543
544	test_attr__init();
545
546	/*
547	 * We use PATH to find perf commands, but we prepend some higher
548	 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
549	 * environment, and the $(perfexecdir) from the Makefile at build
550	 * time.
551	 */
552	setup_path();
553	/*
554	 * Block SIGWINCH notifications so that the thread that wants it can
555	 * unblock and get syscalls like select interrupted instead of waiting
556	 * forever while the signal goes to some other non interested thread.
557	 */
558	pthread__block_sigwinch();
559
560	while (1) {
561		run_argv(&argc, &argv);
562
563		if (errno != ENOENT)
564			break;
565
566		if (!done_help) {
567			struct cmdnames main_cmds = {};
568
569			for (unsigned int i = 0; i < ARRAY_SIZE(commands); i++) {
570				add_cmdname(&main_cmds,
571					    commands[i].cmd,
572					    strlen(commands[i].cmd));
573			}
574			cmd = argv[0] = help_unknown_cmd(cmd, &main_cmds);
575			clean_cmdnames(&main_cmds);
576			done_help = 1;
577			if (!cmd)
578				break;
579		} else
580			break;
581	}
582
583	if (cmd) {
584		fprintf(stderr, "Failed to run command '%s': %s\n",
585			cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
586	}
587out:
588	if (debug_fp)
589		fclose(debug_fp);
590
591	return 1;
592}
593