18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * perf.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Performance analysis utility. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This is the main hub from which the sub-commands (perf stat, 78c2ecf20Sopenharmony_ci * perf top, perf record, perf report, etc.) are started. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include "builtin.h" 108c2ecf20Sopenharmony_ci#include "perf.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "util/build-id.h" 138c2ecf20Sopenharmony_ci#include "util/cache.h" 148c2ecf20Sopenharmony_ci#include "util/env.h" 158c2ecf20Sopenharmony_ci#include <internal/lib.h> // page_size 168c2ecf20Sopenharmony_ci#include <subcmd/exec-cmd.h> 178c2ecf20Sopenharmony_ci#include "util/config.h" 188c2ecf20Sopenharmony_ci#include <subcmd/run-command.h> 198c2ecf20Sopenharmony_ci#include "util/parse-events.h" 208c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h> 218c2ecf20Sopenharmony_ci#include "util/bpf-loader.h" 228c2ecf20Sopenharmony_ci#include "util/debug.h" 238c2ecf20Sopenharmony_ci#include "util/event.h" 248c2ecf20Sopenharmony_ci#include "util/util.h" // usage() 258c2ecf20Sopenharmony_ci#include "ui/ui.h" 268c2ecf20Sopenharmony_ci#include "perf-sys.h" 278c2ecf20Sopenharmony_ci#include <api/fs/fs.h> 288c2ecf20Sopenharmony_ci#include <api/fs/tracing_path.h> 298c2ecf20Sopenharmony_ci#include <perf/core.h> 308c2ecf20Sopenharmony_ci#include <errno.h> 318c2ecf20Sopenharmony_ci#include <pthread.h> 328c2ecf20Sopenharmony_ci#include <signal.h> 338c2ecf20Sopenharmony_ci#include <stdlib.h> 348c2ecf20Sopenharmony_ci#include <time.h> 358c2ecf20Sopenharmony_ci#include <sys/types.h> 368c2ecf20Sopenharmony_ci#include <sys/stat.h> 378c2ecf20Sopenharmony_ci#include <unistd.h> 388c2ecf20Sopenharmony_ci#include <linux/kernel.h> 398c2ecf20Sopenharmony_ci#include <linux/string.h> 408c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ciconst char perf_usage_string[] = 438c2ecf20Sopenharmony_ci "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]"; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciconst char perf_more_info_string[] = 468c2ecf20Sopenharmony_ci "See 'perf help COMMAND' for more information on a specific command."; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int use_pager = -1; 498c2ecf20Sopenharmony_ciconst char *input_name; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct cmd_struct { 528c2ecf20Sopenharmony_ci const char *cmd; 538c2ecf20Sopenharmony_ci int (*fn)(int, const char **); 548c2ecf20Sopenharmony_ci int option; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic struct cmd_struct commands[] = { 588c2ecf20Sopenharmony_ci { "buildid-cache", cmd_buildid_cache, 0 }, 598c2ecf20Sopenharmony_ci { "buildid-list", cmd_buildid_list, 0 }, 608c2ecf20Sopenharmony_ci { "config", cmd_config, 0 }, 618c2ecf20Sopenharmony_ci { "c2c", cmd_c2c, 0 }, 628c2ecf20Sopenharmony_ci { "diff", cmd_diff, 0 }, 638c2ecf20Sopenharmony_ci { "evlist", cmd_evlist, 0 }, 648c2ecf20Sopenharmony_ci { "help", cmd_help, 0 }, 658c2ecf20Sopenharmony_ci { "kallsyms", cmd_kallsyms, 0 }, 668c2ecf20Sopenharmony_ci { "list", cmd_list, 0 }, 678c2ecf20Sopenharmony_ci { "record", cmd_record, 0 }, 688c2ecf20Sopenharmony_ci { "report", cmd_report, 0 }, 698c2ecf20Sopenharmony_ci { "bench", cmd_bench, 0 }, 708c2ecf20Sopenharmony_ci { "stat", cmd_stat, 0 }, 718c2ecf20Sopenharmony_ci { "timechart", cmd_timechart, 0 }, 728c2ecf20Sopenharmony_ci { "top", cmd_top, 0 }, 738c2ecf20Sopenharmony_ci { "annotate", cmd_annotate, 0 }, 748c2ecf20Sopenharmony_ci { "version", cmd_version, 0 }, 758c2ecf20Sopenharmony_ci { "script", cmd_script, 0 }, 768c2ecf20Sopenharmony_ci { "sched", cmd_sched, 0 }, 778c2ecf20Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT 788c2ecf20Sopenharmony_ci { "probe", cmd_probe, 0 }, 798c2ecf20Sopenharmony_ci#endif 808c2ecf20Sopenharmony_ci { "kmem", cmd_kmem, 0 }, 818c2ecf20Sopenharmony_ci { "lock", cmd_lock, 0 }, 828c2ecf20Sopenharmony_ci { "kvm", cmd_kvm, 0 }, 838c2ecf20Sopenharmony_ci { "test", cmd_test, 0 }, 848c2ecf20Sopenharmony_ci#if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT) 858c2ecf20Sopenharmony_ci { "trace", cmd_trace, 0 }, 868c2ecf20Sopenharmony_ci#endif 878c2ecf20Sopenharmony_ci { "inject", cmd_inject, 0 }, 888c2ecf20Sopenharmony_ci { "mem", cmd_mem, 0 }, 898c2ecf20Sopenharmony_ci { "data", cmd_data, 0 }, 908c2ecf20Sopenharmony_ci { "ftrace", cmd_ftrace, 0 }, 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistruct pager_config { 948c2ecf20Sopenharmony_ci const char *cmd; 958c2ecf20Sopenharmony_ci int val; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int pager_command_config(const char *var, const char *value, void *data) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct pager_config *c = data; 1018c2ecf20Sopenharmony_ci if (strstarts(var, "pager.") && !strcmp(var + 6, c->cmd)) 1028c2ecf20Sopenharmony_ci c->val = perf_config_bool(var, value); 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ 1078c2ecf20Sopenharmony_cistatic int check_pager_config(const char *cmd) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int err; 1108c2ecf20Sopenharmony_ci struct pager_config c; 1118c2ecf20Sopenharmony_ci c.cmd = cmd; 1128c2ecf20Sopenharmony_ci c.val = -1; 1138c2ecf20Sopenharmony_ci err = perf_config(pager_command_config, &c); 1148c2ecf20Sopenharmony_ci return err ?: c.val; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int browser_command_config(const char *var, const char *value, void *data) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct pager_config *c = data; 1208c2ecf20Sopenharmony_ci if (strstarts(var, "tui.") && !strcmp(var + 4, c->cmd)) 1218c2ecf20Sopenharmony_ci c->val = perf_config_bool(var, value); 1228c2ecf20Sopenharmony_ci if (strstarts(var, "gtk.") && !strcmp(var + 4, c->cmd)) 1238c2ecf20Sopenharmony_ci c->val = perf_config_bool(var, value) ? 2 : 0; 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* 1288c2ecf20Sopenharmony_ci * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk", 1298c2ecf20Sopenharmony_ci * and -1 for "not specified" 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_cistatic int check_browser_config(const char *cmd) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci int err; 1348c2ecf20Sopenharmony_ci struct pager_config c; 1358c2ecf20Sopenharmony_ci c.cmd = cmd; 1368c2ecf20Sopenharmony_ci c.val = -1; 1378c2ecf20Sopenharmony_ci err = perf_config(browser_command_config, &c); 1388c2ecf20Sopenharmony_ci return err ?: c.val; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void commit_pager_choice(void) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci switch (use_pager) { 1448c2ecf20Sopenharmony_ci case 0: 1458c2ecf20Sopenharmony_ci setenv(PERF_PAGER_ENVIRONMENT, "cat", 1); 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case 1: 1488c2ecf20Sopenharmony_ci /* setup_pager(); */ 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci default: 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistruct option options[] = { 1568c2ecf20Sopenharmony_ci OPT_ARGUMENT("help", "help"), 1578c2ecf20Sopenharmony_ci OPT_ARGUMENT("version", "version"), 1588c2ecf20Sopenharmony_ci OPT_ARGUMENT("exec-path", "exec-path"), 1598c2ecf20Sopenharmony_ci OPT_ARGUMENT("html-path", "html-path"), 1608c2ecf20Sopenharmony_ci OPT_ARGUMENT("paginate", "paginate"), 1618c2ecf20Sopenharmony_ci OPT_ARGUMENT("no-pager", "no-pager"), 1628c2ecf20Sopenharmony_ci OPT_ARGUMENT("debugfs-dir", "debugfs-dir"), 1638c2ecf20Sopenharmony_ci OPT_ARGUMENT("buildid-dir", "buildid-dir"), 1648c2ecf20Sopenharmony_ci OPT_ARGUMENT("list-cmds", "list-cmds"), 1658c2ecf20Sopenharmony_ci OPT_ARGUMENT("list-opts", "list-opts"), 1668c2ecf20Sopenharmony_ci OPT_ARGUMENT("debug", "debug"), 1678c2ecf20Sopenharmony_ci OPT_END() 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int handle_options(const char ***argv, int *argc, int *envchanged) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci int handled = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci while (*argc > 0) { 1758c2ecf20Sopenharmony_ci const char *cmd = (*argv)[0]; 1768c2ecf20Sopenharmony_ci if (cmd[0] != '-') 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * For legacy reasons, the "version" and "help" 1818c2ecf20Sopenharmony_ci * commands can be written with "--" prepended 1828c2ecf20Sopenharmony_ci * to make them look like flags. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version")) 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * Shortcut for '-h' and '-v' options to invoke help 1898c2ecf20Sopenharmony_ci * and version command. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci if (!strcmp(cmd, "-h")) { 1928c2ecf20Sopenharmony_ci (*argv)[0] = "--help"; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (!strcmp(cmd, "-v")) { 1978c2ecf20Sopenharmony_ci (*argv)[0] = "--version"; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (!strcmp(cmd, "-vv")) { 2028c2ecf20Sopenharmony_ci (*argv)[0] = "version"; 2038c2ecf20Sopenharmony_ci version_verbose = 1; 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * Check remaining flags. 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ci if (strstarts(cmd, CMD_EXEC_PATH)) { 2118c2ecf20Sopenharmony_ci cmd += strlen(CMD_EXEC_PATH); 2128c2ecf20Sopenharmony_ci if (*cmd == '=') 2138c2ecf20Sopenharmony_ci set_argv_exec_path(cmd + 1); 2148c2ecf20Sopenharmony_ci else { 2158c2ecf20Sopenharmony_ci puts(get_argv_exec_path()); 2168c2ecf20Sopenharmony_ci exit(0); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci } else if (!strcmp(cmd, "--html-path")) { 2198c2ecf20Sopenharmony_ci puts(system_path(PERF_HTML_PATH)); 2208c2ecf20Sopenharmony_ci exit(0); 2218c2ecf20Sopenharmony_ci } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) { 2228c2ecf20Sopenharmony_ci use_pager = 1; 2238c2ecf20Sopenharmony_ci } else if (!strcmp(cmd, "--no-pager")) { 2248c2ecf20Sopenharmony_ci use_pager = 0; 2258c2ecf20Sopenharmony_ci if (envchanged) 2268c2ecf20Sopenharmony_ci *envchanged = 1; 2278c2ecf20Sopenharmony_ci } else if (!strcmp(cmd, "--debugfs-dir")) { 2288c2ecf20Sopenharmony_ci if (*argc < 2) { 2298c2ecf20Sopenharmony_ci fprintf(stderr, "No directory given for --debugfs-dir.\n"); 2308c2ecf20Sopenharmony_ci usage(perf_usage_string); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci tracing_path_set((*argv)[1]); 2338c2ecf20Sopenharmony_ci if (envchanged) 2348c2ecf20Sopenharmony_ci *envchanged = 1; 2358c2ecf20Sopenharmony_ci (*argv)++; 2368c2ecf20Sopenharmony_ci (*argc)--; 2378c2ecf20Sopenharmony_ci } else if (!strcmp(cmd, "--buildid-dir")) { 2388c2ecf20Sopenharmony_ci if (*argc < 2) { 2398c2ecf20Sopenharmony_ci fprintf(stderr, "No directory given for --buildid-dir.\n"); 2408c2ecf20Sopenharmony_ci usage(perf_usage_string); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci set_buildid_dir((*argv)[1]); 2438c2ecf20Sopenharmony_ci if (envchanged) 2448c2ecf20Sopenharmony_ci *envchanged = 1; 2458c2ecf20Sopenharmony_ci (*argv)++; 2468c2ecf20Sopenharmony_ci (*argc)--; 2478c2ecf20Sopenharmony_ci } else if (strstarts(cmd, CMD_DEBUGFS_DIR)) { 2488c2ecf20Sopenharmony_ci tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR)); 2498c2ecf20Sopenharmony_ci fprintf(stderr, "dir: %s\n", tracing_path_mount()); 2508c2ecf20Sopenharmony_ci if (envchanged) 2518c2ecf20Sopenharmony_ci *envchanged = 1; 2528c2ecf20Sopenharmony_ci } else if (!strcmp(cmd, "--list-cmds")) { 2538c2ecf20Sopenharmony_ci unsigned int i; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(commands); i++) { 2568c2ecf20Sopenharmony_ci struct cmd_struct *p = commands+i; 2578c2ecf20Sopenharmony_ci printf("%s ", p->cmd); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci putchar('\n'); 2608c2ecf20Sopenharmony_ci exit(0); 2618c2ecf20Sopenharmony_ci } else if (!strcmp(cmd, "--list-opts")) { 2628c2ecf20Sopenharmony_ci unsigned int i; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(options)-1; i++) { 2658c2ecf20Sopenharmony_ci struct option *p = options+i; 2668c2ecf20Sopenharmony_ci printf("--%s ", p->long_name); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci putchar('\n'); 2698c2ecf20Sopenharmony_ci exit(0); 2708c2ecf20Sopenharmony_ci } else if (!strcmp(cmd, "--debug")) { 2718c2ecf20Sopenharmony_ci if (*argc < 2) { 2728c2ecf20Sopenharmony_ci fprintf(stderr, "No variable specified for --debug.\n"); 2738c2ecf20Sopenharmony_ci usage(perf_usage_string); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci if (perf_debug_option((*argv)[1])) 2768c2ecf20Sopenharmony_ci usage(perf_usage_string); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci (*argv)++; 2798c2ecf20Sopenharmony_ci (*argc)--; 2808c2ecf20Sopenharmony_ci } else { 2818c2ecf20Sopenharmony_ci fprintf(stderr, "Unknown option: %s\n", cmd); 2828c2ecf20Sopenharmony_ci usage(perf_usage_string); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci (*argv)++; 2868c2ecf20Sopenharmony_ci (*argc)--; 2878c2ecf20Sopenharmony_ci handled++; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci return handled; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci#define RUN_SETUP (1<<0) 2938c2ecf20Sopenharmony_ci#define USE_PAGER (1<<1) 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int run_builtin(struct cmd_struct *p, int argc, const char **argv) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int status; 2988c2ecf20Sopenharmony_ci struct stat st; 2998c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (use_browser == -1) 3028c2ecf20Sopenharmony_ci use_browser = check_browser_config(p->cmd); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (use_pager == -1 && p->option & RUN_SETUP) 3058c2ecf20Sopenharmony_ci use_pager = check_pager_config(p->cmd); 3068c2ecf20Sopenharmony_ci if (use_pager == -1 && p->option & USE_PAGER) 3078c2ecf20Sopenharmony_ci use_pager = 1; 3088c2ecf20Sopenharmony_ci commit_pager_choice(); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci perf_env__init(&perf_env); 3118c2ecf20Sopenharmony_ci perf_env__set_cmdline(&perf_env, argc, argv); 3128c2ecf20Sopenharmony_ci status = p->fn(argc, argv); 3138c2ecf20Sopenharmony_ci perf_config__exit(); 3148c2ecf20Sopenharmony_ci exit_browser(status); 3158c2ecf20Sopenharmony_ci perf_env__exit(&perf_env); 3168c2ecf20Sopenharmony_ci bpf__clear(); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (status) 3198c2ecf20Sopenharmony_ci return status & 0xff; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* Somebody closed stdout? */ 3228c2ecf20Sopenharmony_ci if (fstat(fileno(stdout), &st)) 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci /* Ignore write errors for pipes and sockets.. */ 3258c2ecf20Sopenharmony_ci if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci status = 1; 3298c2ecf20Sopenharmony_ci /* Check for ENOSPC and EIO errors.. */ 3308c2ecf20Sopenharmony_ci if (fflush(stdout)) { 3318c2ecf20Sopenharmony_ci fprintf(stderr, "write failure on standard output: %s", 3328c2ecf20Sopenharmony_ci str_error_r(errno, sbuf, sizeof(sbuf))); 3338c2ecf20Sopenharmony_ci goto out; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci if (ferror(stdout)) { 3368c2ecf20Sopenharmony_ci fprintf(stderr, "unknown write failure on standard output"); 3378c2ecf20Sopenharmony_ci goto out; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci if (fclose(stdout)) { 3408c2ecf20Sopenharmony_ci fprintf(stderr, "close failed on standard output: %s", 3418c2ecf20Sopenharmony_ci str_error_r(errno, sbuf, sizeof(sbuf))); 3428c2ecf20Sopenharmony_ci goto out; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci status = 0; 3458c2ecf20Sopenharmony_ciout: 3468c2ecf20Sopenharmony_ci return status; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void handle_internal_command(int argc, const char **argv) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci const char *cmd = argv[0]; 3528c2ecf20Sopenharmony_ci unsigned int i; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* Turn "perf cmd --help" into "perf help cmd" */ 3558c2ecf20Sopenharmony_ci if (argc > 1 && !strcmp(argv[1], "--help")) { 3568c2ecf20Sopenharmony_ci argv[1] = argv[0]; 3578c2ecf20Sopenharmony_ci argv[0] = cmd = "help"; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(commands); i++) { 3618c2ecf20Sopenharmony_ci struct cmd_struct *p = commands+i; 3628c2ecf20Sopenharmony_ci if (strcmp(p->cmd, cmd)) 3638c2ecf20Sopenharmony_ci continue; 3648c2ecf20Sopenharmony_ci exit(run_builtin(p, argc, argv)); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void execv_dashed_external(const char **argv) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci char *cmd; 3718c2ecf20Sopenharmony_ci const char *tmp; 3728c2ecf20Sopenharmony_ci int status; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (asprintf(&cmd, "perf-%s", argv[0]) < 0) 3758c2ecf20Sopenharmony_ci goto do_die; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * argv[0] must be the perf command, but the argv array 3798c2ecf20Sopenharmony_ci * belongs to the caller, and may be reused in 3808c2ecf20Sopenharmony_ci * subsequent loop iterations. Save argv[0] and 3818c2ecf20Sopenharmony_ci * restore it on error. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci tmp = argv[0]; 3848c2ecf20Sopenharmony_ci argv[0] = cmd; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci * if we fail because the command is not found, it is 3888c2ecf20Sopenharmony_ci * OK to return. Otherwise, we just pass along the status code. 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_ci status = run_command_v_opt(argv, 0); 3918c2ecf20Sopenharmony_ci if (status != -ERR_RUN_COMMAND_EXEC) { 3928c2ecf20Sopenharmony_ci if (IS_RUN_COMMAND_ERR(status)) { 3938c2ecf20Sopenharmony_cido_die: 3948c2ecf20Sopenharmony_ci pr_err("FATAL: unable to run '%s'", argv[0]); 3958c2ecf20Sopenharmony_ci status = -128; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci exit(-status); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci errno = ENOENT; /* as if we called execvp */ 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci argv[0] = tmp; 4028c2ecf20Sopenharmony_ci zfree(&cmd); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int run_argv(int *argcp, const char ***argv) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci /* See if it's an internal command */ 4088c2ecf20Sopenharmony_ci handle_internal_command(*argcp, *argv); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* .. then try the external ones */ 4118c2ecf20Sopenharmony_ci execv_dashed_external(*argv); 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic void pthread__block_sigwinch(void) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci sigset_t set; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci sigemptyset(&set); 4208c2ecf20Sopenharmony_ci sigaddset(&set, SIGWINCH); 4218c2ecf20Sopenharmony_ci pthread_sigmask(SIG_BLOCK, &set, NULL); 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_civoid pthread__unblock_sigwinch(void) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci sigset_t set; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci sigemptyset(&set); 4298c2ecf20Sopenharmony_ci sigaddset(&set, SIGWINCH); 4308c2ecf20Sopenharmony_ci pthread_sigmask(SIG_UNBLOCK, &set, NULL); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int libperf_print(enum libperf_print_level level, 4348c2ecf20Sopenharmony_ci const char *fmt, va_list ap) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci return veprintf(level, verbose, fmt, ap); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ciint main(int argc, const char **argv) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci int err; 4428c2ecf20Sopenharmony_ci const char *cmd; 4438c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* libsubcmd init */ 4468c2ecf20Sopenharmony_ci exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); 4478c2ecf20Sopenharmony_ci pager_init(PERF_PAGER_ENVIRONMENT); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci libperf_init(libperf_print); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci cmd = extract_argv0_path(argv[0]); 4528c2ecf20Sopenharmony_ci if (!cmd) 4538c2ecf20Sopenharmony_ci cmd = "perf-help"; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci srandom(time(NULL)); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 4588c2ecf20Sopenharmony_ci config_exclusive_filename = getenv("PERF_CONFIG"); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci err = perf_config(perf_default_config, NULL); 4618c2ecf20Sopenharmony_ci if (err) 4628c2ecf20Sopenharmony_ci return err; 4638c2ecf20Sopenharmony_ci set_buildid_dir(NULL); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* 4668c2ecf20Sopenharmony_ci * "perf-xxxx" is the same as "perf xxxx", but we obviously: 4678c2ecf20Sopenharmony_ci * 4688c2ecf20Sopenharmony_ci * - cannot take flags in between the "perf" and the "xxxx". 4698c2ecf20Sopenharmony_ci * - cannot execute it externally (since it would just do 4708c2ecf20Sopenharmony_ci * the same thing over again) 4718c2ecf20Sopenharmony_ci * 4728c2ecf20Sopenharmony_ci * So we just directly call the internal command handler. If that one 4738c2ecf20Sopenharmony_ci * fails to handle this, then maybe we just run a renamed perf binary 4748c2ecf20Sopenharmony_ci * that contains a dash in its name. To handle this scenario, we just 4758c2ecf20Sopenharmony_ci * fall through and ignore the "xxxx" part of the command string. 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_ci if (strstarts(cmd, "perf-")) { 4788c2ecf20Sopenharmony_ci cmd += 5; 4798c2ecf20Sopenharmony_ci argv[0] = cmd; 4808c2ecf20Sopenharmony_ci handle_internal_command(argc, argv); 4818c2ecf20Sopenharmony_ci /* 4828c2ecf20Sopenharmony_ci * If the command is handled, the above function does not 4838c2ecf20Sopenharmony_ci * return undo changes and fall through in such a case. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci cmd -= 5; 4868c2ecf20Sopenharmony_ci argv[0] = cmd; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci if (strstarts(cmd, "trace")) { 4898c2ecf20Sopenharmony_ci#if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT) 4908c2ecf20Sopenharmony_ci setup_path(); 4918c2ecf20Sopenharmony_ci argv[0] = "trace"; 4928c2ecf20Sopenharmony_ci return cmd_trace(argc, argv); 4938c2ecf20Sopenharmony_ci#else 4948c2ecf20Sopenharmony_ci fprintf(stderr, 4958c2ecf20Sopenharmony_ci "trace command not available: missing audit-libs devel package at build time.\n"); 4968c2ecf20Sopenharmony_ci goto out; 4978c2ecf20Sopenharmony_ci#endif 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci /* Look for flags.. */ 5008c2ecf20Sopenharmony_ci argv++; 5018c2ecf20Sopenharmony_ci argc--; 5028c2ecf20Sopenharmony_ci handle_options(&argv, &argc, NULL); 5038c2ecf20Sopenharmony_ci commit_pager_choice(); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (argc > 0) { 5068c2ecf20Sopenharmony_ci if (strstarts(argv[0], "--")) 5078c2ecf20Sopenharmony_ci argv[0] += 2; 5088c2ecf20Sopenharmony_ci } else { 5098c2ecf20Sopenharmony_ci /* The user didn't specify a command; give them help */ 5108c2ecf20Sopenharmony_ci printf("\n usage: %s\n\n", perf_usage_string); 5118c2ecf20Sopenharmony_ci list_common_cmds_help(); 5128c2ecf20Sopenharmony_ci printf("\n %s\n\n", perf_more_info_string); 5138c2ecf20Sopenharmony_ci goto out; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci cmd = argv[0]; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci test_attr__init(); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* 5208c2ecf20Sopenharmony_ci * We use PATH to find perf commands, but we prepend some higher 5218c2ecf20Sopenharmony_ci * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH 5228c2ecf20Sopenharmony_ci * environment, and the $(perfexecdir) from the Makefile at build 5238c2ecf20Sopenharmony_ci * time. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_ci setup_path(); 5268c2ecf20Sopenharmony_ci /* 5278c2ecf20Sopenharmony_ci * Block SIGWINCH notifications so that the thread that wants it can 5288c2ecf20Sopenharmony_ci * unblock and get syscalls like select interrupted instead of waiting 5298c2ecf20Sopenharmony_ci * forever while the signal goes to some other non interested thread. 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_ci pthread__block_sigwinch(); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci perf_debug_setup(); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci while (1) { 5368c2ecf20Sopenharmony_ci static int done_help; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci run_argv(&argc, &argv); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (errno != ENOENT) 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (!done_help) { 5448c2ecf20Sopenharmony_ci cmd = argv[0] = help_unknown_cmd(cmd); 5458c2ecf20Sopenharmony_ci done_help = 1; 5468c2ecf20Sopenharmony_ci } else 5478c2ecf20Sopenharmony_ci break; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to run command '%s': %s\n", 5518c2ecf20Sopenharmony_ci cmd, str_error_r(errno, sbuf, sizeof(sbuf))); 5528c2ecf20Sopenharmony_ciout: 5538c2ecf20Sopenharmony_ci return 1; 5548c2ecf20Sopenharmony_ci} 555