Newer
Older
scripts_dir = opendir(scripts_path);
if (!scripts_dir)
return -1;
for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
lang_dirent.d_name);
lang_dir = opendir(lang_path);
if (!lang_dir)
continue;
for_each_script(lang_path, lang_dir, script_dirent, script_next) {
script_root = get_script_root(&script_dirent, REPORT_SUFFIX);
if (script_root) {
desc = script_desc__findnew(script_root);
snprintf(script_path, MAXPATHLEN, "%s/%s",
lang_path, script_dirent.d_name);
read_script_info(desc, script_path);
free(script_root);
}
}
}
fprintf(stdout, "List of available trace scripts:\n");
list_for_each_entry(desc, &script_descs, node) {
sprintf(first_half, "%s %s", desc->name,
desc->args ? desc->args : "");
fprintf(stdout, " %-36s %s\n", first_half,
desc->half_liner ? desc->half_liner : "");
}
exit(0);
}
static char *get_script_path(const char *script_root, const char *suffix)
{
struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
char scripts_path[MAXPATHLEN];
char script_path[MAXPATHLEN];
DIR *scripts_dir, *lang_dir;
char lang_path[MAXPATHLEN];
char *__script_root;
snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
scripts_dir = opendir(scripts_path);
if (!scripts_dir)
return NULL;
for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
lang_dirent.d_name);
lang_dir = opendir(lang_path);
if (!lang_dir)
continue;
for_each_script(lang_path, lang_dir, script_dirent, script_next) {
__script_root = get_script_root(&script_dirent, suffix);
if (__script_root && !strcmp(script_root, __script_root)) {
free(__script_root);
closedir(lang_dir);
closedir(scripts_dir);
snprintf(script_path, MAXPATHLEN, "%s/%s",
lang_path, script_dirent.d_name);
return strdup(script_path);
}
free(__script_root);
}
return NULL;
static bool is_top_script(const char *script_path)
{
return ends_with(script_path, "top") == NULL ? false : true;
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
}
static int has_required_arg(char *script_path)
{
struct script_desc *desc;
int n_args = 0;
char *p;
desc = script_desc__new(NULL);
if (read_script_info(desc, script_path))
goto out;
if (!desc->args)
goto out;
for (p = desc->args; *p; p++)
if (*p == '<')
n_args++;
out:
script_desc__delete(desc);
return n_args;
}
static const char * const script_usage[] = {
"perf script [<options>]",
"perf script [<options>] record <script> [<record-options>] <command>",
"perf script [<options>] report <script> [script-args]",
"perf script [<options>] <script> [<record-options>] <command>",
"perf script [<options>] <top-script> [script-args]",
NULL
};
static const struct option options[] = {
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
"dump raw trace in ASCII"),

Ian Munsie
committed
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show symbol address, etc)"),
OPT_BOOLEAN('L', "Latency", &latency_format,
"show latency attributes (irqs/preemption disabled, etc)"),
OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
list_available_scripts),
OPT_CALLBACK('s', "script", NULL, "name",
"script file name (lang:script name, script name, or *)",
parse_scriptname),
OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
"generate perf-script.xx script in specified language"),
OPT_STRING('i', "input", &input_name, "file",
"input file name"),
OPT_BOOLEAN('d', "debug-mode", &debug_mode,
"do various checks like samples ordering and lost events"),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"),
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
"file", "kallsyms pathname"),
OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
"When printing symbols do not display call chain"),
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
"Look for files with symbols relative to this directory"),
OPT_CALLBACK('f', "fields", NULL, "str",
"comma separated output fields prepend with 'type:'. "
"Valid types: hw,sw,trace,raw. "
"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
"addr,symoff",
parse_output_fields),
OPT_BOOLEAN('a', "all-cpus", &system_wide,
"system-wide collection from all CPUs"),
OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
"only consider these symbols"),
OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
"only display events for these comms"),
OPT_BOOLEAN('I', "show-info", &show_full_info,
"display extended information from perf.data file"),
OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
"Show the path of [kernel.kallsyms]"),
static int have_cmd(int argc, const char **argv)
{
char **__argv = malloc(sizeof(const char *) * argc);
if (!__argv) {
pr_err("malloc failed\n");
return -1;
}
memcpy(__argv, argv, sizeof(const char *) * argc);
argc = parse_options(argc, (const char **)__argv, record_options,
NULL, PARSE_OPT_STOP_AT_NON_OPTION);
free(__argv);
system_wide = (argc == 0);
return 0;
int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
char *rec_script_path = NULL;
char *rep_script_path = NULL;

Arnaldo Carvalho de Melo
committed
struct perf_session *session;
const char **__argv;
argc = parse_options(argc, argv, options, script_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
if (!rec_script_path)
return cmd_record(argc, argv, NULL);
if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
if (!rep_script_path) {
"Please specify a valid report script"
"(see 'perf script -l' for listing)\n");
return -1;
}
}
/* make sure PERF_EXEC_PATH is set for scripts */
perf_set_argv_exec_path(perf_exec_path());
if (argc && !script_name && !rec_script_path && !rep_script_path) {
int live_pipe[2];
pid_t pid;
rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
if (!rec_script_path && !rep_script_path) {
fprintf(stderr, " Couldn't find script %s\n\n See perf"
" script -l for available scripts.\n", argv[0]);
usage_with_options(script_usage, options);
}
if (is_top_script(argv[0])) {
rep_args = argc - 1;
} else {
int rec_args;
rep_args = has_required_arg(rep_script_path);
rec_args = (argc - 1) - rep_args;
if (rec_args < 0) {
fprintf(stderr, " %s script requires options."
"\n\n See perf script -l for available "
"scripts and options.\n", argv[0]);
usage_with_options(script_usage, options);
}
if (pipe(live_pipe) < 0) {
perror("failed to create pipe");
}
pid = fork();
if (pid < 0) {
perror("failed to fork");
}
if (!pid) {
dup2(live_pipe[1], 1);
close(live_pipe[0]);
if (is_top_script(argv[0])) {
system_wide = true;
} else if (!system_wide) {
if (have_cmd(argc - rep_args, &argv[rep_args]) != 0) {
err = -1;
goto out;
}
__argv = malloc((argc + 6) * sizeof(const char *));
if (!__argv) {
pr_err("malloc failed\n");
err = -ENOMEM;
goto out;
}
__argv[j++] = "/bin/sh";
__argv[j++] = rec_script_path;
if (system_wide)
__argv[j++] = "-a";
__argv[j++] = "-q";
__argv[j++] = "-o";
__argv[j++] = "-";
for (i = rep_args + 1; i < argc; i++)
__argv[j++] = argv[i];
__argv[j++] = NULL;
execvp("/bin/sh", (char **)__argv);
free(__argv);
exit(-1);
}
dup2(live_pipe[0], 0);
close(live_pipe[1]);
__argv = malloc((argc + 4) * sizeof(const char *));
if (!__argv) {
pr_err("malloc failed\n");
err = -ENOMEM;
goto out;
}
j = 0;
__argv[j++] = "/bin/sh";
__argv[j++] = rep_script_path;
for (i = 1; i < rep_args + 1; i++)
__argv[j++] = argv[i];
__argv[j++] = "-i";
__argv[j++] = "-";
__argv[j++] = NULL;
execvp("/bin/sh", (char **)__argv);
free(__argv);
exit(-1);
}
if (rec_script_path)
script_path = rec_script_path;
if (rep_script_path)
script_path = rep_script_path;
if (script_path) {
j = 0;
if (!rec_script_path)
system_wide = false;
else if (!system_wide) {
if (have_cmd(argc - 1, &argv[1]) != 0) {
err = -1;
goto out;
}
}
__argv = malloc((argc + 2) * sizeof(const char *));
if (!__argv) {
pr_err("malloc failed\n");
err = -ENOMEM;
goto out;
}
__argv[j++] = "/bin/sh";
__argv[j++] = script_path;
if (system_wide)
__argv[j++] = "-a";
__argv[j++] = argv[i];
__argv[j++] = NULL;
execvp("/bin/sh", (char **)__argv);
free(__argv);
if (symbol__init() < 0)
return -1;
if (!script_name)
setup_pager();
session = perf_session__new(input_name, O_RDONLY, 0, false,

Arnaldo Carvalho de Melo
committed
if (session == NULL)
return -ENOMEM;
if (cpu_list) {
if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
return -1;
}
perf_session__fprintf_info(session, stdout, show_full_info);
symbol_conf.use_callchain = true;
else
symbol_conf.use_callchain = false;
if (generate_script_lang) {
struct stat perf_stat;
if (output_set_by_user()) {
fprintf(stderr,
"custom fields not supported for generated scripts");
return -1;
}
input = open(session->filename, O_RDONLY); /* input_name */
if (input < 0) {
perror("failed to open file");
}
err = fstat(input, &perf_stat);
if (err < 0) {
perror("failed to stat file");
}
if (!perf_stat.st_size) {
fprintf(stderr, "zero-sized file, nothing to do!\n");
}
scripting_ops = script_spec__lookup(generate_script_lang);
if (!scripting_ops) {
fprintf(stderr, "invalid language specifier");
return -1;
}
err = scripting_ops->generate_script(session->pevent,
"perf-script");
goto out;
}
if (script_name) {
err = scripting_ops->start_script(script_name, argc, argv);
pr_debug("perf script started with script %s\n\n", script_name);
err = perf_session__check_output_opt(session);
if (err < 0)
goto out;

Arnaldo Carvalho de Melo
committed
perf_session__delete(session);
cleanup_scripting();
out:
return err;