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