diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 96 |
1 files changed, 70 insertions, 26 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index f57035b89c15..9708a1290571 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -44,6 +44,7 @@ enum perf_output_field { | |||
44 | PERF_OUTPUT_ADDR = 1U << 10, | 44 | PERF_OUTPUT_ADDR = 1U << 10, |
45 | PERF_OUTPUT_SYMOFFSET = 1U << 11, | 45 | PERF_OUTPUT_SYMOFFSET = 1U << 11, |
46 | PERF_OUTPUT_SRCLINE = 1U << 12, | 46 | PERF_OUTPUT_SRCLINE = 1U << 12, |
47 | PERF_OUTPUT_PERIOD = 1U << 13, | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | struct output_option { | 50 | struct output_option { |
@@ -63,6 +64,7 @@ struct output_option { | |||
63 | {.str = "addr", .field = PERF_OUTPUT_ADDR}, | 64 | {.str = "addr", .field = PERF_OUTPUT_ADDR}, |
64 | {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, | 65 | {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, |
65 | {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, | 66 | {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, |
67 | {.str = "period", .field = PERF_OUTPUT_PERIOD}, | ||
66 | }; | 68 | }; |
67 | 69 | ||
68 | /* default set to maintain compatibility with current format */ | 70 | /* default set to maintain compatibility with current format */ |
@@ -80,7 +82,8 @@ static struct { | |||
80 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | | 82 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | |
81 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | 83 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | |
82 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | 84 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | |
83 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO, | 85 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | |
86 | PERF_OUTPUT_PERIOD, | ||
84 | 87 | ||
85 | .invalid_fields = PERF_OUTPUT_TRACE, | 88 | .invalid_fields = PERF_OUTPUT_TRACE, |
86 | }, | 89 | }, |
@@ -91,7 +94,8 @@ static struct { | |||
91 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | | 94 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | |
92 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | 95 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | |
93 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | 96 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | |
94 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO, | 97 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | |
98 | PERF_OUTPUT_PERIOD, | ||
95 | 99 | ||
96 | .invalid_fields = PERF_OUTPUT_TRACE, | 100 | .invalid_fields = PERF_OUTPUT_TRACE, |
97 | }, | 101 | }, |
@@ -110,7 +114,8 @@ static struct { | |||
110 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | | 114 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | |
111 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | 115 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | |
112 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | 116 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | |
113 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO, | 117 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | |
118 | PERF_OUTPUT_PERIOD, | ||
114 | 119 | ||
115 | .invalid_fields = PERF_OUTPUT_TRACE, | 120 | .invalid_fields = PERF_OUTPUT_TRACE, |
116 | }, | 121 | }, |
@@ -184,10 +189,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
184 | if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", | 189 | if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", |
185 | PERF_OUTPUT_IP)) | 190 | PERF_OUTPUT_IP)) |
186 | return -EINVAL; | 191 | return -EINVAL; |
187 | |||
188 | if (!no_callchain && | ||
189 | !(attr->sample_type & PERF_SAMPLE_CALLCHAIN)) | ||
190 | symbol_conf.use_callchain = false; | ||
191 | } | 192 | } |
192 | 193 | ||
193 | if (PRINT_FIELD(ADDR) && | 194 | if (PRINT_FIELD(ADDR) && |
@@ -233,6 +234,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
233 | PERF_OUTPUT_CPU)) | 234 | PERF_OUTPUT_CPU)) |
234 | return -EINVAL; | 235 | return -EINVAL; |
235 | 236 | ||
237 | if (PRINT_FIELD(PERIOD) && | ||
238 | perf_evsel__check_stype(evsel, PERF_SAMPLE_PERIOD, "PERIOD", | ||
239 | PERF_OUTPUT_PERIOD)) | ||
240 | return -EINVAL; | ||
241 | |||
236 | return 0; | 242 | return 0; |
237 | } | 243 | } |
238 | 244 | ||
@@ -290,6 +296,19 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
290 | set_print_ip_opts(&evsel->attr); | 296 | set_print_ip_opts(&evsel->attr); |
291 | } | 297 | } |
292 | 298 | ||
299 | if (!no_callchain) { | ||
300 | bool use_callchain = false; | ||
301 | |||
302 | evlist__for_each(session->evlist, evsel) { | ||
303 | if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
304 | use_callchain = true; | ||
305 | break; | ||
306 | } | ||
307 | } | ||
308 | if (!use_callchain) | ||
309 | symbol_conf.use_callchain = false; | ||
310 | } | ||
311 | |||
293 | /* | 312 | /* |
294 | * set default for tracepoints to print symbols only | 313 | * set default for tracepoints to print symbols only |
295 | * if callchains are present | 314 | * if callchains are present |
@@ -439,6 +458,9 @@ static void process_event(union perf_event *event, struct perf_sample *sample, | |||
439 | 458 | ||
440 | print_sample_start(sample, thread, evsel); | 459 | print_sample_start(sample, thread, evsel); |
441 | 460 | ||
461 | if (PRINT_FIELD(PERIOD)) | ||
462 | printf("%10" PRIu64 " ", sample->period); | ||
463 | |||
442 | if (PRINT_FIELD(EVNAME)) { | 464 | if (PRINT_FIELD(EVNAME)) { |
443 | const char *evname = perf_evsel__name(evsel); | 465 | const char *evname = perf_evsel__name(evsel); |
444 | printf("%s: ", evname ? evname : "[unknown]"); | 466 | printf("%s: ", evname ? evname : "[unknown]"); |
@@ -476,6 +498,11 @@ static int default_start_script(const char *script __maybe_unused, | |||
476 | return 0; | 498 | return 0; |
477 | } | 499 | } |
478 | 500 | ||
501 | static int default_flush_script(void) | ||
502 | { | ||
503 | return 0; | ||
504 | } | ||
505 | |||
479 | static int default_stop_script(void) | 506 | static int default_stop_script(void) |
480 | { | 507 | { |
481 | return 0; | 508 | return 0; |
@@ -489,6 +516,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused, | |||
489 | 516 | ||
490 | static struct scripting_ops default_scripting_ops = { | 517 | static struct scripting_ops default_scripting_ops = { |
491 | .start_script = default_start_script, | 518 | .start_script = default_start_script, |
519 | .flush_script = default_flush_script, | ||
492 | .stop_script = default_stop_script, | 520 | .stop_script = default_stop_script, |
493 | .process_event = process_event, | 521 | .process_event = process_event, |
494 | .generate_script = default_generate_script, | 522 | .generate_script = default_generate_script, |
@@ -504,6 +532,11 @@ static void setup_scripting(void) | |||
504 | scripting_ops = &default_scripting_ops; | 532 | scripting_ops = &default_scripting_ops; |
505 | } | 533 | } |
506 | 534 | ||
535 | static int flush_scripting(void) | ||
536 | { | ||
537 | return scripting_ops->flush_script(); | ||
538 | } | ||
539 | |||
507 | static int cleanup_scripting(void) | 540 | static int cleanup_scripting(void) |
508 | { | 541 | { |
509 | pr_debug("\nperf script stopped\n"); | 542 | pr_debug("\nperf script stopped\n"); |
@@ -552,7 +585,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
552 | 585 | ||
553 | scripting_ops->process_event(event, sample, evsel, thread, &al); | 586 | scripting_ops->process_event(event, sample, evsel, thread, &al); |
554 | 587 | ||
555 | evsel->hists.stats.total_period += sample->period; | ||
556 | return 0; | 588 | return 0; |
557 | } | 589 | } |
558 | 590 | ||
@@ -1471,12 +1503,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1471 | bool show_full_info = false; | 1503 | bool show_full_info = false; |
1472 | bool header = false; | 1504 | bool header = false; |
1473 | bool header_only = false; | 1505 | bool header_only = false; |
1506 | bool script_started = false; | ||
1474 | char *rec_script_path = NULL; | 1507 | char *rec_script_path = NULL; |
1475 | char *rep_script_path = NULL; | 1508 | char *rep_script_path = NULL; |
1476 | struct perf_session *session; | 1509 | struct perf_session *session; |
1477 | char *script_path = NULL; | 1510 | char *script_path = NULL; |
1478 | const char **__argv; | 1511 | const char **__argv; |
1479 | int i, j, err; | 1512 | int i, j, err = 0; |
1480 | struct perf_script script = { | 1513 | struct perf_script script = { |
1481 | .tool = { | 1514 | .tool = { |
1482 | .sample = process_sample_event, | 1515 | .sample = process_sample_event, |
@@ -1488,7 +1521,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1488 | .attr = process_attr, | 1521 | .attr = process_attr, |
1489 | .tracing_data = perf_event__process_tracing_data, | 1522 | .tracing_data = perf_event__process_tracing_data, |
1490 | .build_id = perf_event__process_build_id, | 1523 | .build_id = perf_event__process_build_id, |
1491 | .ordered_samples = true, | 1524 | .ordered_events = true, |
1492 | .ordering_requires_timestamps = true, | 1525 | .ordering_requires_timestamps = true, |
1493 | }, | 1526 | }, |
1494 | }; | 1527 | }; |
@@ -1523,7 +1556,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1523 | "comma separated output fields prepend with 'type:'. " | 1556 | "comma separated output fields prepend with 'type:'. " |
1524 | "Valid types: hw,sw,trace,raw. " | 1557 | "Valid types: hw,sw,trace,raw. " |
1525 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 1558 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
1526 | "addr,symoff", parse_output_fields), | 1559 | "addr,symoff,period", parse_output_fields), |
1527 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1560 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1528 | "system-wide collection from all CPUs"), | 1561 | "system-wide collection from all CPUs"), |
1529 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | 1562 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
@@ -1718,26 +1751,28 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1718 | exit(-1); | 1751 | exit(-1); |
1719 | } | 1752 | } |
1720 | 1753 | ||
1721 | if (symbol__init() < 0) | ||
1722 | return -1; | ||
1723 | if (!script_name) | 1754 | if (!script_name) |
1724 | setup_pager(); | 1755 | setup_pager(); |
1725 | 1756 | ||
1726 | session = perf_session__new(&file, false, &script.tool); | 1757 | session = perf_session__new(&file, false, &script.tool); |
1727 | if (session == NULL) | 1758 | if (session == NULL) |
1728 | return -ENOMEM; | 1759 | return -1; |
1729 | 1760 | ||
1730 | if (header || header_only) { | 1761 | if (header || header_only) { |
1731 | perf_session__fprintf_info(session, stdout, show_full_info); | 1762 | perf_session__fprintf_info(session, stdout, show_full_info); |
1732 | if (header_only) | 1763 | if (header_only) |
1733 | return 0; | 1764 | goto out_delete; |
1734 | } | 1765 | } |
1735 | 1766 | ||
1767 | if (symbol__init(&session->header.env) < 0) | ||
1768 | goto out_delete; | ||
1769 | |||
1736 | script.session = session; | 1770 | script.session = session; |
1737 | 1771 | ||
1738 | if (cpu_list) { | 1772 | if (cpu_list) { |
1739 | if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) | 1773 | err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); |
1740 | return -1; | 1774 | if (err < 0) |
1775 | goto out_delete; | ||
1741 | } | 1776 | } |
1742 | 1777 | ||
1743 | if (!no_callchain) | 1778 | if (!no_callchain) |
@@ -1752,53 +1787,62 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1752 | if (output_set_by_user()) { | 1787 | if (output_set_by_user()) { |
1753 | fprintf(stderr, | 1788 | fprintf(stderr, |
1754 | "custom fields not supported for generated scripts"); | 1789 | "custom fields not supported for generated scripts"); |
1755 | return -1; | 1790 | err = -EINVAL; |
1791 | goto out_delete; | ||
1756 | } | 1792 | } |
1757 | 1793 | ||
1758 | input = open(file.path, O_RDONLY); /* input_name */ | 1794 | input = open(file.path, O_RDONLY); /* input_name */ |
1759 | if (input < 0) { | 1795 | if (input < 0) { |
1796 | err = -errno; | ||
1760 | perror("failed to open file"); | 1797 | perror("failed to open file"); |
1761 | return -1; | 1798 | goto out_delete; |
1762 | } | 1799 | } |
1763 | 1800 | ||
1764 | err = fstat(input, &perf_stat); | 1801 | err = fstat(input, &perf_stat); |
1765 | if (err < 0) { | 1802 | if (err < 0) { |
1766 | perror("failed to stat file"); | 1803 | perror("failed to stat file"); |
1767 | return -1; | 1804 | goto out_delete; |
1768 | } | 1805 | } |
1769 | 1806 | ||
1770 | if (!perf_stat.st_size) { | 1807 | if (!perf_stat.st_size) { |
1771 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | 1808 | fprintf(stderr, "zero-sized file, nothing to do!\n"); |
1772 | return 0; | 1809 | goto out_delete; |
1773 | } | 1810 | } |
1774 | 1811 | ||
1775 | scripting_ops = script_spec__lookup(generate_script_lang); | 1812 | scripting_ops = script_spec__lookup(generate_script_lang); |
1776 | if (!scripting_ops) { | 1813 | if (!scripting_ops) { |
1777 | fprintf(stderr, "invalid language specifier"); | 1814 | fprintf(stderr, "invalid language specifier"); |
1778 | return -1; | 1815 | err = -ENOENT; |
1816 | goto out_delete; | ||
1779 | } | 1817 | } |
1780 | 1818 | ||
1781 | err = scripting_ops->generate_script(session->tevent.pevent, | 1819 | err = scripting_ops->generate_script(session->tevent.pevent, |
1782 | "perf-script"); | 1820 | "perf-script"); |
1783 | goto out; | 1821 | goto out_delete; |
1784 | } | 1822 | } |
1785 | 1823 | ||
1786 | if (script_name) { | 1824 | if (script_name) { |
1787 | err = scripting_ops->start_script(script_name, argc, argv); | 1825 | err = scripting_ops->start_script(script_name, argc, argv); |
1788 | if (err) | 1826 | if (err) |
1789 | goto out; | 1827 | goto out_delete; |
1790 | pr_debug("perf script started with script %s\n\n", script_name); | 1828 | pr_debug("perf script started with script %s\n\n", script_name); |
1829 | script_started = true; | ||
1791 | } | 1830 | } |
1792 | 1831 | ||
1793 | 1832 | ||
1794 | err = perf_session__check_output_opt(session); | 1833 | err = perf_session__check_output_opt(session); |
1795 | if (err < 0) | 1834 | if (err < 0) |
1796 | goto out; | 1835 | goto out_delete; |
1797 | 1836 | ||
1798 | err = __cmd_script(&script); | 1837 | err = __cmd_script(&script); |
1799 | 1838 | ||
1839 | flush_scripting(); | ||
1840 | |||
1841 | out_delete: | ||
1800 | perf_session__delete(session); | 1842 | perf_session__delete(session); |
1801 | cleanup_scripting(); | 1843 | |
1844 | if (script_started) | ||
1845 | cleanup_scripting(); | ||
1802 | out: | 1846 | out: |
1803 | return err; | 1847 | return err; |
1804 | } | 1848 | } |