diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 104 |
1 files changed, 73 insertions, 31 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index f57035b89c15..ce304dfd962a 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -23,7 +23,6 @@ static char const *generate_script_lang; static bool debug_mode; static u64 last_timestamp; static u64 nr_unordered; -extern const struct option record_options[]; static bool no_callchain; static bool latency_format; static bool system_wide; @@ -44,6 +43,7 @@ enum perf_output_field { PERF_OUTPUT_ADDR = 1U << 10, PERF_OUTPUT_SYMOFFSET = 1U << 11, PERF_OUTPUT_SRCLINE = 1U << 12, + PERF_OUTPUT_PERIOD = 1U << 13, }; struct output_option { @@ -63,6 +63,7 @@ struct output_option { {.str = "addr", .field = PERF_OUTPUT_ADDR}, {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, + {.str = "period", .field = PERF_OUTPUT_PERIOD}, }; /* default set to maintain compatibility with current format */ @@ -80,7 +81,8 @@ static struct { .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | - PERF_OUTPUT_SYM | PERF_OUTPUT_DSO, + PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | + PERF_OUTPUT_PERIOD, .invalid_fields = PERF_OUTPUT_TRACE, }, @@ -91,7 +93,8 @@ static struct { .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | - PERF_OUTPUT_SYM | PERF_OUTPUT_DSO, + PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | + PERF_OUTPUT_PERIOD, .invalid_fields = PERF_OUTPUT_TRACE, }, @@ -110,7 +113,8 @@ static struct { .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | - PERF_OUTPUT_SYM | PERF_OUTPUT_DSO, + PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | + PERF_OUTPUT_PERIOD, .invalid_fields = PERF_OUTPUT_TRACE, }, @@ -184,10 +188,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", PERF_OUTPUT_IP)) return -EINVAL; - - if (!no_callchain && - !(attr->sample_type & PERF_SAMPLE_CALLCHAIN)) - symbol_conf.use_callchain = false; } if (PRINT_FIELD(ADDR) && @@ -233,6 +233,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, PERF_OUTPUT_CPU)) return -EINVAL; + if (PRINT_FIELD(PERIOD) && + perf_evsel__check_stype(evsel, PERF_SAMPLE_PERIOD, "PERIOD", + PERF_OUTPUT_PERIOD)) + return -EINVAL; + return 0; } @@ -290,6 +295,19 @@ static int perf_session__check_output_opt(struct perf_session *session) set_print_ip_opts(&evsel->attr); } + if (!no_callchain) { + bool use_callchain = false; + + evlist__for_each(session->evlist, evsel) { + if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { + use_callchain = true; + break; + } + } + if (!use_callchain) + symbol_conf.use_callchain = false; + } + /* * set default for tracepoints to print symbols only * if callchains are present @@ -360,7 +378,6 @@ static void print_sample_start(struct perf_sample *sample, static void print_sample_addr(union perf_event *event, struct perf_sample *sample, - struct machine *machine, struct thread *thread, struct perf_event_attr *attr) { @@ -371,7 +388,7 @@ static void print_sample_addr(union perf_event *event, if (!sample_addr_correlates_sym(attr)) return; - perf_event__preprocess_sample_addr(event, sample, machine, thread, &al); + perf_event__preprocess_sample_addr(event, sample, thread, &al); if (PRINT_FIELD(SYM)) { printf(" "); @@ -419,7 +436,7 @@ static void print_sample_bts(union perf_event *event, ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && !output[attr->type].user_set)) { printf(" => "); - print_sample_addr(event, sample, al->machine, thread, attr); + print_sample_addr(event, sample, thread, attr); } if (print_srcline_last) @@ -439,6 +456,9 @@ static void process_event(union perf_event *event, struct perf_sample *sample, print_sample_start(sample, thread, evsel); + if (PRINT_FIELD(PERIOD)) + printf("%10" PRIu64 " ", sample->period); + if (PRINT_FIELD(EVNAME)) { const char *evname = perf_evsel__name(evsel); printf("%s: ", evname ? evname : "[unknown]"); @@ -453,7 +473,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, event_format__print(evsel->tp_format, sample->cpu, sample->raw_data, sample->raw_size); if (PRINT_FIELD(ADDR)) - print_sample_addr(event, sample, al->machine, thread, attr); + print_sample_addr(event, sample, thread, attr); if (PRINT_FIELD(IP)) { if (!symbol_conf.use_callchain) @@ -476,6 +496,11 @@ static int default_start_script(const char *script __maybe_unused, return 0; } +static int default_flush_script(void) +{ + return 0; +} + static int default_stop_script(void) { return 0; @@ -489,6 +514,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused, static struct scripting_ops default_scripting_ops = { .start_script = default_start_script, + .flush_script = default_flush_script, .stop_script = default_stop_script, .process_event = process_event, .generate_script = default_generate_script, @@ -504,6 +530,11 @@ static void setup_scripting(void) scripting_ops = &default_scripting_ops; } +static int flush_scripting(void) +{ + return scripting_ops->flush_script(); +} + static int cleanup_scripting(void) { pr_debug("\nperf script stopped\n"); @@ -552,7 +583,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, scripting_ops->process_event(event, sample, evsel, thread, &al); - evsel->hists.stats.total_period += sample->period; return 0; } @@ -1471,12 +1501,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) bool show_full_info = false; bool header = false; bool header_only = false; + bool script_started = false; char *rec_script_path = NULL; char *rep_script_path = NULL; struct perf_session *session; char *script_path = NULL; const char **__argv; - int i, j, err; + int i, j, err = 0; struct perf_script script = { .tool = { .sample = process_sample_event, @@ -1488,7 +1519,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) .attr = process_attr, .tracing_data = perf_event__process_tracing_data, .build_id = perf_event__process_build_id, - .ordered_samples = true, + .ordered_events = true, .ordering_requires_timestamps = true, }, }; @@ -1523,7 +1554,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "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), + "addr,symoff,period", 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...]", @@ -1718,26 +1749,28 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) exit(-1); } - if (symbol__init() < 0) - return -1; if (!script_name) setup_pager(); session = perf_session__new(&file, false, &script.tool); if (session == NULL) - return -ENOMEM; + return -1; if (header || header_only) { perf_session__fprintf_info(session, stdout, show_full_info); if (header_only) - return 0; + goto out_delete; } + if (symbol__init(&session->header.env) < 0) + goto out_delete; + script.session = session; if (cpu_list) { - if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) - return -1; + err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); + if (err < 0) + goto out_delete; } if (!no_callchain) @@ -1752,53 +1785,62 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) if (output_set_by_user()) { fprintf(stderr, "custom fields not supported for generated scripts"); - return -1; + err = -EINVAL; + goto out_delete; } input = open(file.path, O_RDONLY); /* input_name */ if (input < 0) { + err = -errno; perror("failed to open file"); - return -1; + goto out_delete; } err = fstat(input, &perf_stat); if (err < 0) { perror("failed to stat file"); - return -1; + goto out_delete; } if (!perf_stat.st_size) { fprintf(stderr, "zero-sized file, nothing to do!\n"); - return 0; + goto out_delete; } scripting_ops = script_spec__lookup(generate_script_lang); if (!scripting_ops) { fprintf(stderr, "invalid language specifier"); - return -1; + err = -ENOENT; + goto out_delete; } err = scripting_ops->generate_script(session->tevent.pevent, "perf-script"); - goto out; + goto out_delete; } if (script_name) { err = scripting_ops->start_script(script_name, argc, argv); if (err) - goto out; + goto out_delete; pr_debug("perf script started with script %s\n\n", script_name); + script_started = true; } err = perf_session__check_output_opt(session); if (err < 0) - goto out; + goto out_delete; err = __cmd_script(&script); + flush_scripting(); + +out_delete: perf_session__delete(session); - cleanup_scripting(); + + if (script_started) + cleanup_scripting(); out: return err; } |