diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 266 |
1 files changed, 229 insertions, 37 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 9b43bda45a41..ab19a6ee4093 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -22,9 +22,11 @@ | |||
22 | #include "util/cpumap.h" | 22 | #include "util/cpumap.h" |
23 | #include "util/thread_map.h" | 23 | #include "util/thread_map.h" |
24 | #include "util/stat.h" | 24 | #include "util/stat.h" |
25 | #include "util/color.h" | ||
25 | #include "util/string2.h" | 26 | #include "util/string2.h" |
26 | #include "util/thread-stack.h" | 27 | #include "util/thread-stack.h" |
27 | #include "util/time-utils.h" | 28 | #include "util/time-utils.h" |
29 | #include "util/path.h" | ||
28 | #include "print_binary.h" | 30 | #include "print_binary.h" |
29 | #include <linux/bitmap.h> | 31 | #include <linux/bitmap.h> |
30 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
@@ -40,6 +42,7 @@ | |||
40 | #include <sys/param.h> | 42 | #include <sys/param.h> |
41 | #include <sys/types.h> | 43 | #include <sys/types.h> |
42 | #include <sys/stat.h> | 44 | #include <sys/stat.h> |
45 | #include <fcntl.h> | ||
43 | #include <unistd.h> | 46 | #include <unistd.h> |
44 | 47 | ||
45 | #include "sane_ctype.h" | 48 | #include "sane_ctype.h" |
@@ -90,6 +93,8 @@ enum perf_output_field { | |||
90 | PERF_OUTPUT_SYNTH = 1U << 25, | 93 | PERF_OUTPUT_SYNTH = 1U << 25, |
91 | PERF_OUTPUT_PHYS_ADDR = 1U << 26, | 94 | PERF_OUTPUT_PHYS_ADDR = 1U << 26, |
92 | PERF_OUTPUT_UREGS = 1U << 27, | 95 | PERF_OUTPUT_UREGS = 1U << 27, |
96 | PERF_OUTPUT_METRIC = 1U << 28, | ||
97 | PERF_OUTPUT_MISC = 1U << 29, | ||
93 | }; | 98 | }; |
94 | 99 | ||
95 | struct output_option { | 100 | struct output_option { |
@@ -124,6 +129,8 @@ struct output_option { | |||
124 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, | 129 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, |
125 | {.str = "synth", .field = PERF_OUTPUT_SYNTH}, | 130 | {.str = "synth", .field = PERF_OUTPUT_SYNTH}, |
126 | {.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR}, | 131 | {.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR}, |
132 | {.str = "metric", .field = PERF_OUTPUT_METRIC}, | ||
133 | {.str = "misc", .field = PERF_OUTPUT_MISC}, | ||
127 | }; | 134 | }; |
128 | 135 | ||
129 | enum { | 136 | enum { |
@@ -215,12 +222,20 @@ struct perf_evsel_script { | |||
215 | char *filename; | 222 | char *filename; |
216 | FILE *fp; | 223 | FILE *fp; |
217 | u64 samples; | 224 | u64 samples; |
225 | /* For metric output */ | ||
226 | u64 val; | ||
227 | int gnum; | ||
218 | }; | 228 | }; |
219 | 229 | ||
230 | static inline struct perf_evsel_script *evsel_script(struct perf_evsel *evsel) | ||
231 | { | ||
232 | return (struct perf_evsel_script *)evsel->priv; | ||
233 | } | ||
234 | |||
220 | static struct perf_evsel_script *perf_evsel_script__new(struct perf_evsel *evsel, | 235 | static struct perf_evsel_script *perf_evsel_script__new(struct perf_evsel *evsel, |
221 | struct perf_data *data) | 236 | struct perf_data *data) |
222 | { | 237 | { |
223 | struct perf_evsel_script *es = malloc(sizeof(*es)); | 238 | struct perf_evsel_script *es = zalloc(sizeof(*es)); |
224 | 239 | ||
225 | if (es != NULL) { | 240 | if (es != NULL) { |
226 | if (asprintf(&es->filename, "%s.%s.dump", data->file.path, perf_evsel__name(evsel)) < 0) | 241 | if (asprintf(&es->filename, "%s.%s.dump", data->file.path, perf_evsel__name(evsel)) < 0) |
@@ -228,7 +243,6 @@ static struct perf_evsel_script *perf_evsel_script__new(struct perf_evsel *evsel | |||
228 | es->fp = fopen(es->filename, "w"); | 243 | es->fp = fopen(es->filename, "w"); |
229 | if (es->fp == NULL) | 244 | if (es->fp == NULL) |
230 | goto out_free_filename; | 245 | goto out_free_filename; |
231 | es->samples = 0; | ||
232 | } | 246 | } |
233 | 247 | ||
234 | return es; | 248 | return es; |
@@ -423,11 +437,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
423 | PERF_OUTPUT_CPU, allow_user_set)) | 437 | PERF_OUTPUT_CPU, allow_user_set)) |
424 | return -EINVAL; | 438 | return -EINVAL; |
425 | 439 | ||
426 | if (PRINT_FIELD(PERIOD) && | ||
427 | perf_evsel__check_stype(evsel, PERF_SAMPLE_PERIOD, "PERIOD", | ||
428 | PERF_OUTPUT_PERIOD)) | ||
429 | return -EINVAL; | ||
430 | |||
431 | if (PRINT_FIELD(IREGS) && | 440 | if (PRINT_FIELD(IREGS) && |
432 | perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS", | 441 | perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS", |
433 | PERF_OUTPUT_IREGS)) | 442 | PERF_OUTPUT_IREGS)) |
@@ -588,7 +597,8 @@ static int perf_sample__fprintf_uregs(struct perf_sample *sample, | |||
588 | 597 | ||
589 | static int perf_sample__fprintf_start(struct perf_sample *sample, | 598 | static int perf_sample__fprintf_start(struct perf_sample *sample, |
590 | struct thread *thread, | 599 | struct thread *thread, |
591 | struct perf_evsel *evsel, FILE *fp) | 600 | struct perf_evsel *evsel, |
601 | u32 type, FILE *fp) | ||
592 | { | 602 | { |
593 | struct perf_event_attr *attr = &evsel->attr; | 603 | struct perf_event_attr *attr = &evsel->attr; |
594 | unsigned long secs; | 604 | unsigned long secs; |
@@ -618,6 +628,47 @@ static int perf_sample__fprintf_start(struct perf_sample *sample, | |||
618 | printed += fprintf(fp, "[%03d] ", sample->cpu); | 628 | printed += fprintf(fp, "[%03d] ", sample->cpu); |
619 | } | 629 | } |
620 | 630 | ||
631 | if (PRINT_FIELD(MISC)) { | ||
632 | int ret = 0; | ||
633 | |||
634 | #define has(m) \ | ||
635 | (sample->misc & PERF_RECORD_MISC_##m) == PERF_RECORD_MISC_##m | ||
636 | |||
637 | if (has(KERNEL)) | ||
638 | ret += fprintf(fp, "K"); | ||
639 | if (has(USER)) | ||
640 | ret += fprintf(fp, "U"); | ||
641 | if (has(HYPERVISOR)) | ||
642 | ret += fprintf(fp, "H"); | ||
643 | if (has(GUEST_KERNEL)) | ||
644 | ret += fprintf(fp, "G"); | ||
645 | if (has(GUEST_USER)) | ||
646 | ret += fprintf(fp, "g"); | ||
647 | |||
648 | switch (type) { | ||
649 | case PERF_RECORD_MMAP: | ||
650 | case PERF_RECORD_MMAP2: | ||
651 | if (has(MMAP_DATA)) | ||
652 | ret += fprintf(fp, "M"); | ||
653 | break; | ||
654 | case PERF_RECORD_COMM: | ||
655 | if (has(COMM_EXEC)) | ||
656 | ret += fprintf(fp, "E"); | ||
657 | break; | ||
658 | case PERF_RECORD_SWITCH: | ||
659 | case PERF_RECORD_SWITCH_CPU_WIDE: | ||
660 | if (has(SWITCH_OUT)) | ||
661 | ret += fprintf(fp, "S"); | ||
662 | default: | ||
663 | break; | ||
664 | } | ||
665 | |||
666 | #undef has | ||
667 | |||
668 | ret += fprintf(fp, "%*s", 6 - ret, " "); | ||
669 | printed += ret; | ||
670 | } | ||
671 | |||
621 | if (PRINT_FIELD(TIME)) { | 672 | if (PRINT_FIELD(TIME)) { |
622 | nsecs = sample->time; | 673 | nsecs = sample->time; |
623 | secs = nsecs / NSEC_PER_SEC; | 674 | secs = nsecs / NSEC_PER_SEC; |
@@ -1437,13 +1488,16 @@ struct perf_script { | |||
1437 | bool show_mmap_events; | 1488 | bool show_mmap_events; |
1438 | bool show_switch_events; | 1489 | bool show_switch_events; |
1439 | bool show_namespace_events; | 1490 | bool show_namespace_events; |
1491 | bool show_lost_events; | ||
1440 | bool allocated; | 1492 | bool allocated; |
1441 | bool per_event_dump; | 1493 | bool per_event_dump; |
1442 | struct cpu_map *cpus; | 1494 | struct cpu_map *cpus; |
1443 | struct thread_map *threads; | 1495 | struct thread_map *threads; |
1444 | int name_width; | 1496 | int name_width; |
1445 | const char *time_str; | 1497 | const char *time_str; |
1446 | struct perf_time_interval ptime; | 1498 | struct perf_time_interval *ptime_range; |
1499 | int range_size; | ||
1500 | int range_num; | ||
1447 | }; | 1501 | }; |
1448 | 1502 | ||
1449 | static int perf_evlist__max_name_len(struct perf_evlist *evlist) | 1503 | static int perf_evlist__max_name_len(struct perf_evlist *evlist) |
@@ -1477,6 +1531,88 @@ static int data_src__fprintf(u64 data_src, FILE *fp) | |||
1477 | return fprintf(fp, "%-*s", maxlen, out); | 1531 | return fprintf(fp, "%-*s", maxlen, out); |
1478 | } | 1532 | } |
1479 | 1533 | ||
1534 | struct metric_ctx { | ||
1535 | struct perf_sample *sample; | ||
1536 | struct thread *thread; | ||
1537 | struct perf_evsel *evsel; | ||
1538 | FILE *fp; | ||
1539 | }; | ||
1540 | |||
1541 | static void script_print_metric(void *ctx, const char *color, | ||
1542 | const char *fmt, | ||
1543 | const char *unit, double val) | ||
1544 | { | ||
1545 | struct metric_ctx *mctx = ctx; | ||
1546 | |||
1547 | if (!fmt) | ||
1548 | return; | ||
1549 | perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel, | ||
1550 | PERF_RECORD_SAMPLE, mctx->fp); | ||
1551 | fputs("\tmetric: ", mctx->fp); | ||
1552 | if (color) | ||
1553 | color_fprintf(mctx->fp, color, fmt, val); | ||
1554 | else | ||
1555 | printf(fmt, val); | ||
1556 | fprintf(mctx->fp, " %s\n", unit); | ||
1557 | } | ||
1558 | |||
1559 | static void script_new_line(void *ctx) | ||
1560 | { | ||
1561 | struct metric_ctx *mctx = ctx; | ||
1562 | |||
1563 | perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel, | ||
1564 | PERF_RECORD_SAMPLE, mctx->fp); | ||
1565 | fputs("\tmetric: ", mctx->fp); | ||
1566 | } | ||
1567 | |||
1568 | static void perf_sample__fprint_metric(struct perf_script *script, | ||
1569 | struct thread *thread, | ||
1570 | struct perf_evsel *evsel, | ||
1571 | struct perf_sample *sample, | ||
1572 | FILE *fp) | ||
1573 | { | ||
1574 | struct perf_stat_output_ctx ctx = { | ||
1575 | .print_metric = script_print_metric, | ||
1576 | .new_line = script_new_line, | ||
1577 | .ctx = &(struct metric_ctx) { | ||
1578 | .sample = sample, | ||
1579 | .thread = thread, | ||
1580 | .evsel = evsel, | ||
1581 | .fp = fp, | ||
1582 | }, | ||
1583 | .force_header = false, | ||
1584 | }; | ||
1585 | struct perf_evsel *ev2; | ||
1586 | static bool init; | ||
1587 | u64 val; | ||
1588 | |||
1589 | if (!init) { | ||
1590 | perf_stat__init_shadow_stats(); | ||
1591 | init = true; | ||
1592 | } | ||
1593 | if (!evsel->stats) | ||
1594 | perf_evlist__alloc_stats(script->session->evlist, false); | ||
1595 | if (evsel_script(evsel->leader)->gnum++ == 0) | ||
1596 | perf_stat__reset_shadow_stats(); | ||
1597 | val = sample->period * evsel->scale; | ||
1598 | perf_stat__update_shadow_stats(evsel, | ||
1599 | val, | ||
1600 | sample->cpu, | ||
1601 | &rt_stat); | ||
1602 | evsel_script(evsel)->val = val; | ||
1603 | if (evsel_script(evsel->leader)->gnum == evsel->leader->nr_members) { | ||
1604 | for_each_group_member (ev2, evsel->leader) { | ||
1605 | perf_stat__print_shadow_stats(ev2, | ||
1606 | evsel_script(ev2)->val, | ||
1607 | sample->cpu, | ||
1608 | &ctx, | ||
1609 | NULL, | ||
1610 | &rt_stat); | ||
1611 | } | ||
1612 | evsel_script(evsel->leader)->gnum = 0; | ||
1613 | } | ||
1614 | } | ||
1615 | |||
1480 | static void process_event(struct perf_script *script, | 1616 | static void process_event(struct perf_script *script, |
1481 | struct perf_sample *sample, struct perf_evsel *evsel, | 1617 | struct perf_sample *sample, struct perf_evsel *evsel, |
1482 | struct addr_location *al, | 1618 | struct addr_location *al, |
@@ -1493,7 +1629,8 @@ static void process_event(struct perf_script *script, | |||
1493 | 1629 | ||
1494 | ++es->samples; | 1630 | ++es->samples; |
1495 | 1631 | ||
1496 | perf_sample__fprintf_start(sample, thread, evsel, fp); | 1632 | perf_sample__fprintf_start(sample, thread, evsel, |
1633 | PERF_RECORD_SAMPLE, fp); | ||
1497 | 1634 | ||
1498 | if (PRINT_FIELD(PERIOD)) | 1635 | if (PRINT_FIELD(PERIOD)) |
1499 | fprintf(fp, "%10" PRIu64 " ", sample->period); | 1636 | fprintf(fp, "%10" PRIu64 " ", sample->period); |
@@ -1564,6 +1701,9 @@ static void process_event(struct perf_script *script, | |||
1564 | if (PRINT_FIELD(PHYS_ADDR)) | 1701 | if (PRINT_FIELD(PHYS_ADDR)) |
1565 | fprintf(fp, "%16" PRIx64, sample->phys_addr); | 1702 | fprintf(fp, "%16" PRIx64, sample->phys_addr); |
1566 | fprintf(fp, "\n"); | 1703 | fprintf(fp, "\n"); |
1704 | |||
1705 | if (PRINT_FIELD(METRIC)) | ||
1706 | perf_sample__fprint_metric(script, thread, evsel, sample, fp); | ||
1567 | } | 1707 | } |
1568 | 1708 | ||
1569 | static struct scripting_ops *scripting_ops; | 1709 | static struct scripting_ops *scripting_ops; |
@@ -1643,8 +1783,10 @@ static int process_sample_event(struct perf_tool *tool, | |||
1643 | struct perf_script *scr = container_of(tool, struct perf_script, tool); | 1783 | struct perf_script *scr = container_of(tool, struct perf_script, tool); |
1644 | struct addr_location al; | 1784 | struct addr_location al; |
1645 | 1785 | ||
1646 | if (perf_time__skip_sample(&scr->ptime, sample->time)) | 1786 | if (perf_time__ranges_skip_sample(scr->ptime_range, scr->range_num, |
1787 | sample->time)) { | ||
1647 | return 0; | 1788 | return 0; |
1789 | } | ||
1648 | 1790 | ||
1649 | if (debug_mode) { | 1791 | if (debug_mode) { |
1650 | if (sample->time < last_timestamp) { | 1792 | if (sample->time < last_timestamp) { |
@@ -1737,7 +1879,8 @@ static int process_comm_event(struct perf_tool *tool, | |||
1737 | sample->tid = event->comm.tid; | 1879 | sample->tid = event->comm.tid; |
1738 | sample->pid = event->comm.pid; | 1880 | sample->pid = event->comm.pid; |
1739 | } | 1881 | } |
1740 | perf_sample__fprintf_start(sample, thread, evsel, stdout); | 1882 | perf_sample__fprintf_start(sample, thread, evsel, |
1883 | PERF_RECORD_COMM, stdout); | ||
1741 | perf_event__fprintf(event, stdout); | 1884 | perf_event__fprintf(event, stdout); |
1742 | ret = 0; | 1885 | ret = 0; |
1743 | out: | 1886 | out: |
@@ -1772,7 +1915,8 @@ static int process_namespaces_event(struct perf_tool *tool, | |||
1772 | sample->tid = event->namespaces.tid; | 1915 | sample->tid = event->namespaces.tid; |
1773 | sample->pid = event->namespaces.pid; | 1916 | sample->pid = event->namespaces.pid; |
1774 | } | 1917 | } |
1775 | perf_sample__fprintf_start(sample, thread, evsel, stdout); | 1918 | perf_sample__fprintf_start(sample, thread, evsel, |
1919 | PERF_RECORD_NAMESPACES, stdout); | ||
1776 | perf_event__fprintf(event, stdout); | 1920 | perf_event__fprintf(event, stdout); |
1777 | ret = 0; | 1921 | ret = 0; |
1778 | out: | 1922 | out: |
@@ -1805,7 +1949,8 @@ static int process_fork_event(struct perf_tool *tool, | |||
1805 | sample->tid = event->fork.tid; | 1949 | sample->tid = event->fork.tid; |
1806 | sample->pid = event->fork.pid; | 1950 | sample->pid = event->fork.pid; |
1807 | } | 1951 | } |
1808 | perf_sample__fprintf_start(sample, thread, evsel, stdout); | 1952 | perf_sample__fprintf_start(sample, thread, evsel, |
1953 | PERF_RECORD_FORK, stdout); | ||
1809 | perf_event__fprintf(event, stdout); | 1954 | perf_event__fprintf(event, stdout); |
1810 | thread__put(thread); | 1955 | thread__put(thread); |
1811 | 1956 | ||
@@ -1834,7 +1979,8 @@ static int process_exit_event(struct perf_tool *tool, | |||
1834 | sample->tid = event->fork.tid; | 1979 | sample->tid = event->fork.tid; |
1835 | sample->pid = event->fork.pid; | 1980 | sample->pid = event->fork.pid; |
1836 | } | 1981 | } |
1837 | perf_sample__fprintf_start(sample, thread, evsel, stdout); | 1982 | perf_sample__fprintf_start(sample, thread, evsel, |
1983 | PERF_RECORD_EXIT, stdout); | ||
1838 | perf_event__fprintf(event, stdout); | 1984 | perf_event__fprintf(event, stdout); |
1839 | 1985 | ||
1840 | if (perf_event__process_exit(tool, event, sample, machine) < 0) | 1986 | if (perf_event__process_exit(tool, event, sample, machine) < 0) |
@@ -1869,7 +2015,8 @@ static int process_mmap_event(struct perf_tool *tool, | |||
1869 | sample->tid = event->mmap.tid; | 2015 | sample->tid = event->mmap.tid; |
1870 | sample->pid = event->mmap.pid; | 2016 | sample->pid = event->mmap.pid; |
1871 | } | 2017 | } |
1872 | perf_sample__fprintf_start(sample, thread, evsel, stdout); | 2018 | perf_sample__fprintf_start(sample, thread, evsel, |
2019 | PERF_RECORD_MMAP, stdout); | ||
1873 | perf_event__fprintf(event, stdout); | 2020 | perf_event__fprintf(event, stdout); |
1874 | thread__put(thread); | 2021 | thread__put(thread); |
1875 | return 0; | 2022 | return 0; |
@@ -1900,7 +2047,8 @@ static int process_mmap2_event(struct perf_tool *tool, | |||
1900 | sample->tid = event->mmap2.tid; | 2047 | sample->tid = event->mmap2.tid; |
1901 | sample->pid = event->mmap2.pid; | 2048 | sample->pid = event->mmap2.pid; |
1902 | } | 2049 | } |
1903 | perf_sample__fprintf_start(sample, thread, evsel, stdout); | 2050 | perf_sample__fprintf_start(sample, thread, evsel, |
2051 | PERF_RECORD_MMAP2, stdout); | ||
1904 | perf_event__fprintf(event, stdout); | 2052 | perf_event__fprintf(event, stdout); |
1905 | thread__put(thread); | 2053 | thread__put(thread); |
1906 | return 0; | 2054 | return 0; |
@@ -1926,7 +2074,31 @@ static int process_switch_event(struct perf_tool *tool, | |||
1926 | return -1; | 2074 | return -1; |
1927 | } | 2075 | } |
1928 | 2076 | ||
1929 | perf_sample__fprintf_start(sample, thread, evsel, stdout); | 2077 | perf_sample__fprintf_start(sample, thread, evsel, |
2078 | PERF_RECORD_SWITCH, stdout); | ||
2079 | perf_event__fprintf(event, stdout); | ||
2080 | thread__put(thread); | ||
2081 | return 0; | ||
2082 | } | ||
2083 | |||
2084 | static int | ||
2085 | process_lost_event(struct perf_tool *tool, | ||
2086 | union perf_event *event, | ||
2087 | struct perf_sample *sample, | ||
2088 | struct machine *machine) | ||
2089 | { | ||
2090 | struct perf_script *script = container_of(tool, struct perf_script, tool); | ||
2091 | struct perf_session *session = script->session; | ||
2092 | struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
2093 | struct thread *thread; | ||
2094 | |||
2095 | thread = machine__findnew_thread(machine, sample->pid, | ||
2096 | sample->tid); | ||
2097 | if (thread == NULL) | ||
2098 | return -1; | ||
2099 | |||
2100 | perf_sample__fprintf_start(sample, thread, evsel, | ||
2101 | PERF_RECORD_LOST, stdout); | ||
1930 | perf_event__fprintf(event, stdout); | 2102 | perf_event__fprintf(event, stdout); |
1931 | thread__put(thread); | 2103 | thread__put(thread); |
1932 | return 0; | 2104 | return 0; |
@@ -2026,6 +2198,8 @@ static int __cmd_script(struct perf_script *script) | |||
2026 | script->tool.context_switch = process_switch_event; | 2198 | script->tool.context_switch = process_switch_event; |
2027 | if (script->show_namespace_events) | 2199 | if (script->show_namespace_events) |
2028 | script->tool.namespaces = process_namespaces_event; | 2200 | script->tool.namespaces = process_namespaces_event; |
2201 | if (script->show_lost_events) | ||
2202 | script->tool.lost = process_lost_event; | ||
2029 | 2203 | ||
2030 | if (perf_script__setup_per_event_dump(script)) { | 2204 | if (perf_script__setup_per_event_dump(script)) { |
2031 | pr_err("Couldn't create the per event dump files\n"); | 2205 | pr_err("Couldn't create the per event dump files\n"); |
@@ -2311,19 +2485,6 @@ out: | |||
2311 | return rc; | 2485 | return rc; |
2312 | } | 2486 | } |
2313 | 2487 | ||
2314 | /* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */ | ||
2315 | static int is_directory(const char *base_path, const struct dirent *dent) | ||
2316 | { | ||
2317 | char path[PATH_MAX]; | ||
2318 | struct stat st; | ||
2319 | |||
2320 | sprintf(path, "%s/%s", base_path, dent->d_name); | ||
2321 | if (stat(path, &st)) | ||
2322 | return 0; | ||
2323 | |||
2324 | return S_ISDIR(st.st_mode); | ||
2325 | } | ||
2326 | |||
2327 | #define for_each_lang(scripts_path, scripts_dir, lang_dirent) \ | 2488 | #define for_each_lang(scripts_path, scripts_dir, lang_dirent) \ |
2328 | while ((lang_dirent = readdir(scripts_dir)) != NULL) \ | 2489 | while ((lang_dirent = readdir(scripts_dir)) != NULL) \ |
2329 | if ((lang_dirent->d_type == DT_DIR || \ | 2490 | if ((lang_dirent->d_type == DT_DIR || \ |
@@ -2758,9 +2919,10 @@ static void script__setup_sample_type(struct perf_script *script) | |||
2758 | 2919 | ||
2759 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) { | 2920 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) { |
2760 | if ((sample_type & PERF_SAMPLE_REGS_USER) && | 2921 | if ((sample_type & PERF_SAMPLE_REGS_USER) && |
2761 | (sample_type & PERF_SAMPLE_STACK_USER)) | 2922 | (sample_type & PERF_SAMPLE_STACK_USER)) { |
2762 | callchain_param.record_mode = CALLCHAIN_DWARF; | 2923 | callchain_param.record_mode = CALLCHAIN_DWARF; |
2763 | else if (sample_type & PERF_SAMPLE_BRANCH_STACK) | 2924 | dwarf_callchain_users = true; |
2925 | } else if (sample_type & PERF_SAMPLE_BRANCH_STACK) | ||
2764 | callchain_param.record_mode = CALLCHAIN_LBR; | 2926 | callchain_param.record_mode = CALLCHAIN_LBR; |
2765 | else | 2927 | else |
2766 | callchain_param.record_mode = CALLCHAIN_FP; | 2928 | callchain_param.record_mode = CALLCHAIN_FP; |
@@ -2975,6 +3137,8 @@ int cmd_script(int argc, const char **argv) | |||
2975 | "Show context switch events (if recorded)"), | 3137 | "Show context switch events (if recorded)"), |
2976 | OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events, | 3138 | OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events, |
2977 | "Show namespace events (if recorded)"), | 3139 | "Show namespace events (if recorded)"), |
3140 | OPT_BOOLEAN('\0', "show-lost-events", &script.show_lost_events, | ||
3141 | "Show lost events (if recorded)"), | ||
2978 | OPT_BOOLEAN('\0', "per-event-dump", &script.per_event_dump, | 3142 | OPT_BOOLEAN('\0', "per-event-dump", &script.per_event_dump, |
2979 | "Dump trace output to files named by the monitored events"), | 3143 | "Dump trace output to files named by the monitored events"), |
2980 | OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), | 3144 | OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), |
@@ -3281,18 +3445,46 @@ int cmd_script(int argc, const char **argv) | |||
3281 | if (err < 0) | 3445 | if (err < 0) |
3282 | goto out_delete; | 3446 | goto out_delete; |
3283 | 3447 | ||
3284 | /* needs to be parsed after looking up reference time */ | 3448 | script.ptime_range = perf_time__range_alloc(script.time_str, |
3285 | if (perf_time__parse_str(&script.ptime, script.time_str) != 0) { | 3449 | &script.range_size); |
3286 | pr_err("Invalid time string\n"); | 3450 | if (!script.ptime_range) { |
3287 | err = -EINVAL; | 3451 | err = -ENOMEM; |
3288 | goto out_delete; | 3452 | goto out_delete; |
3289 | } | 3453 | } |
3290 | 3454 | ||
3455 | /* needs to be parsed after looking up reference time */ | ||
3456 | if (perf_time__parse_str(script.ptime_range, script.time_str) != 0) { | ||
3457 | if (session->evlist->first_sample_time == 0 && | ||
3458 | session->evlist->last_sample_time == 0) { | ||
3459 | pr_err("HINT: no first/last sample time found in perf data.\n" | ||
3460 | "Please use latest perf binary to execute 'perf record'\n" | ||
3461 | "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n"); | ||
3462 | err = -EINVAL; | ||
3463 | goto out_delete; | ||
3464 | } | ||
3465 | |||
3466 | script.range_num = perf_time__percent_parse_str( | ||
3467 | script.ptime_range, script.range_size, | ||
3468 | script.time_str, | ||
3469 | session->evlist->first_sample_time, | ||
3470 | session->evlist->last_sample_time); | ||
3471 | |||
3472 | if (script.range_num < 0) { | ||
3473 | pr_err("Invalid time string\n"); | ||
3474 | err = -EINVAL; | ||
3475 | goto out_delete; | ||
3476 | } | ||
3477 | } else { | ||
3478 | script.range_num = 1; | ||
3479 | } | ||
3480 | |||
3291 | err = __cmd_script(&script); | 3481 | err = __cmd_script(&script); |
3292 | 3482 | ||
3293 | flush_scripting(); | 3483 | flush_scripting(); |
3294 | 3484 | ||
3295 | out_delete: | 3485 | out_delete: |
3486 | zfree(&script.ptime_range); | ||
3487 | |||
3296 | perf_evlist__free_stats(session->evlist); | 3488 | perf_evlist__free_stats(session->evlist); |
3297 | perf_session__delete(session); | 3489 | perf_session__delete(session); |
3298 | 3490 | ||