aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-script.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r--tools/perf/builtin-script.c104
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;
}