Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * perf.c
0003  *
0004  * Performance analysis utility.
0005  *
0006  * This is the main hub from which the sub-commands (perf stat,
0007  * perf top, perf record, perf report, etc.) are started.
0008  */
0009 #include "builtin.h"
0010 #include "perf.h"
0011 
0012 #include "util/build-id.h"
0013 #include "util/cache.h"
0014 #include "util/env.h"
0015 #include <internal/lib.h> // page_size
0016 #include <subcmd/exec-cmd.h>
0017 #include "util/config.h"
0018 #include <subcmd/run-command.h>
0019 #include "util/parse-events.h"
0020 #include <subcmd/parse-options.h>
0021 #include "util/bpf-loader.h"
0022 #include "util/debug.h"
0023 #include "util/event.h"
0024 #include "util/util.h" // usage()
0025 #include "ui/ui.h"
0026 #include "perf-sys.h"
0027 #include <api/fs/fs.h>
0028 #include <api/fs/tracing_path.h>
0029 #include <perf/core.h>
0030 #include <errno.h>
0031 #include <pthread.h>
0032 #include <signal.h>
0033 #include <stdlib.h>
0034 #include <time.h>
0035 #include <sys/types.h>
0036 #include <sys/stat.h>
0037 #include <unistd.h>
0038 #include <linux/kernel.h>
0039 #include <linux/string.h>
0040 #include <linux/zalloc.h>
0041 
0042 const char perf_usage_string[] =
0043     "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
0044 
0045 const char perf_more_info_string[] =
0046     "See 'perf help COMMAND' for more information on a specific command.";
0047 
0048 static int use_pager = -1;
0049 const char *input_name;
0050 
0051 struct cmd_struct {
0052     const char *cmd;
0053     int (*fn)(int, const char **);
0054     int option;
0055 };
0056 
0057 static struct cmd_struct commands[] = {
0058     { "archive",    NULL,   0 },
0059     { "buildid-cache", cmd_buildid_cache, 0 },
0060     { "buildid-list", cmd_buildid_list, 0 },
0061     { "config", cmd_config, 0 },
0062     { "c2c",    cmd_c2c,    0 },
0063     { "diff",   cmd_diff,   0 },
0064     { "evlist", cmd_evlist, 0 },
0065     { "help",   cmd_help,   0 },
0066     { "iostat", NULL,   0 },
0067     { "kallsyms",   cmd_kallsyms,   0 },
0068     { "list",   cmd_list,   0 },
0069     { "record", cmd_record, 0 },
0070     { "report", cmd_report, 0 },
0071     { "bench",  cmd_bench,  0 },
0072     { "stat",   cmd_stat,   0 },
0073     { "timechart",  cmd_timechart,  0 },
0074     { "top",    cmd_top,    0 },
0075     { "annotate",   cmd_annotate,   0 },
0076     { "version",    cmd_version,    0 },
0077     { "script", cmd_script, 0 },
0078     { "sched",  cmd_sched,  0 },
0079 #ifdef HAVE_LIBELF_SUPPORT
0080     { "probe",  cmd_probe,  0 },
0081 #endif
0082     { "kmem",   cmd_kmem,   0 },
0083     { "lock",   cmd_lock,   0 },
0084     { "kvm",    cmd_kvm,    0 },
0085     { "test",   cmd_test,   0 },
0086 #if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT)
0087     { "trace",  cmd_trace,  0 },
0088 #endif
0089     { "inject", cmd_inject, 0 },
0090     { "mem",    cmd_mem,    0 },
0091     { "data",   cmd_data,   0 },
0092     { "ftrace", cmd_ftrace, 0 },
0093     { "daemon", cmd_daemon, 0 },
0094     { "kwork",  cmd_kwork,  0 },
0095 };
0096 
0097 struct pager_config {
0098     const char *cmd;
0099     int val;
0100 };
0101 
0102 static int pager_command_config(const char *var, const char *value, void *data)
0103 {
0104     struct pager_config *c = data;
0105     if (strstarts(var, "pager.") && !strcmp(var + 6, c->cmd))
0106         c->val = perf_config_bool(var, value);
0107     return 0;
0108 }
0109 
0110 /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
0111 static int check_pager_config(const char *cmd)
0112 {
0113     int err;
0114     struct pager_config c;
0115     c.cmd = cmd;
0116     c.val = -1;
0117     err = perf_config(pager_command_config, &c);
0118     return err ?: c.val;
0119 }
0120 
0121 static int browser_command_config(const char *var, const char *value, void *data)
0122 {
0123     struct pager_config *c = data;
0124     if (strstarts(var, "tui.") && !strcmp(var + 4, c->cmd))
0125         c->val = perf_config_bool(var, value);
0126     if (strstarts(var, "gtk.") && !strcmp(var + 4, c->cmd))
0127         c->val = perf_config_bool(var, value) ? 2 : 0;
0128     return 0;
0129 }
0130 
0131 /*
0132  * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk",
0133  * and -1 for "not specified"
0134  */
0135 static int check_browser_config(const char *cmd)
0136 {
0137     int err;
0138     struct pager_config c;
0139     c.cmd = cmd;
0140     c.val = -1;
0141     err = perf_config(browser_command_config, &c);
0142     return err ?: c.val;
0143 }
0144 
0145 static void commit_pager_choice(void)
0146 {
0147     switch (use_pager) {
0148     case 0:
0149         setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
0150         break;
0151     case 1:
0152         /* setup_pager(); */
0153         break;
0154     default:
0155         break;
0156     }
0157 }
0158 
0159 struct option options[] = {
0160     OPT_ARGUMENT("help", "help"),
0161     OPT_ARGUMENT("version", "version"),
0162     OPT_ARGUMENT("exec-path", "exec-path"),
0163     OPT_ARGUMENT("html-path", "html-path"),
0164     OPT_ARGUMENT("paginate", "paginate"),
0165     OPT_ARGUMENT("no-pager", "no-pager"),
0166     OPT_ARGUMENT("debugfs-dir", "debugfs-dir"),
0167     OPT_ARGUMENT("buildid-dir", "buildid-dir"),
0168     OPT_ARGUMENT("list-cmds", "list-cmds"),
0169     OPT_ARGUMENT("list-opts", "list-opts"),
0170     OPT_ARGUMENT("debug", "debug"),
0171     OPT_END()
0172 };
0173 
0174 static int handle_options(const char ***argv, int *argc, int *envchanged)
0175 {
0176     int handled = 0;
0177 
0178     while (*argc > 0) {
0179         const char *cmd = (*argv)[0];
0180         if (cmd[0] != '-')
0181             break;
0182 
0183         /*
0184          * For legacy reasons, the "version" and "help"
0185          * commands can be written with "--" prepended
0186          * to make them look like flags.
0187          */
0188         if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
0189             break;
0190 
0191         /*
0192          * Shortcut for '-h' and '-v' options to invoke help
0193          * and version command.
0194          */
0195         if (!strcmp(cmd, "-h")) {
0196             (*argv)[0] = "--help";
0197             break;
0198         }
0199 
0200         if (!strcmp(cmd, "-v")) {
0201             (*argv)[0] = "--version";
0202             break;
0203         }
0204 
0205         if (!strcmp(cmd, "-vv")) {
0206             (*argv)[0] = "version";
0207             version_verbose = 1;
0208             break;
0209         }
0210 
0211         /*
0212          * Check remaining flags.
0213          */
0214         if (strstarts(cmd, CMD_EXEC_PATH)) {
0215             cmd += strlen(CMD_EXEC_PATH);
0216             if (*cmd == '=')
0217                 set_argv_exec_path(cmd + 1);
0218             else {
0219                 puts(get_argv_exec_path());
0220                 exit(0);
0221             }
0222         } else if (!strcmp(cmd, "--html-path")) {
0223             puts(system_path(PERF_HTML_PATH));
0224             exit(0);
0225         } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
0226             use_pager = 1;
0227         } else if (!strcmp(cmd, "--no-pager")) {
0228             use_pager = 0;
0229             if (envchanged)
0230                 *envchanged = 1;
0231         } else if (!strcmp(cmd, "--debugfs-dir")) {
0232             if (*argc < 2) {
0233                 fprintf(stderr, "No directory given for --debugfs-dir.\n");
0234                 usage(perf_usage_string);
0235             }
0236             tracing_path_set((*argv)[1]);
0237             if (envchanged)
0238                 *envchanged = 1;
0239             (*argv)++;
0240             (*argc)--;
0241         } else if (!strcmp(cmd, "--buildid-dir")) {
0242             if (*argc < 2) {
0243                 fprintf(stderr, "No directory given for --buildid-dir.\n");
0244                 usage(perf_usage_string);
0245             }
0246             set_buildid_dir((*argv)[1]);
0247             if (envchanged)
0248                 *envchanged = 1;
0249             (*argv)++;
0250             (*argc)--;
0251         } else if (strstarts(cmd, CMD_DEBUGFS_DIR)) {
0252             tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR));
0253             fprintf(stderr, "dir: %s\n", tracing_path_mount());
0254             if (envchanged)
0255                 *envchanged = 1;
0256         } else if (!strcmp(cmd, "--list-cmds")) {
0257             unsigned int i;
0258 
0259             for (i = 0; i < ARRAY_SIZE(commands); i++) {
0260                 struct cmd_struct *p = commands+i;
0261                 printf("%s ", p->cmd);
0262             }
0263             putchar('\n');
0264             exit(0);
0265         } else if (!strcmp(cmd, "--list-opts")) {
0266             unsigned int i;
0267 
0268             for (i = 0; i < ARRAY_SIZE(options)-1; i++) {
0269                 struct option *p = options+i;
0270                 printf("--%s ", p->long_name);
0271             }
0272             putchar('\n');
0273             exit(0);
0274         } else if (!strcmp(cmd, "--debug")) {
0275             if (*argc < 2) {
0276                 fprintf(stderr, "No variable specified for --debug.\n");
0277                 usage(perf_usage_string);
0278             }
0279             if (perf_debug_option((*argv)[1]))
0280                 usage(perf_usage_string);
0281 
0282             (*argv)++;
0283             (*argc)--;
0284         } else {
0285             fprintf(stderr, "Unknown option: %s\n", cmd);
0286             usage(perf_usage_string);
0287         }
0288 
0289         (*argv)++;
0290         (*argc)--;
0291         handled++;
0292     }
0293     return handled;
0294 }
0295 
0296 #define RUN_SETUP   (1<<0)
0297 #define USE_PAGER   (1<<1)
0298 
0299 static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
0300 {
0301     int status;
0302     struct stat st;
0303     char sbuf[STRERR_BUFSIZE];
0304 
0305     if (use_browser == -1)
0306         use_browser = check_browser_config(p->cmd);
0307 
0308     if (use_pager == -1 && p->option & RUN_SETUP)
0309         use_pager = check_pager_config(p->cmd);
0310     if (use_pager == -1 && p->option & USE_PAGER)
0311         use_pager = 1;
0312     commit_pager_choice();
0313 
0314     perf_env__init(&perf_env);
0315     perf_env__set_cmdline(&perf_env, argc, argv);
0316     status = p->fn(argc, argv);
0317     perf_config__exit();
0318     exit_browser(status);
0319     perf_env__exit(&perf_env);
0320     bpf__clear();
0321 
0322     if (status)
0323         return status & 0xff;
0324 
0325     /* Somebody closed stdout? */
0326     if (fstat(fileno(stdout), &st))
0327         return 0;
0328     /* Ignore write errors for pipes and sockets.. */
0329     if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
0330         return 0;
0331 
0332     status = 1;
0333     /* Check for ENOSPC and EIO errors.. */
0334     if (fflush(stdout)) {
0335         fprintf(stderr, "write failure on standard output: %s",
0336             str_error_r(errno, sbuf, sizeof(sbuf)));
0337         goto out;
0338     }
0339     if (ferror(stdout)) {
0340         fprintf(stderr, "unknown write failure on standard output");
0341         goto out;
0342     }
0343     if (fclose(stdout)) {
0344         fprintf(stderr, "close failed on standard output: %s",
0345             str_error_r(errno, sbuf, sizeof(sbuf)));
0346         goto out;
0347     }
0348     status = 0;
0349 out:
0350     return status;
0351 }
0352 
0353 static void handle_internal_command(int argc, const char **argv)
0354 {
0355     const char *cmd = argv[0];
0356     unsigned int i;
0357 
0358     /* Turn "perf cmd --help" into "perf help cmd" */
0359     if (argc > 1 && !strcmp(argv[1], "--help")) {
0360         argv[1] = argv[0];
0361         argv[0] = cmd = "help";
0362     }
0363 
0364     for (i = 0; i < ARRAY_SIZE(commands); i++) {
0365         struct cmd_struct *p = commands+i;
0366         if (p->fn == NULL)
0367             continue;
0368         if (strcmp(p->cmd, cmd))
0369             continue;
0370         exit(run_builtin(p, argc, argv));
0371     }
0372 }
0373 
0374 static void execv_dashed_external(const char **argv)
0375 {
0376     char *cmd;
0377     const char *tmp;
0378     int status;
0379 
0380     if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
0381         goto do_die;
0382 
0383     /*
0384      * argv[0] must be the perf command, but the argv array
0385      * belongs to the caller, and may be reused in
0386      * subsequent loop iterations. Save argv[0] and
0387      * restore it on error.
0388      */
0389     tmp = argv[0];
0390     argv[0] = cmd;
0391 
0392     /*
0393      * if we fail because the command is not found, it is
0394      * OK to return. Otherwise, we just pass along the status code.
0395      */
0396     status = run_command_v_opt(argv, 0);
0397     if (status != -ERR_RUN_COMMAND_EXEC) {
0398         if (IS_RUN_COMMAND_ERR(status)) {
0399 do_die:
0400             pr_err("FATAL: unable to run '%s'", argv[0]);
0401             status = -128;
0402         }
0403         exit(-status);
0404     }
0405     errno = ENOENT; /* as if we called execvp */
0406 
0407     argv[0] = tmp;
0408     zfree(&cmd);
0409 }
0410 
0411 static int run_argv(int *argcp, const char ***argv)
0412 {
0413     /* See if it's an internal command */
0414     handle_internal_command(*argcp, *argv);
0415 
0416     /* .. then try the external ones */
0417     execv_dashed_external(*argv);
0418     return 0;
0419 }
0420 
0421 static void pthread__block_sigwinch(void)
0422 {
0423     sigset_t set;
0424 
0425     sigemptyset(&set);
0426     sigaddset(&set, SIGWINCH);
0427     pthread_sigmask(SIG_BLOCK, &set, NULL);
0428 }
0429 
0430 void pthread__unblock_sigwinch(void)
0431 {
0432     sigset_t set;
0433 
0434     sigemptyset(&set);
0435     sigaddset(&set, SIGWINCH);
0436     pthread_sigmask(SIG_UNBLOCK, &set, NULL);
0437 }
0438 
0439 static int libperf_print(enum libperf_print_level level,
0440              const char *fmt, va_list ap)
0441 {
0442     return veprintf(level, verbose, fmt, ap);
0443 }
0444 
0445 int main(int argc, const char **argv)
0446 {
0447     int err;
0448     const char *cmd;
0449     char sbuf[STRERR_BUFSIZE];
0450 
0451     perf_debug_setup();
0452 
0453     /* libsubcmd init */
0454     exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
0455     pager_init(PERF_PAGER_ENVIRONMENT);
0456 
0457     libperf_init(libperf_print);
0458 
0459     cmd = extract_argv0_path(argv[0]);
0460     if (!cmd)
0461         cmd = "perf-help";
0462 
0463     srandom(time(NULL));
0464 
0465     /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
0466     config_exclusive_filename = getenv("PERF_CONFIG");
0467 
0468     err = perf_config(perf_default_config, NULL);
0469     if (err)
0470         return err;
0471     set_buildid_dir(NULL);
0472 
0473     /*
0474      * "perf-xxxx" is the same as "perf xxxx", but we obviously:
0475      *
0476      *  - cannot take flags in between the "perf" and the "xxxx".
0477      *  - cannot execute it externally (since it would just do
0478      *    the same thing over again)
0479      *
0480      * So we just directly call the internal command handler. If that one
0481      * fails to handle this, then maybe we just run a renamed perf binary
0482      * that contains a dash in its name. To handle this scenario, we just
0483      * fall through and ignore the "xxxx" part of the command string.
0484      */
0485     if (strstarts(cmd, "perf-")) {
0486         cmd += 5;
0487         argv[0] = cmd;
0488         handle_internal_command(argc, argv);
0489         /*
0490          * If the command is handled, the above function does not
0491          * return undo changes and fall through in such a case.
0492          */
0493         cmd -= 5;
0494         argv[0] = cmd;
0495     }
0496     if (strstarts(cmd, "trace")) {
0497 #if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT)
0498         setup_path();
0499         argv[0] = "trace";
0500         return cmd_trace(argc, argv);
0501 #else
0502         fprintf(stderr,
0503             "trace command not available: missing audit-libs devel package at build time.\n");
0504         goto out;
0505 #endif
0506     }
0507     /* Look for flags.. */
0508     argv++;
0509     argc--;
0510     handle_options(&argv, &argc, NULL);
0511     commit_pager_choice();
0512 
0513     if (argc > 0) {
0514         if (strstarts(argv[0], "--"))
0515             argv[0] += 2;
0516     } else {
0517         /* The user didn't specify a command; give them help */
0518         printf("\n usage: %s\n\n", perf_usage_string);
0519         list_common_cmds_help();
0520         printf("\n %s\n\n", perf_more_info_string);
0521         goto out;
0522     }
0523     cmd = argv[0];
0524 
0525     test_attr__init();
0526 
0527     /*
0528      * We use PATH to find perf commands, but we prepend some higher
0529      * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
0530      * environment, and the $(perfexecdir) from the Makefile at build
0531      * time.
0532      */
0533     setup_path();
0534     /*
0535      * Block SIGWINCH notifications so that the thread that wants it can
0536      * unblock and get syscalls like select interrupted instead of waiting
0537      * forever while the signal goes to some other non interested thread.
0538      */
0539     pthread__block_sigwinch();
0540 
0541     while (1) {
0542         static int done_help;
0543 
0544         run_argv(&argc, &argv);
0545 
0546         if (errno != ENOENT)
0547             break;
0548 
0549         if (!done_help) {
0550             cmd = argv[0] = help_unknown_cmd(cmd);
0551             done_help = 1;
0552         } else
0553             break;
0554     }
0555 
0556     fprintf(stderr, "Failed to run command '%s': %s\n",
0557         cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
0558 out:
0559     return 1;
0560 }