/* * perf.c * * Performance analysis utility. * * This is the main hub from which the sub-commands (perf stat, * perf top, perf record, perf report, etc.) are started.
*/ #include"builtin.h" #include"perf.h"
staticint handle_options(constchar ***argv, int *argc, int *envchanged)
{ int handled = 0;
while (*argc > 0) { constchar *cmd = (*argv)[0]; if (cmd[0] != '-') break;
/* * For legacy reasons, the "version" and "help" * commands can be written with "--" prepended * to make them look like flags.
*/ if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version")) break;
/* * Shortcut for '-h' and '-v' options to invoke help * and version command.
*/ if (!strcmp(cmd, "-h")) {
(*argv)[0] = "--help"; break;
}
if (!strcmp(cmd, "-v")) {
(*argv)[0] = "--version"; break;
}
/* * Check remaining flags.
*/ if (strstarts(cmd, CMD_EXEC_PATH)) {
cmd += strlen(CMD_EXEC_PATH); if (*cmd == '=')
set_argv_exec_path(cmd + 1); else {
puts(get_argv_exec_path()); exit(0);
}
} elseif (!strcmp(cmd, "--html-path")) {
puts(system_path(PERF_HTML_PATH)); exit(0);
} elseif (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
use_pager = 1;
} elseif (!strcmp(cmd, "--no-pager")) {
use_pager = 0; if (envchanged)
*envchanged = 1;
} elseif (!strcmp(cmd, "--debugfs-dir")) { if (*argc < 2) {
fprintf(stderr, "No directory given for --debugfs-dir.\n");
usage(perf_usage_string);
}
tracing_path_set((*argv)[1]); if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} elseif (!strcmp(cmd, "--buildid-dir")) { if (*argc < 2) {
fprintf(stderr, "No directory given for --buildid-dir.\n");
usage(perf_usage_string);
}
set_buildid_dir((*argv)[1]); if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} elseif (strstarts(cmd, CMD_DEBUGFS_DIR)) {
tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR));
fprintf(stderr, "dir: %s\n", tracing_path_mount()); if (envchanged)
*envchanged = 1;
} elseif (!strcmp(cmd, "--list-cmds")) { unsignedint i;
for (i = 0; i < ARRAY_SIZE(commands); i++) { struct cmd_struct *p = commands+i;
printf("%s ", p->cmd);
}
putchar('\n'); exit(0);
} elseif (!strcmp(cmd, "--list-opts")) { unsignedint i;
for (i = 0; i < ARRAY_SIZE(options)-1; i++) { struct option *p = options+i;
printf("--%s ", p->long_name);
}
putchar('\n'); exit(0);
} elseif (!strcmp(cmd, "--debug")) { if (*argc < 2) {
fprintf(stderr, "No variable specified for --debug.\n");
usage(perf_usage_string);
} if (perf_debug_option((*argv)[1]))
usage(perf_usage_string);
(*argv)++;
(*argc)--;
} elseif (!strcmp(cmd, "--debug-file")) { if (*argc < 2) {
fprintf(stderr, "No path given for --debug-file.\n");
usage(perf_usage_string);
}
if (set_debug_file((*argv)[1]))
usage(perf_usage_string);
status = p->fn(argc, argv);
perf_config__exit();
exit_browser(status);
if (status) return status & 0xff;
/* Somebody closed stdout? */ if (fstat(fileno(stdout), &st)) return 0; /* Ignore write errors for pipes and sockets.. */ if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) return 0;
status = 1; /* Check for ENOSPC and EIO errors.. */ if (fflush(stdout)) {
fprintf(stderr, "write failure on standard output: %s",
str_error_r(errno, sbuf, sizeof(sbuf))); goto out;
} if (ferror(stdout)) {
fprintf(stderr, "unknown write failure on standard output"); goto out;
} if (fclose(stdout)) {
fprintf(stderr, "close failed on standard output: %s",
str_error_r(errno, sbuf, sizeof(sbuf))); goto out;
}
status = 0;
out: return status;
}
/* Turn "perf cmd --help" into "perf help cmd" */ if (argc > 1 && !strcmp(argv[1], "--help")) {
argv[1] = argv[0];
argv[0] = cmd = "help";
}
for (i = 0; i < ARRAY_SIZE(commands); i++) { struct cmd_struct *p = commands+i; if (p->fn == NULL) continue; if (strcmp(p->cmd, cmd)) continue; exit(run_builtin(p, argc, argv));
}
}
staticvoid execv_dashed_external(constchar **argv)
{ char *cmd; constchar *tmp; int status;
if (asprintf(&cmd, "perf-%s", argv[0]) < 0) goto do_die;
/* * argv[0] must be the perf command, but the argv array * belongs to the caller, and may be reused in * subsequent loop iterations. Save argv[0] and * restore it on error.
*/
tmp = argv[0];
argv[0] = cmd;
/* * if we fail because the command is not found, it is * OK to return. Otherwise, we just pass along the status code.
*/
status = run_command_v_opt(argv, 0); if (status != -ERR_RUN_COMMAND_EXEC) { if (IS_RUN_COMMAND_ERR(status)) {
do_die:
pr_err("FATAL: unable to run '%s'", argv[0]);
status = -128;
} exit(-status);
}
errno = ENOENT; /* as if we called execvp */
argv[0] = tmp;
zfree(&cmd);
}
staticint run_argv(int *argcp, constchar ***argv)
{ /* See if it's an internal command */
handle_internal_command(*argcp, *argv);
/* .. then try the external ones */
execv_dashed_external(*argv); return 0;
}
cmd = extract_argv0_path(argv[0]); if (!cmd)
cmd = "perf-help";
srandom(time(NULL));
/* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
config_exclusive_filename = getenv("PERF_CONFIG");
err = perf_config(perf_default_config, NULL); if (err) return err;
set_buildid_dir(NULL);
/* * "perf-xxxx" is the same as "perf xxxx", but we obviously: * * - cannot take flags in between the "perf" and the "xxxx". * - cannot execute it externally (since it would just do * the same thing over again) * * So we just directly call the internal command handler. If that one * fails to handle this, then maybe we just run a renamed perf binary * that contains a dash in its name. To handle this scenario, we just * fall through and ignore the "xxxx" part of the command string.
*/ if (strstarts(cmd, "perf-")) {
cmd += 5;
argv[0] = cmd;
handle_internal_command(argc, argv); /* * If the command is handled, the above function does not * return undo changes and fall through in such a case.
*/
cmd -= 5;
argv[0] = cmd;
} if (strstarts(cmd, "trace")) { #ifndef HAVE_LIBTRACEEVENT
fprintf(stderr, "trace command not available: missing libtraceevent devel package at build time.\n"); goto out; #else
setup_path();
argv[0] = "trace"; return cmd_trace(argc, argv); #endif
} /* Look for flags.. */
argv++;
argc--;
handle_options(&argv, &argc, NULL);
commit_pager_choice();
if (argc > 0) { if (strstarts(argv[0], "--"))
argv[0] += 2;
} else { /* The user didn't specify a command; give them help */
printf("\n usage: %s\n\n", perf_usage_string);
list_common_cmds_help();
printf("\n %s\n\n", perf_more_info_string); goto out;
}
cmd = argv[0];
/* * We use PATH to find perf commands, but we prepend some higher * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH * environment, and the $(perfexecdir) from the Makefile at build * time.
*/
setup_path(); /* * Block SIGWINCH notifications so that the thread that wants it can * unblock and get syscalls like select interrupted instead of waiting * forever while the signal goes to some other non interested thread.
*/
pthread__block_sigwinch();
while (1) {
run_argv(&argc, &argv);
if (errno != ENOENT) break;
if (!done_help) { struct cmdnames main_cmds = {};
for (unsignedint i = 0; i < ARRAY_SIZE(commands); i++) {
add_cmdname(&main_cmds,
commands[i].cmd,
strlen(commands[i].cmd));
}
cmd = argv[0] = help_unknown_cmd(cmd, &main_cmds);
clean_cmdnames(&main_cmds);
done_help = 1; if (!cmd) break;
} else break;
}
if (cmd) {
fprintf(stderr, "Failed to run command '%s': %s\n",
cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
}
out: if (debug_fp)
fclose(debug_fp);
return 1;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.