0001
0002
0003
0004
0005
0006
0007
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
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
0133
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
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
0185
0186
0187
0188 if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
0189 break;
0190
0191
0192
0193
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
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
0326 if (fstat(fileno(stdout), &st))
0327 return 0;
0328
0329 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
0330 return 0;
0331
0332 status = 1;
0333
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
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
0385
0386
0387
0388
0389 tmp = argv[0];
0390 argv[0] = cmd;
0391
0392
0393
0394
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;
0406
0407 argv[0] = tmp;
0408 zfree(&cmd);
0409 }
0410
0411 static int run_argv(int *argcp, const char ***argv)
0412 {
0413
0414 handle_internal_command(*argcp, *argv);
0415
0416
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
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
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
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485 if (strstarts(cmd, "perf-")) {
0486 cmd += 5;
0487 argv[0] = cmd;
0488 handle_internal_command(argc, argv);
0489
0490
0491
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
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
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
0529
0530
0531
0532
0533 setup_path();
0534
0535
0536
0537
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 }