diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-10 18:22:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-10 18:22:03 -0400 |
commit | 12ad143e1b803e541e48b8ba40f550250259ecdd (patch) | |
tree | 5202b407df21e5abaeb294d1ecddcf0a2eca7f8b /tools | |
parent | 262d6a9a63a387c8dfa9eb4f7713e159c941e52c (diff) | |
parent | b339da480315505aa28a723a983217ebcff95c86 (diff) |
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Thomas Gleixner:
"Perf updates and fixes:
Kernel:
- Handle events which have the bpf_event attribute set as side band
events as they carry information about BPF programs.
- Add missing switch-case fall-through comments
Libraries:
- Fix leaks and double frees in error code paths.
- Prevent buffer overflows in libtraceevent
Tools:
- Improvements in handling Intel BT/PTS
- Add BTF ELF markers to perf trace BPF programs to improve output
- Support --time, --cpu, --pid and --tid filters for perf diff
- Calculate the column width in perf annotate as the hardcoded 6
characters for the instruction are not sufficient
- Small fixes all over the place"
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (38 commits)
perf/core: Mark expected switch fall-through
perf/x86/intel/uncore: Fix client IMC events return huge result
perf/ring_buffer: Use high order allocations for AUX buffers optimistically
perf data: Force perf_data__open|close zero data->file.path
perf session: Fix double free in perf_data__close
perf evsel: Probe for precise_ip with simple attr
perf tools: Read and store caps/max_precise in perf_pmu
perf hist: Fix memory leak of srcline
perf hist: Add error path into hist_entry__init
perf c2c: Fix c2c report for empty numa node
perf script python: Add Python3 support to intel-pt-events.py
perf script python: Add Python3 support to event_analyzing_sample.py
perf script python: add Python3 support to check-perf-trace.py
perf script python: Add Python3 support to futex-contention.py
perf script python: Remove mixed indentation
perf diff: Support --pid/--tid filter options
perf diff: Support --cpu filter option
perf diff: Support --time filter option
perf thread: Generalize function to copy from thread addr space from intel-bts code
perf annotate: Calculate the max instruction name, align column to that
...
Diffstat (limited to 'tools')
50 files changed, 975 insertions, 447 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index abd4fa5d3088..87494c7c619d 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -2457,7 +2457,7 @@ static int arg_num_eval(struct tep_print_arg *arg, long long *val) | |||
2457 | static char *arg_eval (struct tep_print_arg *arg) | 2457 | static char *arg_eval (struct tep_print_arg *arg) |
2458 | { | 2458 | { |
2459 | long long val; | 2459 | long long val; |
2460 | static char buf[20]; | 2460 | static char buf[24]; |
2461 | 2461 | ||
2462 | switch (arg->type) { | 2462 | switch (arg->type) { |
2463 | case TEP_PRINT_ATOM: | 2463 | case TEP_PRINT_ATOM: |
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index a79c84ae61aa..da7809b15cc9 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt | |||
@@ -118,6 +118,62 @@ OPTIONS | |||
118 | sum of shown entries will be always 100%. "absolute" means it retains | 118 | sum of shown entries will be always 100%. "absolute" means it retains |
119 | the original value before and after the filter is applied. | 119 | the original value before and after the filter is applied. |
120 | 120 | ||
121 | --time:: | ||
122 | Analyze samples within given time window. It supports time | ||
123 | percent with multiple time ranges. Time string is 'a%/n,b%/m,...' | ||
124 | or 'a%-b%,c%-%d,...'. | ||
125 | |||
126 | For example: | ||
127 | |||
128 | Select the second 10% time slice to diff: | ||
129 | |||
130 | perf diff --time 10%/2 | ||
131 | |||
132 | Select from 0% to 10% time slice to diff: | ||
133 | |||
134 | perf diff --time 0%-10% | ||
135 | |||
136 | Select the first and the second 10% time slices to diff: | ||
137 | |||
138 | perf diff --time 10%/1,10%/2 | ||
139 | |||
140 | Select from 0% to 10% and 30% to 40% slices to diff: | ||
141 | |||
142 | perf diff --time 0%-10%,30%-40% | ||
143 | |||
144 | It also supports analyzing samples within a given time window | ||
145 | <start>,<stop>. Times have the format seconds.microseconds. If 'start' | ||
146 | is not given (i.e., time string is ',x.y') then analysis starts at | ||
147 | the beginning of the file. If stop time is not given (i.e, time | ||
148 | string is 'x.y,') then analysis goes to the end of the file. Time string is | ||
149 | 'a1.b1,c1.d1:a2.b2,c2.d2'. Use ':' to separate timestamps for different | ||
150 | perf.data files. | ||
151 | |||
152 | For example, we get the timestamp information from 'perf script'. | ||
153 | |||
154 | perf script -i perf.data.old | ||
155 | mgen 13940 [000] 3946.361400: ... | ||
156 | |||
157 | perf script -i perf.data | ||
158 | mgen 13940 [000] 3971.150589 ... | ||
159 | |||
160 | perf diff --time 3946.361400,:3971.150589, | ||
161 | |||
162 | It analyzes the perf.data.old from the timestamp 3946.361400 to | ||
163 | the end of perf.data.old and analyzes the perf.data from the | ||
164 | timestamp 3971.150589 to the end of perf.data. | ||
165 | |||
166 | --cpu:: Only diff samples for the list of CPUs provided. Multiple CPUs can | ||
167 | be provided as a comma-separated list with no space: 0,1. Ranges of | ||
168 | CPUs are specified with -: 0-2. Default is to report samples on all | ||
169 | CPUs. | ||
170 | |||
171 | --pid=:: | ||
172 | Only diff samples for given process ID (comma separated list). | ||
173 | |||
174 | --tid=:: | ||
175 | Only diff samples for given thread ID (comma separated list). | ||
176 | |||
121 | COMPARISON | 177 | COMPARISON |
122 | ---------- | 178 | ---------- |
123 | The comparison is governed by the baseline file. The baseline perf.data | 179 | The comparison is governed by the baseline file. The baseline perf.data |
diff --git a/tools/perf/arch/arm64/annotate/instructions.c b/tools/perf/arch/arm64/annotate/instructions.c index 76c6345a57d5..8f70a1b282df 100644 --- a/tools/perf/arch/arm64/annotate/instructions.c +++ b/tools/perf/arch/arm64/annotate/instructions.c | |||
@@ -58,7 +58,7 @@ out_free_source: | |||
58 | } | 58 | } |
59 | 59 | ||
60 | static int mov__scnprintf(struct ins *ins, char *bf, size_t size, | 60 | static int mov__scnprintf(struct ins *ins, char *bf, size_t size, |
61 | struct ins_operands *ops); | 61 | struct ins_operands *ops, int max_ins_name); |
62 | 62 | ||
63 | static struct ins_ops arm64_mov_ops = { | 63 | static struct ins_ops arm64_mov_ops = { |
64 | .parse = arm64_mov__parse, | 64 | .parse = arm64_mov__parse, |
diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c index de0dd66dbb48..89bb8f2c54ce 100644 --- a/tools/perf/arch/s390/annotate/instructions.c +++ b/tools/perf/arch/s390/annotate/instructions.c | |||
@@ -46,7 +46,7 @@ static int s390_call__parse(struct arch *arch, struct ins_operands *ops, | |||
46 | } | 46 | } |
47 | 47 | ||
48 | static int call__scnprintf(struct ins *ins, char *bf, size_t size, | 48 | static int call__scnprintf(struct ins *ins, char *bf, size_t size, |
49 | struct ins_operands *ops); | 49 | struct ins_operands *ops, int max_ins_name); |
50 | 50 | ||
51 | static struct ins_ops s390_call_ops = { | 51 | static struct ins_ops s390_call_ops = { |
52 | .parse = s390_call__parse, | 52 | .parse = s390_call__parse, |
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 4272763a5e96..9e6cc868bdb4 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c | |||
@@ -2056,6 +2056,12 @@ static int setup_nodes(struct perf_session *session) | |||
2056 | if (!set) | 2056 | if (!set) |
2057 | return -ENOMEM; | 2057 | return -ENOMEM; |
2058 | 2058 | ||
2059 | nodes[node] = set; | ||
2060 | |||
2061 | /* empty node, skip */ | ||
2062 | if (cpu_map__empty(map)) | ||
2063 | continue; | ||
2064 | |||
2059 | for (cpu = 0; cpu < map->nr; cpu++) { | 2065 | for (cpu = 0; cpu < map->nr; cpu++) { |
2060 | set_bit(map->map[cpu], set); | 2066 | set_bit(map->map[cpu], set); |
2061 | 2067 | ||
@@ -2064,8 +2070,6 @@ static int setup_nodes(struct perf_session *session) | |||
2064 | 2070 | ||
2065 | cpu2node[map->map[cpu]] = node; | 2071 | cpu2node[map->map[cpu]] = node; |
2066 | } | 2072 | } |
2067 | |||
2068 | nodes[node] = set; | ||
2069 | } | 2073 | } |
2070 | 2074 | ||
2071 | setup_nodes_header(); | 2075 | setup_nodes_header(); |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 58fe0e88215c..6e7920793729 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -19,12 +19,21 @@ | |||
19 | #include "util/util.h" | 19 | #include "util/util.h" |
20 | #include "util/data.h" | 20 | #include "util/data.h" |
21 | #include "util/config.h" | 21 | #include "util/config.h" |
22 | #include "util/time-utils.h" | ||
22 | 23 | ||
23 | #include <errno.h> | 24 | #include <errno.h> |
24 | #include <inttypes.h> | 25 | #include <inttypes.h> |
25 | #include <stdlib.h> | 26 | #include <stdlib.h> |
26 | #include <math.h> | 27 | #include <math.h> |
27 | 28 | ||
29 | struct perf_diff { | ||
30 | struct perf_tool tool; | ||
31 | const char *time_str; | ||
32 | struct perf_time_interval *ptime_range; | ||
33 | int range_size; | ||
34 | int range_num; | ||
35 | }; | ||
36 | |||
28 | /* Diff command specific HPP columns. */ | 37 | /* Diff command specific HPP columns. */ |
29 | enum { | 38 | enum { |
30 | PERF_HPP_DIFF__BASELINE, | 39 | PERF_HPP_DIFF__BASELINE, |
@@ -74,6 +83,9 @@ static unsigned int sort_compute = 1; | |||
74 | static s64 compute_wdiff_w1; | 83 | static s64 compute_wdiff_w1; |
75 | static s64 compute_wdiff_w2; | 84 | static s64 compute_wdiff_w2; |
76 | 85 | ||
86 | static const char *cpu_list; | ||
87 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | ||
88 | |||
77 | enum { | 89 | enum { |
78 | COMPUTE_DELTA, | 90 | COMPUTE_DELTA, |
79 | COMPUTE_RATIO, | 91 | COMPUTE_RATIO, |
@@ -323,22 +335,33 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, | |||
323 | return -1; | 335 | return -1; |
324 | } | 336 | } |
325 | 337 | ||
326 | static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, | 338 | static int diff__process_sample_event(struct perf_tool *tool, |
327 | union perf_event *event, | 339 | union perf_event *event, |
328 | struct perf_sample *sample, | 340 | struct perf_sample *sample, |
329 | struct perf_evsel *evsel, | 341 | struct perf_evsel *evsel, |
330 | struct machine *machine) | 342 | struct machine *machine) |
331 | { | 343 | { |
344 | struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool); | ||
332 | struct addr_location al; | 345 | struct addr_location al; |
333 | struct hists *hists = evsel__hists(evsel); | 346 | struct hists *hists = evsel__hists(evsel); |
334 | int ret = -1; | 347 | int ret = -1; |
335 | 348 | ||
349 | if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num, | ||
350 | sample->time)) { | ||
351 | return 0; | ||
352 | } | ||
353 | |||
336 | if (machine__resolve(machine, &al, sample) < 0) { | 354 | if (machine__resolve(machine, &al, sample) < 0) { |
337 | pr_warning("problem processing %d event, skipping it.\n", | 355 | pr_warning("problem processing %d event, skipping it.\n", |
338 | event->header.type); | 356 | event->header.type); |
339 | return -1; | 357 | return -1; |
340 | } | 358 | } |
341 | 359 | ||
360 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) { | ||
361 | ret = 0; | ||
362 | goto out_put; | ||
363 | } | ||
364 | |||
342 | if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample, true)) { | 365 | if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample, true)) { |
343 | pr_warning("problem incrementing symbol period, skipping event\n"); | 366 | pr_warning("problem incrementing symbol period, skipping event\n"); |
344 | goto out_put; | 367 | goto out_put; |
@@ -359,17 +382,19 @@ out_put: | |||
359 | return ret; | 382 | return ret; |
360 | } | 383 | } |
361 | 384 | ||
362 | static struct perf_tool tool = { | 385 | static struct perf_diff pdiff = { |
363 | .sample = diff__process_sample_event, | 386 | .tool = { |
364 | .mmap = perf_event__process_mmap, | 387 | .sample = diff__process_sample_event, |
365 | .mmap2 = perf_event__process_mmap2, | 388 | .mmap = perf_event__process_mmap, |
366 | .comm = perf_event__process_comm, | 389 | .mmap2 = perf_event__process_mmap2, |
367 | .exit = perf_event__process_exit, | 390 | .comm = perf_event__process_comm, |
368 | .fork = perf_event__process_fork, | 391 | .exit = perf_event__process_exit, |
369 | .lost = perf_event__process_lost, | 392 | .fork = perf_event__process_fork, |
370 | .namespaces = perf_event__process_namespaces, | 393 | .lost = perf_event__process_lost, |
371 | .ordered_events = true, | 394 | .namespaces = perf_event__process_namespaces, |
372 | .ordering_requires_timestamps = true, | 395 | .ordered_events = true, |
396 | .ordering_requires_timestamps = true, | ||
397 | }, | ||
373 | }; | 398 | }; |
374 | 399 | ||
375 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | 400 | static struct perf_evsel *evsel_match(struct perf_evsel *evsel, |
@@ -771,19 +796,117 @@ static void data__free(struct data__file *d) | |||
771 | } | 796 | } |
772 | } | 797 | } |
773 | 798 | ||
799 | static int abstime_str_dup(char **pstr) | ||
800 | { | ||
801 | char *str = NULL; | ||
802 | |||
803 | if (pdiff.time_str && strchr(pdiff.time_str, ':')) { | ||
804 | str = strdup(pdiff.time_str); | ||
805 | if (!str) | ||
806 | return -ENOMEM; | ||
807 | } | ||
808 | |||
809 | *pstr = str; | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | static int parse_absolute_time(struct data__file *d, char **pstr) | ||
814 | { | ||
815 | char *p = *pstr; | ||
816 | int ret; | ||
817 | |||
818 | /* | ||
819 | * Absolute timestamp for one file has the format: a.b,c.d | ||
820 | * For multiple files, the format is: a.b,c.d:a.b,c.d | ||
821 | */ | ||
822 | p = strchr(*pstr, ':'); | ||
823 | if (p) { | ||
824 | if (p == *pstr) { | ||
825 | pr_err("Invalid time string\n"); | ||
826 | return -EINVAL; | ||
827 | } | ||
828 | |||
829 | *p = 0; | ||
830 | p++; | ||
831 | if (*p == 0) { | ||
832 | pr_err("Invalid time string\n"); | ||
833 | return -EINVAL; | ||
834 | } | ||
835 | } | ||
836 | |||
837 | ret = perf_time__parse_for_ranges(*pstr, d->session, | ||
838 | &pdiff.ptime_range, | ||
839 | &pdiff.range_size, | ||
840 | &pdiff.range_num); | ||
841 | if (ret < 0) | ||
842 | return ret; | ||
843 | |||
844 | if (!p || *p == 0) | ||
845 | *pstr = NULL; | ||
846 | else | ||
847 | *pstr = p; | ||
848 | |||
849 | return ret; | ||
850 | } | ||
851 | |||
852 | static int parse_percent_time(struct data__file *d) | ||
853 | { | ||
854 | int ret; | ||
855 | |||
856 | ret = perf_time__parse_for_ranges(pdiff.time_str, d->session, | ||
857 | &pdiff.ptime_range, | ||
858 | &pdiff.range_size, | ||
859 | &pdiff.range_num); | ||
860 | return ret; | ||
861 | } | ||
862 | |||
863 | static int parse_time_str(struct data__file *d, char *abstime_ostr, | ||
864 | char **pabstime_tmp) | ||
865 | { | ||
866 | int ret = 0; | ||
867 | |||
868 | if (abstime_ostr) | ||
869 | ret = parse_absolute_time(d, pabstime_tmp); | ||
870 | else if (pdiff.time_str) | ||
871 | ret = parse_percent_time(d); | ||
872 | |||
873 | return ret; | ||
874 | } | ||
875 | |||
774 | static int __cmd_diff(void) | 876 | static int __cmd_diff(void) |
775 | { | 877 | { |
776 | struct data__file *d; | 878 | struct data__file *d; |
777 | int ret = -EINVAL, i; | 879 | int ret, i; |
880 | char *abstime_ostr, *abstime_tmp; | ||
881 | |||
882 | ret = abstime_str_dup(&abstime_ostr); | ||
883 | if (ret) | ||
884 | return ret; | ||
885 | |||
886 | abstime_tmp = abstime_ostr; | ||
887 | ret = -EINVAL; | ||
778 | 888 | ||
779 | data__for_each_file(i, d) { | 889 | data__for_each_file(i, d) { |
780 | d->session = perf_session__new(&d->data, false, &tool); | 890 | d->session = perf_session__new(&d->data, false, &pdiff.tool); |
781 | if (!d->session) { | 891 | if (!d->session) { |
782 | pr_err("Failed to open %s\n", d->data.path); | 892 | pr_err("Failed to open %s\n", d->data.path); |
783 | ret = -1; | 893 | ret = -1; |
784 | goto out_delete; | 894 | goto out_delete; |
785 | } | 895 | } |
786 | 896 | ||
897 | if (pdiff.time_str) { | ||
898 | ret = parse_time_str(d, abstime_ostr, &abstime_tmp); | ||
899 | if (ret < 0) | ||
900 | goto out_delete; | ||
901 | } | ||
902 | |||
903 | if (cpu_list) { | ||
904 | ret = perf_session__cpu_bitmap(d->session, cpu_list, | ||
905 | cpu_bitmap); | ||
906 | if (ret < 0) | ||
907 | goto out_delete; | ||
908 | } | ||
909 | |||
787 | ret = perf_session__process_events(d->session); | 910 | ret = perf_session__process_events(d->session); |
788 | if (ret) { | 911 | if (ret) { |
789 | pr_err("Failed to process %s\n", d->data.path); | 912 | pr_err("Failed to process %s\n", d->data.path); |
@@ -791,6 +914,9 @@ static int __cmd_diff(void) | |||
791 | } | 914 | } |
792 | 915 | ||
793 | perf_evlist__collapse_resort(d->session->evlist); | 916 | perf_evlist__collapse_resort(d->session->evlist); |
917 | |||
918 | if (pdiff.ptime_range) | ||
919 | zfree(&pdiff.ptime_range); | ||
794 | } | 920 | } |
795 | 921 | ||
796 | data_process(); | 922 | data_process(); |
@@ -802,6 +928,13 @@ static int __cmd_diff(void) | |||
802 | } | 928 | } |
803 | 929 | ||
804 | free(data__files); | 930 | free(data__files); |
931 | |||
932 | if (pdiff.ptime_range) | ||
933 | zfree(&pdiff.ptime_range); | ||
934 | |||
935 | if (abstime_ostr) | ||
936 | free(abstime_ostr); | ||
937 | |||
805 | return ret; | 938 | return ret; |
806 | } | 939 | } |
807 | 940 | ||
@@ -849,6 +982,13 @@ static const struct option options[] = { | |||
849 | OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), | 982 | OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), |
850 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", | 983 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", |
851 | "How to display percentage of filtered entries", parse_filter_percentage), | 984 | "How to display percentage of filtered entries", parse_filter_percentage), |
985 | OPT_STRING(0, "time", &pdiff.time_str, "str", | ||
986 | "Time span (time percent or absolute timestamp)"), | ||
987 | OPT_STRING(0, "cpu", &cpu_list, "cpu", "list of cpus to profile"), | ||
988 | OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]", | ||
989 | "only consider symbols in these pids"), | ||
990 | OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]", | ||
991 | "only consider symbols in these tids"), | ||
852 | OPT_END() | 992 | OPT_END() |
853 | }; | 993 | }; |
854 | 994 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1532ebde6c4b..ee93c18a6685 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -1375,36 +1375,13 @@ repeat: | |||
1375 | if (symbol__init(&session->header.env) < 0) | 1375 | if (symbol__init(&session->header.env) < 0) |
1376 | goto error; | 1376 | goto error; |
1377 | 1377 | ||
1378 | report.ptime_range = perf_time__range_alloc(report.time_str, | 1378 | if (report.time_str) { |
1379 | &report.range_size); | 1379 | ret = perf_time__parse_for_ranges(report.time_str, session, |
1380 | if (!report.ptime_range) { | 1380 | &report.ptime_range, |
1381 | ret = -ENOMEM; | 1381 | &report.range_size, |
1382 | goto error; | 1382 | &report.range_num); |
1383 | } | 1383 | if (ret < 0) |
1384 | |||
1385 | if (perf_time__parse_str(report.ptime_range, report.time_str) != 0) { | ||
1386 | if (session->evlist->first_sample_time == 0 && | ||
1387 | session->evlist->last_sample_time == 0) { | ||
1388 | pr_err("HINT: no first/last sample time found in perf data.\n" | ||
1389 | "Please use latest perf binary to execute 'perf record'\n" | ||
1390 | "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n"); | ||
1391 | ret = -EINVAL; | ||
1392 | goto error; | ||
1393 | } | ||
1394 | |||
1395 | report.range_num = perf_time__percent_parse_str( | ||
1396 | report.ptime_range, report.range_size, | ||
1397 | report.time_str, | ||
1398 | session->evlist->first_sample_time, | ||
1399 | session->evlist->last_sample_time); | ||
1400 | |||
1401 | if (report.range_num < 0) { | ||
1402 | pr_err("Invalid time string\n"); | ||
1403 | ret = -EINVAL; | ||
1404 | goto error; | 1384 | goto error; |
1405 | } | ||
1406 | } else { | ||
1407 | report.range_num = 1; | ||
1408 | } | 1385 | } |
1409 | 1386 | ||
1410 | if (session->tevent.pevent && | 1387 | if (session->tevent.pevent && |
@@ -1426,7 +1403,8 @@ repeat: | |||
1426 | ret = 0; | 1403 | ret = 0; |
1427 | 1404 | ||
1428 | error: | 1405 | error: |
1429 | zfree(&report.ptime_range); | 1406 | if (report.ptime_range) |
1407 | zfree(&report.ptime_range); | ||
1430 | 1408 | ||
1431 | perf_session__delete(session); | 1409 | perf_session__delete(session); |
1432 | return ret; | 1410 | return ret; |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2d8cb1d1682c..53f78cf3113f 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -3699,37 +3699,13 @@ int cmd_script(int argc, const char **argv) | |||
3699 | if (err < 0) | 3699 | if (err < 0) |
3700 | goto out_delete; | 3700 | goto out_delete; |
3701 | 3701 | ||
3702 | script.ptime_range = perf_time__range_alloc(script.time_str, | 3702 | if (script.time_str) { |
3703 | &script.range_size); | 3703 | err = perf_time__parse_for_ranges(script.time_str, session, |
3704 | if (!script.ptime_range) { | 3704 | &script.ptime_range, |
3705 | err = -ENOMEM; | 3705 | &script.range_size, |
3706 | goto out_delete; | 3706 | &script.range_num); |
3707 | } | 3707 | if (err < 0) |
3708 | |||
3709 | /* needs to be parsed after looking up reference time */ | ||
3710 | if (perf_time__parse_str(script.ptime_range, script.time_str) != 0) { | ||
3711 | if (session->evlist->first_sample_time == 0 && | ||
3712 | session->evlist->last_sample_time == 0) { | ||
3713 | pr_err("HINT: no first/last sample time found in perf data.\n" | ||
3714 | "Please use latest perf binary to execute 'perf record'\n" | ||
3715 | "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n"); | ||
3716 | err = -EINVAL; | ||
3717 | goto out_delete; | ||
3718 | } | ||
3719 | |||
3720 | script.range_num = perf_time__percent_parse_str( | ||
3721 | script.ptime_range, script.range_size, | ||
3722 | script.time_str, | ||
3723 | session->evlist->first_sample_time, | ||
3724 | session->evlist->last_sample_time); | ||
3725 | |||
3726 | if (script.range_num < 0) { | ||
3727 | pr_err("Invalid time string\n"); | ||
3728 | err = -EINVAL; | ||
3729 | goto out_delete; | 3708 | goto out_delete; |
3730 | } | ||
3731 | } else { | ||
3732 | script.range_num = 1; | ||
3733 | } | 3709 | } |
3734 | 3710 | ||
3735 | err = __cmd_script(&script); | 3711 | err = __cmd_script(&script); |
@@ -3737,7 +3713,8 @@ int cmd_script(int argc, const char **argv) | |||
3737 | flush_scripting(); | 3713 | flush_scripting(); |
3738 | 3714 | ||
3739 | out_delete: | 3715 | out_delete: |
3740 | zfree(&script.ptime_range); | 3716 | if (script.ptime_range) |
3717 | zfree(&script.ptime_range); | ||
3741 | 3718 | ||
3742 | perf_evlist__free_stats(session->evlist); | 3719 | perf_evlist__free_stats(session->evlist); |
3743 | perf_session__delete(session); | 3720 | perf_session__delete(session); |
diff --git a/tools/perf/include/bpf/bpf.h b/tools/perf/include/bpf/bpf.h index 5df7ed9d9020..2eac6d804b2d 100644 --- a/tools/perf/include/bpf/bpf.h +++ b/tools/perf/include/bpf/bpf.h | |||
@@ -24,7 +24,13 @@ struct bpf_map SEC("maps") name = { \ | |||
24 | .key_size = sizeof(type_key), \ | 24 | .key_size = sizeof(type_key), \ |
25 | .value_size = sizeof(type_val), \ | 25 | .value_size = sizeof(type_val), \ |
26 | .max_entries = _max_entries, \ | 26 | .max_entries = _max_entries, \ |
27 | } | 27 | }; \ |
28 | struct ____btf_map_##name { \ | ||
29 | type_key key; \ | ||
30 | type_val value; \ | ||
31 | }; \ | ||
32 | struct ____btf_map_##name __attribute__((section(".maps." #name), used)) \ | ||
33 | ____btf_map_##name = { } | ||
28 | 34 | ||
29 | /* | 35 | /* |
30 | * FIXME: this should receive .max_entries as a parameter, as careful | 36 | * FIXME: this should receive .max_entries as a parameter, as careful |
diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py index 334599c6032c..d2c22954800d 100644 --- a/tools/perf/scripts/python/check-perf-trace.py +++ b/tools/perf/scripts/python/check-perf-trace.py | |||
@@ -7,6 +7,8 @@ | |||
7 | # events, etc. Basically, if this script runs successfully and | 7 | # events, etc. Basically, if this script runs successfully and |
8 | # displays expected results, Python scripting support should be ok. | 8 | # displays expected results, Python scripting support should be ok. |
9 | 9 | ||
10 | from __future__ import print_function | ||
11 | |||
10 | import os | 12 | import os |
11 | import sys | 13 | import sys |
12 | 14 | ||
@@ -19,64 +21,64 @@ from perf_trace_context import * | |||
19 | unhandled = autodict() | 21 | unhandled = autodict() |
20 | 22 | ||
21 | def trace_begin(): | 23 | def trace_begin(): |
22 | print "trace_begin" | 24 | print("trace_begin") |
23 | pass | 25 | pass |
24 | 26 | ||
25 | def trace_end(): | 27 | def trace_end(): |
26 | print_unhandled() | 28 | print_unhandled() |
27 | 29 | ||
28 | def irq__softirq_entry(event_name, context, common_cpu, | 30 | def irq__softirq_entry(event_name, context, common_cpu, |
29 | common_secs, common_nsecs, common_pid, common_comm, | 31 | common_secs, common_nsecs, common_pid, common_comm, |
30 | common_callchain, vec): | 32 | common_callchain, vec): |
31 | print_header(event_name, common_cpu, common_secs, common_nsecs, | 33 | print_header(event_name, common_cpu, common_secs, common_nsecs, |
32 | common_pid, common_comm) | 34 | common_pid, common_comm) |
33 | 35 | ||
34 | print_uncommon(context) | 36 | print_uncommon(context) |
35 | 37 | ||
36 | print "vec=%s\n" % \ | 38 | print("vec=%s" % (symbol_str("irq__softirq_entry", "vec", vec))) |
37 | (symbol_str("irq__softirq_entry", "vec", vec)), | ||
38 | 39 | ||
39 | def kmem__kmalloc(event_name, context, common_cpu, | 40 | def kmem__kmalloc(event_name, context, common_cpu, |
40 | common_secs, common_nsecs, common_pid, common_comm, | 41 | common_secs, common_nsecs, common_pid, common_comm, |
41 | common_callchain, call_site, ptr, bytes_req, bytes_alloc, | 42 | common_callchain, call_site, ptr, bytes_req, bytes_alloc, |
42 | gfp_flags): | 43 | gfp_flags): |
43 | print_header(event_name, common_cpu, common_secs, common_nsecs, | 44 | print_header(event_name, common_cpu, common_secs, common_nsecs, |
44 | common_pid, common_comm) | 45 | common_pid, common_comm) |
45 | 46 | ||
46 | print_uncommon(context) | 47 | print_uncommon(context) |
47 | 48 | ||
48 | print "call_site=%u, ptr=%u, bytes_req=%u, " \ | 49 | print("call_site=%u, ptr=%u, bytes_req=%u, " |
49 | "bytes_alloc=%u, gfp_flags=%s\n" % \ | 50 | "bytes_alloc=%u, gfp_flags=%s" % |
50 | (call_site, ptr, bytes_req, bytes_alloc, | 51 | (call_site, ptr, bytes_req, bytes_alloc, |
51 | 52 | flag_str("kmem__kmalloc", "gfp_flags", gfp_flags))) | |
52 | flag_str("kmem__kmalloc", "gfp_flags", gfp_flags)), | ||
53 | 53 | ||
54 | def trace_unhandled(event_name, context, event_fields_dict): | 54 | def trace_unhandled(event_name, context, event_fields_dict): |
55 | try: | 55 | try: |
56 | unhandled[event_name] += 1 | 56 | unhandled[event_name] += 1 |
57 | except TypeError: | 57 | except TypeError: |
58 | unhandled[event_name] = 1 | 58 | unhandled[event_name] = 1 |
59 | 59 | ||
60 | def print_header(event_name, cpu, secs, nsecs, pid, comm): | 60 | def print_header(event_name, cpu, secs, nsecs, pid, comm): |
61 | print "%-20s %5u %05u.%09u %8u %-20s " % \ | 61 | print("%-20s %5u %05u.%09u %8u %-20s " % |
62 | (event_name, cpu, secs, nsecs, pid, comm), | 62 | (event_name, cpu, secs, nsecs, pid, comm), |
63 | end=' ') | ||
63 | 64 | ||
64 | # print trace fields not included in handler args | 65 | # print trace fields not included in handler args |
65 | def print_uncommon(context): | 66 | def print_uncommon(context): |
66 | print "common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, " \ | 67 | print("common_preempt_count=%d, common_flags=%s, " |
67 | % (common_pc(context), trace_flag_str(common_flags(context)), \ | 68 | "common_lock_depth=%d, " % |
68 | common_lock_depth(context)) | 69 | (common_pc(context), trace_flag_str(common_flags(context)), |
70 | common_lock_depth(context))) | ||
69 | 71 | ||
70 | def print_unhandled(): | 72 | def print_unhandled(): |
71 | keys = unhandled.keys() | 73 | keys = unhandled.keys() |
72 | if not keys: | 74 | if not keys: |
73 | return | 75 | return |
74 | 76 | ||
75 | print "\nunhandled events:\n\n", | 77 | print("\nunhandled events:\n") |
76 | 78 | ||
77 | print "%-40s %10s\n" % ("event", "count"), | 79 | print("%-40s %10s" % ("event", "count")) |
78 | print "%-40s %10s\n" % ("----------------------------------------", \ | 80 | print("%-40s %10s" % ("----------------------------------------", |
79 | "-----------"), | 81 | "-----------")) |
80 | 82 | ||
81 | for event_name in keys: | 83 | for event_name in keys: |
82 | print "%-40s %10d\n" % (event_name, unhandled[event_name]) | 84 | print("%-40s %10d\n" % (event_name, unhandled[event_name])) |
diff --git a/tools/perf/scripts/python/compaction-times.py b/tools/perf/scripts/python/compaction-times.py index 239cb0568ec3..2560a042dc6f 100644 --- a/tools/perf/scripts/python/compaction-times.py +++ b/tools/perf/scripts/python/compaction-times.py | |||
@@ -216,15 +216,15 @@ def compaction__mm_compaction_migratepages(event_name, context, common_cpu, | |||
216 | pair(nr_migrated, nr_failed), None, None) | 216 | pair(nr_migrated, nr_failed), None, None) |
217 | 217 | ||
218 | def compaction__mm_compaction_isolate_freepages(event_name, context, common_cpu, | 218 | def compaction__mm_compaction_isolate_freepages(event_name, context, common_cpu, |
219 | common_secs, common_nsecs, common_pid, common_comm, | 219 | common_secs, common_nsecs, common_pid, common_comm, |
220 | common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken): | 220 | common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken): |
221 | 221 | ||
222 | chead.increment_pending(common_pid, | 222 | chead.increment_pending(common_pid, |
223 | None, pair(nr_scanned, nr_taken), None) | 223 | None, pair(nr_scanned, nr_taken), None) |
224 | 224 | ||
225 | def compaction__mm_compaction_isolate_migratepages(event_name, context, common_cpu, | 225 | def compaction__mm_compaction_isolate_migratepages(event_name, context, common_cpu, |
226 | common_secs, common_nsecs, common_pid, common_comm, | 226 | common_secs, common_nsecs, common_pid, common_comm, |
227 | common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken): | 227 | common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken): |
228 | 228 | ||
229 | chead.increment_pending(common_pid, | 229 | chead.increment_pending(common_pid, |
230 | None, None, pair(nr_scanned, nr_taken)) | 230 | None, None, pair(nr_scanned, nr_taken)) |
diff --git a/tools/perf/scripts/python/event_analyzing_sample.py b/tools/perf/scripts/python/event_analyzing_sample.py index 4e843b9864ec..aa1e2cfa26a6 100644 --- a/tools/perf/scripts/python/event_analyzing_sample.py +++ b/tools/perf/scripts/python/event_analyzing_sample.py | |||
@@ -15,6 +15,8 @@ | |||
15 | # for a x86 HW PMU event: PEBS with load latency data. | 15 | # for a x86 HW PMU event: PEBS with load latency data. |
16 | # | 16 | # |
17 | 17 | ||
18 | from __future__ import print_function | ||
19 | |||
18 | import os | 20 | import os |
19 | import sys | 21 | import sys |
20 | import math | 22 | import math |
@@ -37,7 +39,7 @@ con = sqlite3.connect("/dev/shm/perf.db") | |||
37 | con.isolation_level = None | 39 | con.isolation_level = None |
38 | 40 | ||
39 | def trace_begin(): | 41 | def trace_begin(): |
40 | print "In trace_begin:\n" | 42 | print("In trace_begin:\n") |
41 | 43 | ||
42 | # | 44 | # |
43 | # Will create several tables at the start, pebs_ll is for PEBS data with | 45 | # Will create several tables at the start, pebs_ll is for PEBS data with |
@@ -76,12 +78,12 @@ def process_event(param_dict): | |||
76 | name = param_dict["ev_name"] | 78 | name = param_dict["ev_name"] |
77 | 79 | ||
78 | # Symbol and dso info are not always resolved | 80 | # Symbol and dso info are not always resolved |
79 | if (param_dict.has_key("dso")): | 81 | if ("dso" in param_dict): |
80 | dso = param_dict["dso"] | 82 | dso = param_dict["dso"] |
81 | else: | 83 | else: |
82 | dso = "Unknown_dso" | 84 | dso = "Unknown_dso" |
83 | 85 | ||
84 | if (param_dict.has_key("symbol")): | 86 | if ("symbol" in param_dict): |
85 | symbol = param_dict["symbol"] | 87 | symbol = param_dict["symbol"] |
86 | else: | 88 | else: |
87 | symbol = "Unknown_symbol" | 89 | symbol = "Unknown_symbol" |
@@ -102,7 +104,7 @@ def insert_db(event): | |||
102 | event.ip, event.status, event.dse, event.dla, event.lat)) | 104 | event.ip, event.status, event.dse, event.dla, event.lat)) |
103 | 105 | ||
104 | def trace_end(): | 106 | def trace_end(): |
105 | print "In trace_end:\n" | 107 | print("In trace_end:\n") |
106 | # We show the basic info for the 2 type of event classes | 108 | # We show the basic info for the 2 type of event classes |
107 | show_general_events() | 109 | show_general_events() |
108 | show_pebs_ll() | 110 | show_pebs_ll() |
@@ -123,29 +125,29 @@ def show_general_events(): | |||
123 | # Check the total record number in the table | 125 | # Check the total record number in the table |
124 | count = con.execute("select count(*) from gen_events") | 126 | count = con.execute("select count(*) from gen_events") |
125 | for t in count: | 127 | for t in count: |
126 | print "There is %d records in gen_events table" % t[0] | 128 | print("There is %d records in gen_events table" % t[0]) |
127 | if t[0] == 0: | 129 | if t[0] == 0: |
128 | return | 130 | return |
129 | 131 | ||
130 | print "Statistics about the general events grouped by thread/symbol/dso: \n" | 132 | print("Statistics about the general events grouped by thread/symbol/dso: \n") |
131 | 133 | ||
132 | # Group by thread | 134 | # Group by thread |
133 | commq = con.execute("select comm, count(comm) from gen_events group by comm order by -count(comm)") | 135 | commq = con.execute("select comm, count(comm) from gen_events group by comm order by -count(comm)") |
134 | print "\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42) | 136 | print("\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42)) |
135 | for row in commq: | 137 | for row in commq: |
136 | print "%16s %8d %s" % (row[0], row[1], num2sym(row[1])) | 138 | print("%16s %8d %s" % (row[0], row[1], num2sym(row[1]))) |
137 | 139 | ||
138 | # Group by symbol | 140 | # Group by symbol |
139 | print "\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58) | 141 | print("\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58)) |
140 | symbolq = con.execute("select symbol, count(symbol) from gen_events group by symbol order by -count(symbol)") | 142 | symbolq = con.execute("select symbol, count(symbol) from gen_events group by symbol order by -count(symbol)") |
141 | for row in symbolq: | 143 | for row in symbolq: |
142 | print "%32s %8d %s" % (row[0], row[1], num2sym(row[1])) | 144 | print("%32s %8d %s" % (row[0], row[1], num2sym(row[1]))) |
143 | 145 | ||
144 | # Group by dso | 146 | # Group by dso |
145 | print "\n%40s %8s %16s\n%s" % ("dso", "number", "histogram", "="*74) | 147 | print("\n%40s %8s %16s\n%s" % ("dso", "number", "histogram", "="*74)) |
146 | dsoq = con.execute("select dso, count(dso) from gen_events group by dso order by -count(dso)") | 148 | dsoq = con.execute("select dso, count(dso) from gen_events group by dso order by -count(dso)") |
147 | for row in dsoq: | 149 | for row in dsoq: |
148 | print "%40s %8d %s" % (row[0], row[1], num2sym(row[1])) | 150 | print("%40s %8d %s" % (row[0], row[1], num2sym(row[1]))) |
149 | 151 | ||
150 | # | 152 | # |
151 | # This function just shows the basic info, and we could do more with the | 153 | # This function just shows the basic info, and we could do more with the |
@@ -156,35 +158,35 @@ def show_pebs_ll(): | |||
156 | 158 | ||
157 | count = con.execute("select count(*) from pebs_ll") | 159 | count = con.execute("select count(*) from pebs_ll") |
158 | for t in count: | 160 | for t in count: |
159 | print "There is %d records in pebs_ll table" % t[0] | 161 | print("There is %d records in pebs_ll table" % t[0]) |
160 | if t[0] == 0: | 162 | if t[0] == 0: |
161 | return | 163 | return |
162 | 164 | ||
163 | print "Statistics about the PEBS Load Latency events grouped by thread/symbol/dse/latency: \n" | 165 | print("Statistics about the PEBS Load Latency events grouped by thread/symbol/dse/latency: \n") |
164 | 166 | ||
165 | # Group by thread | 167 | # Group by thread |
166 | commq = con.execute("select comm, count(comm) from pebs_ll group by comm order by -count(comm)") | 168 | commq = con.execute("select comm, count(comm) from pebs_ll group by comm order by -count(comm)") |
167 | print "\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42) | 169 | print("\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42)) |
168 | for row in commq: | 170 | for row in commq: |
169 | print "%16s %8d %s" % (row[0], row[1], num2sym(row[1])) | 171 | print("%16s %8d %s" % (row[0], row[1], num2sym(row[1]))) |
170 | 172 | ||
171 | # Group by symbol | 173 | # Group by symbol |
172 | print "\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58) | 174 | print("\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58)) |
173 | symbolq = con.execute("select symbol, count(symbol) from pebs_ll group by symbol order by -count(symbol)") | 175 | symbolq = con.execute("select symbol, count(symbol) from pebs_ll group by symbol order by -count(symbol)") |
174 | for row in symbolq: | 176 | for row in symbolq: |
175 | print "%32s %8d %s" % (row[0], row[1], num2sym(row[1])) | 177 | print("%32s %8d %s" % (row[0], row[1], num2sym(row[1]))) |
176 | 178 | ||
177 | # Group by dse | 179 | # Group by dse |
178 | dseq = con.execute("select dse, count(dse) from pebs_ll group by dse order by -count(dse)") | 180 | dseq = con.execute("select dse, count(dse) from pebs_ll group by dse order by -count(dse)") |
179 | print "\n%32s %8s %16s\n%s" % ("dse", "number", "histogram", "="*58) | 181 | print("\n%32s %8s %16s\n%s" % ("dse", "number", "histogram", "="*58)) |
180 | for row in dseq: | 182 | for row in dseq: |
181 | print "%32s %8d %s" % (row[0], row[1], num2sym(row[1])) | 183 | print("%32s %8d %s" % (row[0], row[1], num2sym(row[1]))) |
182 | 184 | ||
183 | # Group by latency | 185 | # Group by latency |
184 | latq = con.execute("select lat, count(lat) from pebs_ll group by lat order by lat") | 186 | latq = con.execute("select lat, count(lat) from pebs_ll group by lat order by lat") |
185 | print "\n%32s %8s %16s\n%s" % ("latency", "number", "histogram", "="*58) | 187 | print("\n%32s %8s %16s\n%s" % ("latency", "number", "histogram", "="*58)) |
186 | for row in latq: | 188 | for row in latq: |
187 | print "%32s %8d %s" % (row[0], row[1], num2sym(row[1])) | 189 | print("%32s %8d %s" % (row[0], row[1], num2sym(row[1]))) |
188 | 190 | ||
189 | def trace_unhandled(event_name, context, event_fields_dict): | 191 | def trace_unhandled(event_name, context, event_fields_dict): |
190 | print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())]) | 192 | print (' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])) |
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py index 30130213da7e..390a351d15ea 100644 --- a/tools/perf/scripts/python/export-to-postgresql.py +++ b/tools/perf/scripts/python/export-to-postgresql.py | |||
@@ -394,7 +394,8 @@ if perf_db_export_calls: | |||
394 | 'call_id bigint,' | 394 | 'call_id bigint,' |
395 | 'return_id bigint,' | 395 | 'return_id bigint,' |
396 | 'parent_call_path_id bigint,' | 396 | 'parent_call_path_id bigint,' |
397 | 'flags integer)') | 397 | 'flags integer,' |
398 | 'parent_id bigint)') | ||
398 | 399 | ||
399 | do_query(query, 'CREATE VIEW machines_view AS ' | 400 | do_query(query, 'CREATE VIEW machines_view AS ' |
400 | 'SELECT ' | 401 | 'SELECT ' |
@@ -478,8 +479,9 @@ if perf_db_export_calls: | |||
478 | 'branch_count,' | 479 | 'branch_count,' |
479 | 'call_id,' | 480 | 'call_id,' |
480 | 'return_id,' | 481 | 'return_id,' |
481 | 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,' | 482 | 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE CAST ( flags AS VARCHAR(6) ) END AS flags,' |
482 | 'parent_call_path_id' | 483 | 'parent_call_path_id,' |
484 | 'calls.parent_id' | ||
483 | ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id') | 485 | ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id') |
484 | 486 | ||
485 | do_query(query, 'CREATE VIEW samples_view AS ' | 487 | do_query(query, 'CREATE VIEW samples_view AS ' |
@@ -575,6 +577,7 @@ def trace_begin(): | |||
575 | sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | 577 | sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
576 | if perf_db_export_calls or perf_db_export_callchains: | 578 | if perf_db_export_calls or perf_db_export_callchains: |
577 | call_path_table(0, 0, 0, 0) | 579 | call_path_table(0, 0, 0, 0) |
580 | call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | ||
578 | 581 | ||
579 | unhandled_count = 0 | 582 | unhandled_count = 0 |
580 | 583 | ||
@@ -657,6 +660,7 @@ def trace_end(): | |||
657 | 'ADD CONSTRAINT returnfk FOREIGN KEY (return_id) REFERENCES samples (id),' | 660 | 'ADD CONSTRAINT returnfk FOREIGN KEY (return_id) REFERENCES samples (id),' |
658 | 'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)') | 661 | 'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)') |
659 | do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)') | 662 | do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)') |
663 | do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)') | ||
660 | 664 | ||
661 | if (unhandled_count): | 665 | if (unhandled_count): |
662 | print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events" | 666 | print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events" |
@@ -728,7 +732,7 @@ def call_path_table(cp_id, parent_id, symbol_id, ip, *x): | |||
728 | value = struct.pack(fmt, 4, 8, cp_id, 8, parent_id, 8, symbol_id, 8, ip) | 732 | value = struct.pack(fmt, 4, 8, cp_id, 8, parent_id, 8, symbol_id, 8, ip) |
729 | call_path_file.write(value) | 733 | call_path_file.write(value) |
730 | 734 | ||
731 | def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return_time, branch_count, call_id, return_id, parent_call_path_id, flags, *x): | 735 | def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return_time, branch_count, call_id, return_id, parent_call_path_id, flags, parent_id, *x): |
732 | fmt = "!hiqiqiqiqiqiqiqiqiqiqii" | 736 | fmt = "!hiqiqiqiqiqiqiqiqiqiqiiiq" |
733 | value = struct.pack(fmt, 11, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags) | 737 | value = struct.pack(fmt, 12, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags, 8, parent_id) |
734 | call_file.write(value) | 738 | call_file.write(value) |
diff --git a/tools/perf/scripts/python/export-to-sqlite.py b/tools/perf/scripts/python/export-to-sqlite.py index ed237f2ed03f..eb63e6c7107f 100644 --- a/tools/perf/scripts/python/export-to-sqlite.py +++ b/tools/perf/scripts/python/export-to-sqlite.py | |||
@@ -222,7 +222,8 @@ if perf_db_export_calls: | |||
222 | 'call_id bigint,' | 222 | 'call_id bigint,' |
223 | 'return_id bigint,' | 223 | 'return_id bigint,' |
224 | 'parent_call_path_id bigint,' | 224 | 'parent_call_path_id bigint,' |
225 | 'flags integer)') | 225 | 'flags integer,' |
226 | 'parent_id bigint)') | ||
226 | 227 | ||
227 | # printf was added to sqlite in version 3.8.3 | 228 | # printf was added to sqlite in version 3.8.3 |
228 | sqlite_has_printf = False | 229 | sqlite_has_printf = False |
@@ -321,7 +322,8 @@ if perf_db_export_calls: | |||
321 | 'call_id,' | 322 | 'call_id,' |
322 | 'return_id,' | 323 | 'return_id,' |
323 | 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,' | 324 | 'CASE WHEN flags=0 THEN \'\' WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' WHEN flags=6 THEN \'jump\' ELSE flags END AS flags,' |
324 | 'parent_call_path_id' | 325 | 'parent_call_path_id,' |
326 | 'parent_id' | ||
325 | ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id') | 327 | ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id') |
326 | 328 | ||
327 | do_query(query, 'CREATE VIEW samples_view AS ' | 329 | do_query(query, 'CREATE VIEW samples_view AS ' |
@@ -373,7 +375,7 @@ if perf_db_export_calls or perf_db_export_callchains: | |||
373 | call_path_query.prepare("INSERT INTO call_paths VALUES (?, ?, ?, ?)") | 375 | call_path_query.prepare("INSERT INTO call_paths VALUES (?, ?, ?, ?)") |
374 | if perf_db_export_calls: | 376 | if perf_db_export_calls: |
375 | call_query = QSqlQuery(db) | 377 | call_query = QSqlQuery(db) |
376 | call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") | 378 | call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") |
377 | 379 | ||
378 | def trace_begin(): | 380 | def trace_begin(): |
379 | print datetime.datetime.today(), "Writing records..." | 381 | print datetime.datetime.today(), "Writing records..." |
@@ -388,6 +390,7 @@ def trace_begin(): | |||
388 | sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | 390 | sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
389 | if perf_db_export_calls or perf_db_export_callchains: | 391 | if perf_db_export_calls or perf_db_export_callchains: |
390 | call_path_table(0, 0, 0, 0) | 392 | call_path_table(0, 0, 0, 0) |
393 | call_return_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | ||
391 | 394 | ||
392 | unhandled_count = 0 | 395 | unhandled_count = 0 |
393 | 396 | ||
@@ -397,6 +400,7 @@ def trace_end(): | |||
397 | print datetime.datetime.today(), "Adding indexes" | 400 | print datetime.datetime.today(), "Adding indexes" |
398 | if perf_db_export_calls: | 401 | if perf_db_export_calls: |
399 | do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)') | 402 | do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)') |
403 | do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)') | ||
400 | 404 | ||
401 | if (unhandled_count): | 405 | if (unhandled_count): |
402 | print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events" | 406 | print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events" |
@@ -452,4 +456,4 @@ def call_path_table(*x): | |||
452 | bind_exec(call_path_query, 4, x) | 456 | bind_exec(call_path_query, 4, x) |
453 | 457 | ||
454 | def call_return_table(*x): | 458 | def call_return_table(*x): |
455 | bind_exec(call_query, 11, x) | 459 | bind_exec(call_query, 12, x) |
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index 09ce73b07d35..afec9479ca7f 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py | |||
@@ -167,9 +167,10 @@ class Thread(QThread): | |||
167 | 167 | ||
168 | class TreeModel(QAbstractItemModel): | 168 | class TreeModel(QAbstractItemModel): |
169 | 169 | ||
170 | def __init__(self, root, parent=None): | 170 | def __init__(self, glb, parent=None): |
171 | super(TreeModel, self).__init__(parent) | 171 | super(TreeModel, self).__init__(parent) |
172 | self.root = root | 172 | self.glb = glb |
173 | self.root = self.GetRoot() | ||
173 | self.last_row_read = 0 | 174 | self.last_row_read = 0 |
174 | 175 | ||
175 | def Item(self, parent): | 176 | def Item(self, parent): |
@@ -557,24 +558,12 @@ class CallGraphRootItem(CallGraphLevelItemBase): | |||
557 | self.child_items.append(child_item) | 558 | self.child_items.append(child_item) |
558 | self.child_count += 1 | 559 | self.child_count += 1 |
559 | 560 | ||
560 | # Context-sensitive call graph data model | 561 | # Context-sensitive call graph data model base |
561 | 562 | ||
562 | class CallGraphModel(TreeModel): | 563 | class CallGraphModelBase(TreeModel): |
563 | 564 | ||
564 | def __init__(self, glb, parent=None): | 565 | def __init__(self, glb, parent=None): |
565 | super(CallGraphModel, self).__init__(CallGraphRootItem(glb), parent) | 566 | super(CallGraphModelBase, self).__init__(glb, parent) |
566 | self.glb = glb | ||
567 | |||
568 | def columnCount(self, parent=None): | ||
569 | return 7 | ||
570 | |||
571 | def columnHeader(self, column): | ||
572 | headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] | ||
573 | return headers[column] | ||
574 | |||
575 | def columnAlignment(self, column): | ||
576 | alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] | ||
577 | return alignment[column] | ||
578 | 567 | ||
579 | def FindSelect(self, value, pattern, query): | 568 | def FindSelect(self, value, pattern, query): |
580 | if pattern: | 569 | if pattern: |
@@ -594,34 +583,7 @@ class CallGraphModel(TreeModel): | |||
594 | match = " GLOB '" + str(value) + "'" | 583 | match = " GLOB '" + str(value) + "'" |
595 | else: | 584 | else: |
596 | match = " = '" + str(value) + "'" | 585 | match = " = '" + str(value) + "'" |
597 | QueryExec(query, "SELECT call_path_id, comm_id, thread_id" | 586 | self.DoFindSelect(query, match) |
598 | " FROM calls" | ||
599 | " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" | ||
600 | " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" | ||
601 | " WHERE symbols.name" + match + | ||
602 | " GROUP BY comm_id, thread_id, call_path_id" | ||
603 | " ORDER BY comm_id, thread_id, call_path_id") | ||
604 | |||
605 | def FindPath(self, query): | ||
606 | # Turn the query result into a list of ids that the tree view can walk | ||
607 | # to open the tree at the right place. | ||
608 | ids = [] | ||
609 | parent_id = query.value(0) | ||
610 | while parent_id: | ||
611 | ids.insert(0, parent_id) | ||
612 | q2 = QSqlQuery(self.glb.db) | ||
613 | QueryExec(q2, "SELECT parent_id" | ||
614 | " FROM call_paths" | ||
615 | " WHERE id = " + str(parent_id)) | ||
616 | if not q2.next(): | ||
617 | break | ||
618 | parent_id = q2.value(0) | ||
619 | # The call path root is not used | ||
620 | if ids[0] == 1: | ||
621 | del ids[0] | ||
622 | ids.insert(0, query.value(2)) | ||
623 | ids.insert(0, query.value(1)) | ||
624 | return ids | ||
625 | 587 | ||
626 | def Found(self, query, found): | 588 | def Found(self, query, found): |
627 | if found: | 589 | if found: |
@@ -675,6 +637,201 @@ class CallGraphModel(TreeModel): | |||
675 | def FindDone(self, thread, callback, ids): | 637 | def FindDone(self, thread, callback, ids): |
676 | callback(ids) | 638 | callback(ids) |
677 | 639 | ||
640 | # Context-sensitive call graph data model | ||
641 | |||
642 | class CallGraphModel(CallGraphModelBase): | ||
643 | |||
644 | def __init__(self, glb, parent=None): | ||
645 | super(CallGraphModel, self).__init__(glb, parent) | ||
646 | |||
647 | def GetRoot(self): | ||
648 | return CallGraphRootItem(self.glb) | ||
649 | |||
650 | def columnCount(self, parent=None): | ||
651 | return 7 | ||
652 | |||
653 | def columnHeader(self, column): | ||
654 | headers = ["Call Path", "Object", "Count ", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] | ||
655 | return headers[column] | ||
656 | |||
657 | def columnAlignment(self, column): | ||
658 | alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] | ||
659 | return alignment[column] | ||
660 | |||
661 | def DoFindSelect(self, query, match): | ||
662 | QueryExec(query, "SELECT call_path_id, comm_id, thread_id" | ||
663 | " FROM calls" | ||
664 | " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" | ||
665 | " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" | ||
666 | " WHERE symbols.name" + match + | ||
667 | " GROUP BY comm_id, thread_id, call_path_id" | ||
668 | " ORDER BY comm_id, thread_id, call_path_id") | ||
669 | |||
670 | def FindPath(self, query): | ||
671 | # Turn the query result into a list of ids that the tree view can walk | ||
672 | # to open the tree at the right place. | ||
673 | ids = [] | ||
674 | parent_id = query.value(0) | ||
675 | while parent_id: | ||
676 | ids.insert(0, parent_id) | ||
677 | q2 = QSqlQuery(self.glb.db) | ||
678 | QueryExec(q2, "SELECT parent_id" | ||
679 | " FROM call_paths" | ||
680 | " WHERE id = " + str(parent_id)) | ||
681 | if not q2.next(): | ||
682 | break | ||
683 | parent_id = q2.value(0) | ||
684 | # The call path root is not used | ||
685 | if ids[0] == 1: | ||
686 | del ids[0] | ||
687 | ids.insert(0, query.value(2)) | ||
688 | ids.insert(0, query.value(1)) | ||
689 | return ids | ||
690 | |||
691 | # Call tree data model level 2+ item base | ||
692 | |||
693 | class CallTreeLevelTwoPlusItemBase(CallGraphLevelItemBase): | ||
694 | |||
695 | def __init__(self, glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item): | ||
696 | super(CallTreeLevelTwoPlusItemBase, self).__init__(glb, row, parent_item) | ||
697 | self.comm_id = comm_id | ||
698 | self.thread_id = thread_id | ||
699 | self.calls_id = calls_id | ||
700 | self.branch_count = branch_count | ||
701 | self.time = time | ||
702 | |||
703 | def Select(self): | ||
704 | self.query_done = True; | ||
705 | if self.calls_id == 0: | ||
706 | comm_thread = " AND comm_id = " + str(self.comm_id) + " AND thread_id = " + str(self.thread_id) | ||
707 | else: | ||
708 | comm_thread = "" | ||
709 | query = QSqlQuery(self.glb.db) | ||
710 | QueryExec(query, "SELECT calls.id, name, short_name, call_time, return_time - call_time, branch_count" | ||
711 | " FROM calls" | ||
712 | " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" | ||
713 | " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" | ||
714 | " INNER JOIN dsos ON symbols.dso_id = dsos.id" | ||
715 | " WHERE calls.parent_id = " + str(self.calls_id) + comm_thread + | ||
716 | " ORDER BY call_time, calls.id") | ||
717 | while query.next(): | ||
718 | child_item = CallTreeLevelThreeItem(self.glb, self.child_count, self.comm_id, self.thread_id, query.value(0), query.value(1), query.value(2), query.value(3), int(query.value(4)), int(query.value(5)), self) | ||
719 | self.child_items.append(child_item) | ||
720 | self.child_count += 1 | ||
721 | |||
722 | # Call tree data model level three item | ||
723 | |||
724 | class CallTreeLevelThreeItem(CallTreeLevelTwoPlusItemBase): | ||
725 | |||
726 | def __init__(self, glb, row, comm_id, thread_id, calls_id, name, dso, count, time, branch_count, parent_item): | ||
727 | super(CallTreeLevelThreeItem, self).__init__(glb, row, comm_id, thread_id, calls_id, time, branch_count, parent_item) | ||
728 | dso = dsoname(dso) | ||
729 | self.data = [ name, dso, str(count), str(time), PercentToOneDP(time, parent_item.time), str(branch_count), PercentToOneDP(branch_count, parent_item.branch_count) ] | ||
730 | self.dbid = calls_id | ||
731 | |||
732 | # Call tree data model level two item | ||
733 | |||
734 | class CallTreeLevelTwoItem(CallTreeLevelTwoPlusItemBase): | ||
735 | |||
736 | def __init__(self, glb, row, comm_id, thread_id, pid, tid, parent_item): | ||
737 | super(CallTreeLevelTwoItem, self).__init__(glb, row, comm_id, thread_id, 0, 0, 0, parent_item) | ||
738 | self.data = [str(pid) + ":" + str(tid), "", "", "", "", "", ""] | ||
739 | self.dbid = thread_id | ||
740 | |||
741 | def Select(self): | ||
742 | super(CallTreeLevelTwoItem, self).Select() | ||
743 | for child_item in self.child_items: | ||
744 | self.time += child_item.time | ||
745 | self.branch_count += child_item.branch_count | ||
746 | for child_item in self.child_items: | ||
747 | child_item.data[4] = PercentToOneDP(child_item.time, self.time) | ||
748 | child_item.data[6] = PercentToOneDP(child_item.branch_count, self.branch_count) | ||
749 | |||
750 | # Call tree data model level one item | ||
751 | |||
752 | class CallTreeLevelOneItem(CallGraphLevelItemBase): | ||
753 | |||
754 | def __init__(self, glb, row, comm_id, comm, parent_item): | ||
755 | super(CallTreeLevelOneItem, self).__init__(glb, row, parent_item) | ||
756 | self.data = [comm, "", "", "", "", "", ""] | ||
757 | self.dbid = comm_id | ||
758 | |||
759 | def Select(self): | ||
760 | self.query_done = True; | ||
761 | query = QSqlQuery(self.glb.db) | ||
762 | QueryExec(query, "SELECT thread_id, pid, tid" | ||
763 | " FROM comm_threads" | ||
764 | " INNER JOIN threads ON thread_id = threads.id" | ||
765 | " WHERE comm_id = " + str(self.dbid)) | ||
766 | while query.next(): | ||
767 | child_item = CallTreeLevelTwoItem(self.glb, self.child_count, self.dbid, query.value(0), query.value(1), query.value(2), self) | ||
768 | self.child_items.append(child_item) | ||
769 | self.child_count += 1 | ||
770 | |||
771 | # Call tree data model root item | ||
772 | |||
773 | class CallTreeRootItem(CallGraphLevelItemBase): | ||
774 | |||
775 | def __init__(self, glb): | ||
776 | super(CallTreeRootItem, self).__init__(glb, 0, None) | ||
777 | self.dbid = 0 | ||
778 | self.query_done = True; | ||
779 | query = QSqlQuery(glb.db) | ||
780 | QueryExec(query, "SELECT id, comm FROM comms") | ||
781 | while query.next(): | ||
782 | if not query.value(0): | ||
783 | continue | ||
784 | child_item = CallTreeLevelOneItem(glb, self.child_count, query.value(0), query.value(1), self) | ||
785 | self.child_items.append(child_item) | ||
786 | self.child_count += 1 | ||
787 | |||
788 | # Call Tree data model | ||
789 | |||
790 | class CallTreeModel(CallGraphModelBase): | ||
791 | |||
792 | def __init__(self, glb, parent=None): | ||
793 | super(CallTreeModel, self).__init__(glb, parent) | ||
794 | |||
795 | def GetRoot(self): | ||
796 | return CallTreeRootItem(self.glb) | ||
797 | |||
798 | def columnCount(self, parent=None): | ||
799 | return 7 | ||
800 | |||
801 | def columnHeader(self, column): | ||
802 | headers = ["Call Path", "Object", "Call Time", "Time (ns) ", "Time (%) ", "Branch Count ", "Branch Count (%) "] | ||
803 | return headers[column] | ||
804 | |||
805 | def columnAlignment(self, column): | ||
806 | alignment = [ Qt.AlignLeft, Qt.AlignLeft, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight, Qt.AlignRight ] | ||
807 | return alignment[column] | ||
808 | |||
809 | def DoFindSelect(self, query, match): | ||
810 | QueryExec(query, "SELECT calls.id, comm_id, thread_id" | ||
811 | " FROM calls" | ||
812 | " INNER JOIN call_paths ON calls.call_path_id = call_paths.id" | ||
813 | " INNER JOIN symbols ON call_paths.symbol_id = symbols.id" | ||
814 | " WHERE symbols.name" + match + | ||
815 | " ORDER BY comm_id, thread_id, call_time, calls.id") | ||
816 | |||
817 | def FindPath(self, query): | ||
818 | # Turn the query result into a list of ids that the tree view can walk | ||
819 | # to open the tree at the right place. | ||
820 | ids = [] | ||
821 | parent_id = query.value(0) | ||
822 | while parent_id: | ||
823 | ids.insert(0, parent_id) | ||
824 | q2 = QSqlQuery(self.glb.db) | ||
825 | QueryExec(q2, "SELECT parent_id" | ||
826 | " FROM calls" | ||
827 | " WHERE id = " + str(parent_id)) | ||
828 | if not q2.next(): | ||
829 | break | ||
830 | parent_id = q2.value(0) | ||
831 | ids.insert(0, query.value(2)) | ||
832 | ids.insert(0, query.value(1)) | ||
833 | return ids | ||
834 | |||
678 | # Vertical widget layout | 835 | # Vertical widget layout |
679 | 836 | ||
680 | class VBox(): | 837 | class VBox(): |
@@ -693,28 +850,16 @@ class VBox(): | |||
693 | def Widget(self): | 850 | def Widget(self): |
694 | return self.vbox | 851 | return self.vbox |
695 | 852 | ||
696 | # Context-sensitive call graph window | 853 | # Tree window base |
697 | |||
698 | class CallGraphWindow(QMdiSubWindow): | ||
699 | |||
700 | def __init__(self, glb, parent=None): | ||
701 | super(CallGraphWindow, self).__init__(parent) | ||
702 | |||
703 | self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x)) | ||
704 | |||
705 | self.view = QTreeView() | ||
706 | self.view.setModel(self.model) | ||
707 | |||
708 | for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)): | ||
709 | self.view.setColumnWidth(c, w) | ||
710 | |||
711 | self.find_bar = FindBar(self, self) | ||
712 | 854 | ||
713 | self.vbox = VBox(self.view, self.find_bar.Widget()) | 855 | class TreeWindowBase(QMdiSubWindow): |
714 | 856 | ||
715 | self.setWidget(self.vbox.Widget()) | 857 | def __init__(self, parent=None): |
858 | super(TreeWindowBase, self).__init__(parent) | ||
716 | 859 | ||
717 | AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph") | 860 | self.model = None |
861 | self.view = None | ||
862 | self.find_bar = None | ||
718 | 863 | ||
719 | def DisplayFound(self, ids): | 864 | def DisplayFound(self, ids): |
720 | if not len(ids): | 865 | if not len(ids): |
@@ -747,6 +892,53 @@ class CallGraphWindow(QMdiSubWindow): | |||
747 | if not found: | 892 | if not found: |
748 | self.find_bar.NotFound() | 893 | self.find_bar.NotFound() |
749 | 894 | ||
895 | |||
896 | # Context-sensitive call graph window | ||
897 | |||
898 | class CallGraphWindow(TreeWindowBase): | ||
899 | |||
900 | def __init__(self, glb, parent=None): | ||
901 | super(CallGraphWindow, self).__init__(parent) | ||
902 | |||
903 | self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x)) | ||
904 | |||
905 | self.view = QTreeView() | ||
906 | self.view.setModel(self.model) | ||
907 | |||
908 | for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)): | ||
909 | self.view.setColumnWidth(c, w) | ||
910 | |||
911 | self.find_bar = FindBar(self, self) | ||
912 | |||
913 | self.vbox = VBox(self.view, self.find_bar.Widget()) | ||
914 | |||
915 | self.setWidget(self.vbox.Widget()) | ||
916 | |||
917 | AddSubWindow(glb.mainwindow.mdi_area, self, "Context-Sensitive Call Graph") | ||
918 | |||
919 | # Call tree window | ||
920 | |||
921 | class CallTreeWindow(TreeWindowBase): | ||
922 | |||
923 | def __init__(self, glb, parent=None): | ||
924 | super(CallTreeWindow, self).__init__(parent) | ||
925 | |||
926 | self.model = LookupCreateModel("Call Tree", lambda x=glb: CallTreeModel(x)) | ||
927 | |||
928 | self.view = QTreeView() | ||
929 | self.view.setModel(self.model) | ||
930 | |||
931 | for c, w in ((0, 230), (1, 100), (2, 100), (3, 70), (4, 70), (5, 100)): | ||
932 | self.view.setColumnWidth(c, w) | ||
933 | |||
934 | self.find_bar = FindBar(self, self) | ||
935 | |||
936 | self.vbox = VBox(self.view, self.find_bar.Widget()) | ||
937 | |||
938 | self.setWidget(self.vbox.Widget()) | ||
939 | |||
940 | AddSubWindow(glb.mainwindow.mdi_area, self, "Call Tree") | ||
941 | |||
750 | # Child data item finder | 942 | # Child data item finder |
751 | 943 | ||
752 | class ChildDataItemFinder(): | 944 | class ChildDataItemFinder(): |
@@ -1327,8 +1519,7 @@ class BranchModel(TreeModel): | |||
1327 | progress = Signal(object) | 1519 | progress = Signal(object) |
1328 | 1520 | ||
1329 | def __init__(self, glb, event_id, where_clause, parent=None): | 1521 | def __init__(self, glb, event_id, where_clause, parent=None): |
1330 | super(BranchModel, self).__init__(BranchRootItem(), parent) | 1522 | super(BranchModel, self).__init__(glb, parent) |
1331 | self.glb = glb | ||
1332 | self.event_id = event_id | 1523 | self.event_id = event_id |
1333 | self.more = True | 1524 | self.more = True |
1334 | self.populated = 0 | 1525 | self.populated = 0 |
@@ -1352,6 +1543,9 @@ class BranchModel(TreeModel): | |||
1352 | self.fetcher.done.connect(self.Update) | 1543 | self.fetcher.done.connect(self.Update) |
1353 | self.fetcher.Fetch(glb_chunk_sz) | 1544 | self.fetcher.Fetch(glb_chunk_sz) |
1354 | 1545 | ||
1546 | def GetRoot(self): | ||
1547 | return BranchRootItem() | ||
1548 | |||
1355 | def columnCount(self, parent=None): | 1549 | def columnCount(self, parent=None): |
1356 | return 8 | 1550 | return 8 |
1357 | 1551 | ||
@@ -1863,10 +2057,10 @@ def GetEventList(db): | |||
1863 | 2057 | ||
1864 | # Is a table selectable | 2058 | # Is a table selectable |
1865 | 2059 | ||
1866 | def IsSelectable(db, table): | 2060 | def IsSelectable(db, table, sql = ""): |
1867 | query = QSqlQuery(db) | 2061 | query = QSqlQuery(db) |
1868 | try: | 2062 | try: |
1869 | QueryExec(query, "SELECT * FROM " + table + " LIMIT 1") | 2063 | QueryExec(query, "SELECT * FROM " + table + " " + sql + " LIMIT 1") |
1870 | except: | 2064 | except: |
1871 | return False | 2065 | return False |
1872 | return True | 2066 | return True |
@@ -2275,9 +2469,10 @@ p.c2 { | |||
2275 | </style> | 2469 | </style> |
2276 | <p class=c1><a href=#reports>1. Reports</a></p> | 2470 | <p class=c1><a href=#reports>1. Reports</a></p> |
2277 | <p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p> | 2471 | <p class=c2><a href=#callgraph>1.1 Context-Sensitive Call Graph</a></p> |
2278 | <p class=c2><a href=#allbranches>1.2 All branches</a></p> | 2472 | <p class=c2><a href=#calltree>1.2 Call Tree</a></p> |
2279 | <p class=c2><a href=#selectedbranches>1.3 Selected branches</a></p> | 2473 | <p class=c2><a href=#allbranches>1.3 All branches</a></p> |
2280 | <p class=c2><a href=#topcallsbyelapsedtime>1.4 Top calls by elapsed time</a></p> | 2474 | <p class=c2><a href=#selectedbranches>1.4 Selected branches</a></p> |
2475 | <p class=c2><a href=#topcallsbyelapsedtime>1.5 Top calls by elapsed time</a></p> | ||
2281 | <p class=c1><a href=#tables>2. Tables</a></p> | 2476 | <p class=c1><a href=#tables>2. Tables</a></p> |
2282 | <h1 id=reports>1. Reports</h1> | 2477 | <h1 id=reports>1. Reports</h1> |
2283 | <h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2> | 2478 | <h2 id=callgraph>1.1 Context-Sensitive Call Graph</h2> |
@@ -2313,7 +2508,10 @@ v- ls | |||
2313 | <h3>Find</h3> | 2508 | <h3>Find</h3> |
2314 | Ctrl-F displays a Find bar which finds function names by either an exact match or a pattern match. | 2509 | Ctrl-F displays a Find bar which finds function names by either an exact match or a pattern match. |
2315 | The pattern matching symbols are ? for any character and * for zero or more characters. | 2510 | The pattern matching symbols are ? for any character and * for zero or more characters. |
2316 | <h2 id=allbranches>1.2 All branches</h2> | 2511 | <h2 id=calltree>1.2 Call Tree</h2> |
2512 | The Call Tree report is very similar to the Context-Sensitive Call Graph, but the data is not aggregated. | ||
2513 | Also the 'Count' column, which would be always 1, is replaced by the 'Call Time'. | ||
2514 | <h2 id=allbranches>1.3 All branches</h2> | ||
2317 | The All branches report displays all branches in chronological order. | 2515 | The All branches report displays all branches in chronological order. |
2318 | Not all data is fetched immediately. More records can be fetched using the Fetch bar provided. | 2516 | Not all data is fetched immediately. More records can be fetched using the Fetch bar provided. |
2319 | <h3>Disassembly</h3> | 2517 | <h3>Disassembly</h3> |
@@ -2339,10 +2537,10 @@ sudo ldconfig | |||
2339 | Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. | 2537 | Ctrl-F displays a Find bar which finds substrings by either an exact match or a regular expression match. |
2340 | Refer to Python documentation for the regular expression syntax. | 2538 | Refer to Python documentation for the regular expression syntax. |
2341 | All columns are searched, but only currently fetched rows are searched. | 2539 | All columns are searched, but only currently fetched rows are searched. |
2342 | <h2 id=selectedbranches>1.3 Selected branches</h2> | 2540 | <h2 id=selectedbranches>1.4 Selected branches</h2> |
2343 | This is the same as the <a href=#allbranches>All branches</a> report but with the data reduced | 2541 | This is the same as the <a href=#allbranches>All branches</a> report but with the data reduced |
2344 | by various selection criteria. A dialog box displays available criteria which are AND'ed together. | 2542 | by various selection criteria. A dialog box displays available criteria which are AND'ed together. |
2345 | <h3>1.3.1 Time ranges</h3> | 2543 | <h3>1.4.1 Time ranges</h3> |
2346 | The time ranges hint text shows the total time range. Relative time ranges can also be entered in | 2544 | The time ranges hint text shows the total time range. Relative time ranges can also be entered in |
2347 | ms, us or ns. Also, negative values are relative to the end of trace. Examples: | 2545 | ms, us or ns. Also, negative values are relative to the end of trace. Examples: |
2348 | <pre> | 2546 | <pre> |
@@ -2353,7 +2551,7 @@ ms, us or ns. Also, negative values are relative to the end of trace. Examples: | |||
2353 | -10ms- The last 10ms | 2551 | -10ms- The last 10ms |
2354 | </pre> | 2552 | </pre> |
2355 | N.B. Due to the granularity of timestamps, there could be no branches in any given time range. | 2553 | N.B. Due to the granularity of timestamps, there could be no branches in any given time range. |
2356 | <h2 id=topcallsbyelapsedtime>1.4 Top calls by elapsed time</h2> | 2554 | <h2 id=topcallsbyelapsedtime>1.5 Top calls by elapsed time</h2> |
2357 | The Top calls by elapsed time report displays calls in descending order of time elapsed between when the function was called and when it returned. | 2555 | The Top calls by elapsed time report displays calls in descending order of time elapsed between when the function was called and when it returned. |
2358 | The data is reduced by various selection criteria. A dialog box displays available criteria which are AND'ed together. | 2556 | The data is reduced by various selection criteria. A dialog box displays available criteria which are AND'ed together. |
2359 | If not all data is fetched, a Fetch bar is provided. Ctrl-F displays a Find bar. | 2557 | If not all data is fetched, a Fetch bar is provided. Ctrl-F displays a Find bar. |
@@ -2489,6 +2687,9 @@ class MainWindow(QMainWindow): | |||
2489 | if IsSelectable(glb.db, "calls"): | 2687 | if IsSelectable(glb.db, "calls"): |
2490 | reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) | 2688 | reports_menu.addAction(CreateAction("Context-Sensitive Call &Graph", "Create a new window containing a context-sensitive call graph", self.NewCallGraph, self)) |
2491 | 2689 | ||
2690 | if IsSelectable(glb.db, "calls", "WHERE parent_id >= 0"): | ||
2691 | reports_menu.addAction(CreateAction("Call &Tree", "Create a new window containing a call tree", self.NewCallTree, self)) | ||
2692 | |||
2492 | self.EventMenu(GetEventList(glb.db), reports_menu) | 2693 | self.EventMenu(GetEventList(glb.db), reports_menu) |
2493 | 2694 | ||
2494 | if IsSelectable(glb.db, "calls"): | 2695 | if IsSelectable(glb.db, "calls"): |
@@ -2549,6 +2750,9 @@ class MainWindow(QMainWindow): | |||
2549 | def NewCallGraph(self): | 2750 | def NewCallGraph(self): |
2550 | CallGraphWindow(self.glb, self) | 2751 | CallGraphWindow(self.glb, self) |
2551 | 2752 | ||
2753 | def NewCallTree(self): | ||
2754 | CallTreeWindow(self.glb, self) | ||
2755 | |||
2552 | def NewTopCalls(self): | 2756 | def NewTopCalls(self): |
2553 | dialog = TopCallsDialog(self.glb, self) | 2757 | dialog = TopCallsDialog(self.glb, self) |
2554 | ret = dialog.exec_() | 2758 | ret = dialog.exec_() |
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py index 3648e8b986ec..310efe5e7e23 100644 --- a/tools/perf/scripts/python/failed-syscalls-by-pid.py +++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py | |||
@@ -58,22 +58,22 @@ def syscalls__sys_exit(event_name, context, common_cpu, | |||
58 | raw_syscalls__sys_exit(**locals()) | 58 | raw_syscalls__sys_exit(**locals()) |
59 | 59 | ||
60 | def print_error_totals(): | 60 | def print_error_totals(): |
61 | if for_comm is not None: | 61 | if for_comm is not None: |
62 | print("\nsyscall errors for %s:\n" % (for_comm)) | 62 | print("\nsyscall errors for %s:\n" % (for_comm)) |
63 | else: | 63 | else: |
64 | print("\nsyscall errors:\n") | 64 | print("\nsyscall errors:\n") |
65 | 65 | ||
66 | print("%-30s %10s" % ("comm [pid]", "count")) | 66 | print("%-30s %10s" % ("comm [pid]", "count")) |
67 | print("%-30s %10s" % ("------------------------------", "----------")) | 67 | print("%-30s %10s" % ("------------------------------", "----------")) |
68 | 68 | ||
69 | comm_keys = syscalls.keys() | 69 | comm_keys = syscalls.keys() |
70 | for comm in comm_keys: | 70 | for comm in comm_keys: |
71 | pid_keys = syscalls[comm].keys() | 71 | pid_keys = syscalls[comm].keys() |
72 | for pid in pid_keys: | 72 | for pid in pid_keys: |
73 | print("\n%s [%d]" % (comm, pid)) | 73 | print("\n%s [%d]" % (comm, pid)) |
74 | id_keys = syscalls[comm][pid].keys() | 74 | id_keys = syscalls[comm][pid].keys() |
75 | for id in id_keys: | 75 | for id in id_keys: |
76 | print(" syscall: %-16s" % syscall_name(id)) | 76 | print(" syscall: %-16s" % syscall_name(id)) |
77 | ret_keys = syscalls[comm][pid][id].keys() | 77 | ret_keys = syscalls[comm][pid][id].keys() |
78 | for ret, val in sorted(syscalls[comm][pid][id].items(), key = lambda kv: (kv[1], kv[0]), reverse = True): | 78 | for ret, val in sorted(syscalls[comm][pid][id].items(), key = lambda kv: (kv[1], kv[0]), reverse = True): |
79 | print(" err = %-20s %10d" % (strerror(ret), val)) | 79 | print(" err = %-20s %10d" % (strerror(ret), val)) |
diff --git a/tools/perf/scripts/python/futex-contention.py b/tools/perf/scripts/python/futex-contention.py index 0f5cf437b602..0c4841acf75d 100644 --- a/tools/perf/scripts/python/futex-contention.py +++ b/tools/perf/scripts/python/futex-contention.py | |||
@@ -10,6 +10,8 @@ | |||
10 | # | 10 | # |
11 | # Measures futex contention | 11 | # Measures futex contention |
12 | 12 | ||
13 | from __future__ import print_function | ||
14 | |||
13 | import os, sys | 15 | import os, sys |
14 | sys.path.append(os.environ['PERF_EXEC_PATH'] + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 16 | sys.path.append(os.environ['PERF_EXEC_PATH'] + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') |
15 | from Util import * | 17 | from Util import * |
@@ -33,18 +35,18 @@ def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, | |||
33 | 35 | ||
34 | def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, | 36 | def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, |
35 | nr, ret): | 37 | nr, ret): |
36 | if thread_blocktime.has_key(tid): | 38 | if tid in thread_blocktime: |
37 | elapsed = nsecs(s, ns) - thread_blocktime[tid] | 39 | elapsed = nsecs(s, ns) - thread_blocktime[tid] |
38 | add_stats(lock_waits, (tid, thread_thislock[tid]), elapsed) | 40 | add_stats(lock_waits, (tid, thread_thislock[tid]), elapsed) |
39 | del thread_blocktime[tid] | 41 | del thread_blocktime[tid] |
40 | del thread_thislock[tid] | 42 | del thread_thislock[tid] |
41 | 43 | ||
42 | def trace_begin(): | 44 | def trace_begin(): |
43 | print "Press control+C to stop and show the summary" | 45 | print("Press control+C to stop and show the summary") |
44 | 46 | ||
45 | def trace_end(): | 47 | def trace_end(): |
46 | for (tid, lock) in lock_waits: | 48 | for (tid, lock) in lock_waits: |
47 | min, max, avg, count = lock_waits[tid, lock] | 49 | min, max, avg, count = lock_waits[tid, lock] |
48 | print "%s[%d] lock %x contended %d times, %d avg ns" % \ | 50 | print("%s[%d] lock %x contended %d times, %d avg ns" % |
49 | (process_names[tid], tid, lock, count, avg) | 51 | (process_names[tid], tid, lock, count, avg)) |
50 | 52 | ||
diff --git a/tools/perf/scripts/python/intel-pt-events.py b/tools/perf/scripts/python/intel-pt-events.py index b19172d673af..a73847c8f548 100644 --- a/tools/perf/scripts/python/intel-pt-events.py +++ b/tools/perf/scripts/python/intel-pt-events.py | |||
@@ -10,6 +10,8 @@ | |||
10 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 10 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
11 | # more details. | 11 | # more details. |
12 | 12 | ||
13 | from __future__ import print_function | ||
14 | |||
13 | import os | 15 | import os |
14 | import sys | 16 | import sys |
15 | import struct | 17 | import struct |
@@ -22,34 +24,34 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | |||
22 | #from Core import * | 24 | #from Core import * |
23 | 25 | ||
24 | def trace_begin(): | 26 | def trace_begin(): |
25 | print "Intel PT Power Events and PTWRITE" | 27 | print("Intel PT Power Events and PTWRITE") |
26 | 28 | ||
27 | def trace_end(): | 29 | def trace_end(): |
28 | print "End" | 30 | print("End") |
29 | 31 | ||
30 | def trace_unhandled(event_name, context, event_fields_dict): | 32 | def trace_unhandled(event_name, context, event_fields_dict): |
31 | print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())]) | 33 | print(' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])) |
32 | 34 | ||
33 | def print_ptwrite(raw_buf): | 35 | def print_ptwrite(raw_buf): |
34 | data = struct.unpack_from("<IQ", raw_buf) | 36 | data = struct.unpack_from("<IQ", raw_buf) |
35 | flags = data[0] | 37 | flags = data[0] |
36 | payload = data[1] | 38 | payload = data[1] |
37 | exact_ip = flags & 1 | 39 | exact_ip = flags & 1 |
38 | print "IP: %u payload: %#x" % (exact_ip, payload), | 40 | print("IP: %u payload: %#x" % (exact_ip, payload), end=' ') |
39 | 41 | ||
40 | def print_cbr(raw_buf): | 42 | def print_cbr(raw_buf): |
41 | data = struct.unpack_from("<BBBBII", raw_buf) | 43 | data = struct.unpack_from("<BBBBII", raw_buf) |
42 | cbr = data[0] | 44 | cbr = data[0] |
43 | f = (data[4] + 500) / 1000 | 45 | f = (data[4] + 500) / 1000 |
44 | p = ((cbr * 1000 / data[2]) + 5) / 10 | 46 | p = ((cbr * 1000 / data[2]) + 5) / 10 |
45 | print "%3u freq: %4u MHz (%3u%%)" % (cbr, f, p), | 47 | print("%3u freq: %4u MHz (%3u%%)" % (cbr, f, p), end=' ') |
46 | 48 | ||
47 | def print_mwait(raw_buf): | 49 | def print_mwait(raw_buf): |
48 | data = struct.unpack_from("<IQ", raw_buf) | 50 | data = struct.unpack_from("<IQ", raw_buf) |
49 | payload = data[1] | 51 | payload = data[1] |
50 | hints = payload & 0xff | 52 | hints = payload & 0xff |
51 | extensions = (payload >> 32) & 0x3 | 53 | extensions = (payload >> 32) & 0x3 |
52 | print "hints: %#x extensions: %#x" % (hints, extensions), | 54 | print("hints: %#x extensions: %#x" % (hints, extensions), end=' ') |
53 | 55 | ||
54 | def print_pwre(raw_buf): | 56 | def print_pwre(raw_buf): |
55 | data = struct.unpack_from("<IQ", raw_buf) | 57 | data = struct.unpack_from("<IQ", raw_buf) |
@@ -57,13 +59,14 @@ def print_pwre(raw_buf): | |||
57 | hw = (payload >> 7) & 1 | 59 | hw = (payload >> 7) & 1 |
58 | cstate = (payload >> 12) & 0xf | 60 | cstate = (payload >> 12) & 0xf |
59 | subcstate = (payload >> 8) & 0xf | 61 | subcstate = (payload >> 8) & 0xf |
60 | print "hw: %u cstate: %u sub-cstate: %u" % (hw, cstate, subcstate), | 62 | print("hw: %u cstate: %u sub-cstate: %u" % (hw, cstate, subcstate), |
63 | end=' ') | ||
61 | 64 | ||
62 | def print_exstop(raw_buf): | 65 | def print_exstop(raw_buf): |
63 | data = struct.unpack_from("<I", raw_buf) | 66 | data = struct.unpack_from("<I", raw_buf) |
64 | flags = data[0] | 67 | flags = data[0] |
65 | exact_ip = flags & 1 | 68 | exact_ip = flags & 1 |
66 | print "IP: %u" % (exact_ip), | 69 | print("IP: %u" % (exact_ip), end=' ') |
67 | 70 | ||
68 | def print_pwrx(raw_buf): | 71 | def print_pwrx(raw_buf): |
69 | data = struct.unpack_from("<IQ", raw_buf) | 72 | data = struct.unpack_from("<IQ", raw_buf) |
@@ -71,36 +74,39 @@ def print_pwrx(raw_buf): | |||
71 | deepest_cstate = payload & 0xf | 74 | deepest_cstate = payload & 0xf |
72 | last_cstate = (payload >> 4) & 0xf | 75 | last_cstate = (payload >> 4) & 0xf |
73 | wake_reason = (payload >> 8) & 0xf | 76 | wake_reason = (payload >> 8) & 0xf |
74 | print "deepest cstate: %u last cstate: %u wake reason: %#x" % (deepest_cstate, last_cstate, wake_reason), | 77 | print("deepest cstate: %u last cstate: %u wake reason: %#x" % |
78 | (deepest_cstate, last_cstate, wake_reason), end=' ') | ||
75 | 79 | ||
76 | def print_common_start(comm, sample, name): | 80 | def print_common_start(comm, sample, name): |
77 | ts = sample["time"] | 81 | ts = sample["time"] |
78 | cpu = sample["cpu"] | 82 | cpu = sample["cpu"] |
79 | pid = sample["pid"] | 83 | pid = sample["pid"] |
80 | tid = sample["tid"] | 84 | tid = sample["tid"] |
81 | print "%16s %5u/%-5u [%03u] %9u.%09u %7s:" % (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000, name), | 85 | print("%16s %5u/%-5u [%03u] %9u.%09u %7s:" % |
86 | (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000, name), | ||
87 | end=' ') | ||
82 | 88 | ||
83 | def print_common_ip(sample, symbol, dso): | 89 | def print_common_ip(sample, symbol, dso): |
84 | ip = sample["ip"] | 90 | ip = sample["ip"] |
85 | print "%16x %s (%s)" % (ip, symbol, dso) | 91 | print("%16x %s (%s)" % (ip, symbol, dso)) |
86 | 92 | ||
87 | def process_event(param_dict): | 93 | def process_event(param_dict): |
88 | event_attr = param_dict["attr"] | 94 | event_attr = param_dict["attr"] |
89 | sample = param_dict["sample"] | 95 | sample = param_dict["sample"] |
90 | raw_buf = param_dict["raw_buf"] | 96 | raw_buf = param_dict["raw_buf"] |
91 | comm = param_dict["comm"] | 97 | comm = param_dict["comm"] |
92 | name = param_dict["ev_name"] | 98 | name = param_dict["ev_name"] |
93 | 99 | ||
94 | # Symbol and dso info are not always resolved | 100 | # Symbol and dso info are not always resolved |
95 | if (param_dict.has_key("dso")): | 101 | if "dso" in param_dict: |
96 | dso = param_dict["dso"] | 102 | dso = param_dict["dso"] |
97 | else: | 103 | else: |
98 | dso = "[unknown]" | 104 | dso = "[unknown]" |
99 | 105 | ||
100 | if (param_dict.has_key("symbol")): | 106 | if "symbol" in param_dict: |
101 | symbol = param_dict["symbol"] | 107 | symbol = param_dict["symbol"] |
102 | else: | 108 | else: |
103 | symbol = "[unknown]" | 109 | symbol = "[unknown]" |
104 | 110 | ||
105 | if name == "ptwrite": | 111 | if name == "ptwrite": |
106 | print_common_start(comm, sample, name) | 112 | print_common_start(comm, sample, name) |
diff --git a/tools/perf/scripts/python/mem-phys-addr.py b/tools/perf/scripts/python/mem-phys-addr.py index fb0bbcbfa0f0..1f332e72b9b0 100644 --- a/tools/perf/scripts/python/mem-phys-addr.py +++ b/tools/perf/scripts/python/mem-phys-addr.py | |||
@@ -44,12 +44,13 @@ def print_memory_type(): | |||
44 | print("%-40s %10s %10s\n" % ("Memory type", "count", "percentage"), end='') | 44 | print("%-40s %10s %10s\n" % ("Memory type", "count", "percentage"), end='') |
45 | print("%-40s %10s %10s\n" % ("----------------------------------------", | 45 | print("%-40s %10s %10s\n" % ("----------------------------------------", |
46 | "-----------", "-----------"), | 46 | "-----------", "-----------"), |
47 | end=''); | 47 | end=''); |
48 | total = sum(load_mem_type_cnt.values()) | 48 | total = sum(load_mem_type_cnt.values()) |
49 | for mem_type, count in sorted(load_mem_type_cnt.most_common(), \ | 49 | for mem_type, count in sorted(load_mem_type_cnt.most_common(), \ |
50 | key = lambda kv: (kv[1], kv[0]), reverse = True): | 50 | key = lambda kv: (kv[1], kv[0]), reverse = True): |
51 | print("%-40s %10d %10.1f%%\n" % (mem_type, count, 100 * count / total), | 51 | print("%-40s %10d %10.1f%%\n" % |
52 | end='') | 52 | (mem_type, count, 100 * count / total), |
53 | end='') | ||
53 | 54 | ||
54 | def trace_begin(): | 55 | def trace_begin(): |
55 | parse_iomem() | 56 | parse_iomem() |
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py index 212557a02c50..101059971738 100755 --- a/tools/perf/scripts/python/net_dropmonitor.py +++ b/tools/perf/scripts/python/net_dropmonitor.py | |||
@@ -7,7 +7,7 @@ import os | |||
7 | import sys | 7 | import sys |
8 | 8 | ||
9 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 9 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
10 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 10 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') |
11 | 11 | ||
12 | from perf_trace_context import * | 12 | from perf_trace_context import * |
13 | from Core import * | 13 | from Core import * |
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py index 267bda49325d..ea0c8b90a783 100644 --- a/tools/perf/scripts/python/netdev-times.py +++ b/tools/perf/scripts/python/netdev-times.py | |||
@@ -124,14 +124,16 @@ def print_receive(hunk): | |||
124 | event = event_list[i] | 124 | event = event_list[i] |
125 | if event['event_name'] == 'napi_poll': | 125 | if event['event_name'] == 'napi_poll': |
126 | print(PF_NAPI_POLL % | 126 | print(PF_NAPI_POLL % |
127 | (diff_msec(base_t, event['event_t']), event['dev'])) | 127 | (diff_msec(base_t, event['event_t']), |
128 | event['dev'])) | ||
128 | if i == len(event_list) - 1: | 129 | if i == len(event_list) - 1: |
129 | print("") | 130 | print("") |
130 | else: | 131 | else: |
131 | print(PF_JOINT) | 132 | print(PF_JOINT) |
132 | else: | 133 | else: |
133 | print(PF_NET_RECV % | 134 | print(PF_NET_RECV % |
134 | (diff_msec(base_t, event['event_t']), event['skbaddr'], | 135 | (diff_msec(base_t, event['event_t']), |
136 | event['skbaddr'], | ||
135 | event['len'])) | 137 | event['len'])) |
136 | if 'comm' in event.keys(): | 138 | if 'comm' in event.keys(): |
137 | print(PF_WJOINT) | 139 | print(PF_WJOINT) |
@@ -256,7 +258,7 @@ def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, callchain, i | |||
256 | all_event_list.append(event_info) | 258 | all_event_list.append(event_info) |
257 | 259 | ||
258 | def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi, | 260 | def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi, |
259 | dev_name, work=None, budget=None): | 261 | dev_name, work=None, budget=None): |
260 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, | 262 | event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, |
261 | napi, dev_name, work, budget) | 263 | napi, dev_name, work, budget) |
262 | all_event_list.append(event_info) | 264 | all_event_list.append(event_info) |
@@ -353,7 +355,7 @@ def handle_irq_softirq_exit(event_info): | |||
353 | if irq_list == [] or event_list == 0: | 355 | if irq_list == [] or event_list == 0: |
354 | return | 356 | return |
355 | rec_data = {'sirq_ent_t':sirq_ent_t, 'sirq_ext_t':time, | 357 | rec_data = {'sirq_ent_t':sirq_ent_t, 'sirq_ext_t':time, |
356 | 'irq_list':irq_list, 'event_list':event_list} | 358 | 'irq_list':irq_list, 'event_list':event_list} |
357 | # merge information realted to a NET_RX softirq | 359 | # merge information realted to a NET_RX softirq |
358 | receive_hunk_list.append(rec_data) | 360 | receive_hunk_list.append(rec_data) |
359 | 361 | ||
@@ -390,7 +392,7 @@ def handle_netif_receive_skb(event_info): | |||
390 | skbaddr, skblen, dev_name) = event_info | 392 | skbaddr, skblen, dev_name) = event_info |
391 | if cpu in net_rx_dic.keys(): | 393 | if cpu in net_rx_dic.keys(): |
392 | rec_data = {'event_name':'netif_receive_skb', | 394 | rec_data = {'event_name':'netif_receive_skb', |
393 | 'event_t':time, 'skbaddr':skbaddr, 'len':skblen} | 395 | 'event_t':time, 'skbaddr':skbaddr, 'len':skblen} |
394 | event_list = net_rx_dic[cpu]['event_list'] | 396 | event_list = net_rx_dic[cpu]['event_list'] |
395 | event_list.append(rec_data) | 397 | event_list.append(rec_data) |
396 | rx_skb_list.insert(0, rec_data) | 398 | rx_skb_list.insert(0, rec_data) |
diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py index 3984bf51f3c5..8196e3087c9e 100644 --- a/tools/perf/scripts/python/sched-migration.py +++ b/tools/perf/scripts/python/sched-migration.py | |||
@@ -14,10 +14,10 @@ import sys | |||
14 | 14 | ||
15 | from collections import defaultdict | 15 | from collections import defaultdict |
16 | try: | 16 | try: |
17 | from UserList import UserList | 17 | from UserList import UserList |
18 | except ImportError: | 18 | except ImportError: |
19 | # Python 3: UserList moved to the collections package | 19 | # Python 3: UserList moved to the collections package |
20 | from collections import UserList | 20 | from collections import UserList |
21 | 21 | ||
22 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 22 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
23 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 23 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') |
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py index 987ffae7c8ca..6e0278dcb092 100644 --- a/tools/perf/scripts/python/sctop.py +++ b/tools/perf/scripts/python/sctop.py | |||
@@ -13,9 +13,9 @@ from __future__ import print_function | |||
13 | import os, sys, time | 13 | import os, sys, time |
14 | 14 | ||
15 | try: | 15 | try: |
16 | import thread | 16 | import thread |
17 | except ImportError: | 17 | except ImportError: |
18 | import _thread as thread | 18 | import _thread as thread |
19 | 19 | ||
20 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 20 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
21 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 21 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') |
@@ -75,11 +75,12 @@ def print_syscall_totals(interval): | |||
75 | 75 | ||
76 | print("%-40s %10s" % ("event", "count")) | 76 | print("%-40s %10s" % ("event", "count")) |
77 | print("%-40s %10s" % | 77 | print("%-40s %10s" % |
78 | ("----------------------------------------", | 78 | ("----------------------------------------", |
79 | "----------")) | 79 | "----------")) |
80 | 80 | ||
81 | for id, val in sorted(syscalls.items(), key = lambda kv: (kv[1], kv[0]), \ | 81 | for id, val in sorted(syscalls.items(), |
82 | reverse = True): | 82 | key = lambda kv: (kv[1], kv[0]), |
83 | reverse = True): | ||
83 | try: | 84 | try: |
84 | print("%-40s %10d" % (syscall_name(id), val)) | 85 | print("%-40s %10d" % (syscall_name(id), val)) |
85 | except TypeError: | 86 | except TypeError: |
diff --git a/tools/perf/scripts/python/stackcollapse.py b/tools/perf/scripts/python/stackcollapse.py index 5e703efaddcc..b1c4def1410a 100755 --- a/tools/perf/scripts/python/stackcollapse.py +++ b/tools/perf/scripts/python/stackcollapse.py | |||
@@ -27,7 +27,7 @@ from collections import defaultdict | |||
27 | from optparse import OptionParser, make_option | 27 | from optparse import OptionParser, make_option |
28 | 28 | ||
29 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | 29 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ |
30 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | 30 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') |
31 | 31 | ||
32 | from perf_trace_context import * | 32 | from perf_trace_context import * |
33 | from Core import * | 33 | from Core import * |
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py index 42782487b0e9..f254e40c6f0f 100644 --- a/tools/perf/scripts/python/syscall-counts-by-pid.py +++ b/tools/perf/scripts/python/syscall-counts-by-pid.py | |||
@@ -39,11 +39,10 @@ def trace_end(): | |||
39 | print_syscall_totals() | 39 | print_syscall_totals() |
40 | 40 | ||
41 | def raw_syscalls__sys_enter(event_name, context, common_cpu, | 41 | def raw_syscalls__sys_enter(event_name, context, common_cpu, |
42 | common_secs, common_nsecs, common_pid, common_comm, | 42 | common_secs, common_nsecs, common_pid, common_comm, |
43 | common_callchain, id, args): | 43 | common_callchain, id, args): |
44 | |||
45 | if (for_comm and common_comm != for_comm) or \ | 44 | if (for_comm and common_comm != for_comm) or \ |
46 | (for_pid and common_pid != for_pid ): | 45 | (for_pid and common_pid != for_pid ): |
47 | return | 46 | return |
48 | try: | 47 | try: |
49 | syscalls[common_comm][common_pid][id] += 1 | 48 | syscalls[common_comm][common_pid][id] += 1 |
@@ -51,26 +50,26 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu, | |||
51 | syscalls[common_comm][common_pid][id] = 1 | 50 | syscalls[common_comm][common_pid][id] = 1 |
52 | 51 | ||
53 | def syscalls__sys_enter(event_name, context, common_cpu, | 52 | def syscalls__sys_enter(event_name, context, common_cpu, |
54 | common_secs, common_nsecs, common_pid, common_comm, | 53 | common_secs, common_nsecs, common_pid, common_comm, |
55 | id, args): | 54 | id, args): |
56 | raw_syscalls__sys_enter(**locals()) | 55 | raw_syscalls__sys_enter(**locals()) |
57 | 56 | ||
58 | def print_syscall_totals(): | 57 | def print_syscall_totals(): |
59 | if for_comm is not None: | 58 | if for_comm is not None: |
60 | print("\nsyscall events for %s:\n" % (for_comm)) | 59 | print("\nsyscall events for %s:\n" % (for_comm)) |
61 | else: | 60 | else: |
62 | print("\nsyscall events by comm/pid:\n") | 61 | print("\nsyscall events by comm/pid:\n") |
63 | 62 | ||
64 | print("%-40s %10s" % ("comm [pid]/syscalls", "count")) | 63 | print("%-40s %10s" % ("comm [pid]/syscalls", "count")) |
65 | print("%-40s %10s" % ("----------------------------------------", | 64 | print("%-40s %10s" % ("----------------------------------------", |
66 | "----------")) | 65 | "----------")) |
67 | 66 | ||
68 | comm_keys = syscalls.keys() | 67 | comm_keys = syscalls.keys() |
69 | for comm in comm_keys: | 68 | for comm in comm_keys: |
70 | pid_keys = syscalls[comm].keys() | 69 | pid_keys = syscalls[comm].keys() |
71 | for pid in pid_keys: | 70 | for pid in pid_keys: |
72 | print("\n%s [%d]" % (comm, pid)) | 71 | print("\n%s [%d]" % (comm, pid)) |
73 | id_keys = syscalls[comm][pid].keys() | 72 | id_keys = syscalls[comm][pid].keys() |
74 | for id, val in sorted(syscalls[comm][pid].items(), \ | 73 | for id, val in sorted(syscalls[comm][pid].items(), |
75 | key = lambda kv: (kv[1], kv[0]), reverse = True): | 74 | key = lambda kv: (kv[1], kv[0]), reverse = True): |
76 | print(" %-38s %10d" % (syscall_name(id), val)) | 75 | print(" %-38s %10d" % (syscall_name(id), val)) |
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py index 0ebd89cfd42c..8adb95ff1664 100644 --- a/tools/perf/scripts/python/syscall-counts.py +++ b/tools/perf/scripts/python/syscall-counts.py | |||
@@ -36,8 +36,8 @@ def trace_end(): | |||
36 | print_syscall_totals() | 36 | print_syscall_totals() |
37 | 37 | ||
38 | def raw_syscalls__sys_enter(event_name, context, common_cpu, | 38 | def raw_syscalls__sys_enter(event_name, context, common_cpu, |
39 | common_secs, common_nsecs, common_pid, common_comm, | 39 | common_secs, common_nsecs, common_pid, common_comm, |
40 | common_callchain, id, args): | 40 | common_callchain, id, args): |
41 | if for_comm is not None: | 41 | if for_comm is not None: |
42 | if common_comm != for_comm: | 42 | if common_comm != for_comm: |
43 | return | 43 | return |
@@ -47,20 +47,19 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu, | |||
47 | syscalls[id] = 1 | 47 | syscalls[id] = 1 |
48 | 48 | ||
49 | def syscalls__sys_enter(event_name, context, common_cpu, | 49 | def syscalls__sys_enter(event_name, context, common_cpu, |
50 | common_secs, common_nsecs, common_pid, common_comm, | 50 | common_secs, common_nsecs, common_pid, common_comm, id, args): |
51 | id, args): | ||
52 | raw_syscalls__sys_enter(**locals()) | 51 | raw_syscalls__sys_enter(**locals()) |
53 | 52 | ||
54 | def print_syscall_totals(): | 53 | def print_syscall_totals(): |
55 | if for_comm is not None: | 54 | if for_comm is not None: |
56 | print("\nsyscall events for %s:\n" % (for_comm)) | 55 | print("\nsyscall events for %s:\n" % (for_comm)) |
57 | else: | 56 | else: |
58 | print("\nsyscall events:\n") | 57 | print("\nsyscall events:\n") |
59 | 58 | ||
60 | print("%-40s %10s" % ("event", "count")) | 59 | print("%-40s %10s" % ("event", "count")) |
61 | print("%-40s %10s" % ("----------------------------------------", | 60 | print("%-40s %10s" % ("----------------------------------------", |
62 | "-----------")) | 61 | "-----------")) |
63 | 62 | ||
64 | for id, val in sorted(syscalls.items(), key = lambda kv: (kv[1], kv[0]), \ | 63 | for id, val in sorted(syscalls.items(), |
65 | reverse = True): | 64 | key = lambda kv: (kv[1], kv[0]), reverse = True): |
66 | print("%-40s %10d" % (syscall_name(id), val)) | 65 | print("%-40s %10d" % (syscall_name(id), val)) |
diff --git a/tools/perf/trace/beauty/msg_flags.c b/tools/perf/trace/beauty/msg_flags.c index d66c66315987..ea68db08b8e7 100644 --- a/tools/perf/trace/beauty/msg_flags.c +++ b/tools/perf/trace/beauty/msg_flags.c | |||
@@ -29,7 +29,7 @@ static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size, | |||
29 | return scnprintf(bf, size, "NONE"); | 29 | return scnprintf(bf, size, "NONE"); |
30 | #define P_MSG_FLAG(n) \ | 30 | #define P_MSG_FLAG(n) \ |
31 | if (flags & MSG_##n) { \ | 31 | if (flags & MSG_##n) { \ |
32 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ | 32 | printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ |
33 | flags &= ~MSG_##n; \ | 33 | flags &= ~MSG_##n; \ |
34 | } | 34 | } |
35 | 35 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 11a8a447a3af..5f6dbbf5d749 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -198,18 +198,18 @@ static void ins__delete(struct ins_operands *ops) | |||
198 | } | 198 | } |
199 | 199 | ||
200 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, | 200 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, |
201 | struct ins_operands *ops) | 201 | struct ins_operands *ops, int max_ins_name) |
202 | { | 202 | { |
203 | return scnprintf(bf, size, "%-6s %s", ins->name, ops->raw); | 203 | return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw); |
204 | } | 204 | } |
205 | 205 | ||
206 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, | 206 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, |
207 | struct ins_operands *ops) | 207 | struct ins_operands *ops, int max_ins_name) |
208 | { | 208 | { |
209 | if (ins->ops->scnprintf) | 209 | if (ins->ops->scnprintf) |
210 | return ins->ops->scnprintf(ins, bf, size, ops); | 210 | return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); |
211 | 211 | ||
212 | return ins__raw_scnprintf(ins, bf, size, ops); | 212 | return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); |
213 | } | 213 | } |
214 | 214 | ||
215 | bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) | 215 | bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) |
@@ -273,18 +273,18 @@ indirect_call: | |||
273 | } | 273 | } |
274 | 274 | ||
275 | static int call__scnprintf(struct ins *ins, char *bf, size_t size, | 275 | static int call__scnprintf(struct ins *ins, char *bf, size_t size, |
276 | struct ins_operands *ops) | 276 | struct ins_operands *ops, int max_ins_name) |
277 | { | 277 | { |
278 | if (ops->target.sym) | 278 | if (ops->target.sym) |
279 | return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name); | 279 | return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); |
280 | 280 | ||
281 | if (ops->target.addr == 0) | 281 | if (ops->target.addr == 0) |
282 | return ins__raw_scnprintf(ins, bf, size, ops); | 282 | return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); |
283 | 283 | ||
284 | if (ops->target.name) | 284 | if (ops->target.name) |
285 | return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.name); | 285 | return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); |
286 | 286 | ||
287 | return scnprintf(bf, size, "%-6s *%" PRIx64, ins->name, ops->target.addr); | 287 | return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr); |
288 | } | 288 | } |
289 | 289 | ||
290 | static struct ins_ops call_ops = { | 290 | static struct ins_ops call_ops = { |
@@ -388,15 +388,15 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s | |||
388 | } | 388 | } |
389 | 389 | ||
390 | static int jump__scnprintf(struct ins *ins, char *bf, size_t size, | 390 | static int jump__scnprintf(struct ins *ins, char *bf, size_t size, |
391 | struct ins_operands *ops) | 391 | struct ins_operands *ops, int max_ins_name) |
392 | { | 392 | { |
393 | const char *c; | 393 | const char *c; |
394 | 394 | ||
395 | if (!ops->target.addr || ops->target.offset < 0) | 395 | if (!ops->target.addr || ops->target.offset < 0) |
396 | return ins__raw_scnprintf(ins, bf, size, ops); | 396 | return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); |
397 | 397 | ||
398 | if (ops->target.outside && ops->target.sym != NULL) | 398 | if (ops->target.outside && ops->target.sym != NULL) |
399 | return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name); | 399 | return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); |
400 | 400 | ||
401 | c = strchr(ops->raw, ','); | 401 | c = strchr(ops->raw, ','); |
402 | c = validate_comma(c, ops); | 402 | c = validate_comma(c, ops); |
@@ -415,7 +415,7 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, | |||
415 | c++; | 415 | c++; |
416 | } | 416 | } |
417 | 417 | ||
418 | return scnprintf(bf, size, "%-6s %.*s%" PRIx64, | 418 | return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, |
419 | ins->name, c ? c - ops->raw : 0, ops->raw, | 419 | ins->name, c ? c - ops->raw : 0, ops->raw, |
420 | ops->target.offset); | 420 | ops->target.offset); |
421 | } | 421 | } |
@@ -483,16 +483,16 @@ out_free_ops: | |||
483 | } | 483 | } |
484 | 484 | ||
485 | static int lock__scnprintf(struct ins *ins, char *bf, size_t size, | 485 | static int lock__scnprintf(struct ins *ins, char *bf, size_t size, |
486 | struct ins_operands *ops) | 486 | struct ins_operands *ops, int max_ins_name) |
487 | { | 487 | { |
488 | int printed; | 488 | int printed; |
489 | 489 | ||
490 | if (ops->locked.ins.ops == NULL) | 490 | if (ops->locked.ins.ops == NULL) |
491 | return ins__raw_scnprintf(ins, bf, size, ops); | 491 | return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); |
492 | 492 | ||
493 | printed = scnprintf(bf, size, "%-6s ", ins->name); | 493 | printed = scnprintf(bf, size, "%-*s ", max_ins_name, ins->name); |
494 | return printed + ins__scnprintf(&ops->locked.ins, bf + printed, | 494 | return printed + ins__scnprintf(&ops->locked.ins, bf + printed, |
495 | size - printed, ops->locked.ops); | 495 | size - printed, ops->locked.ops, max_ins_name); |
496 | } | 496 | } |
497 | 497 | ||
498 | static void lock__delete(struct ins_operands *ops) | 498 | static void lock__delete(struct ins_operands *ops) |
@@ -564,9 +564,9 @@ out_free_source: | |||
564 | } | 564 | } |
565 | 565 | ||
566 | static int mov__scnprintf(struct ins *ins, char *bf, size_t size, | 566 | static int mov__scnprintf(struct ins *ins, char *bf, size_t size, |
567 | struct ins_operands *ops) | 567 | struct ins_operands *ops, int max_ins_name) |
568 | { | 568 | { |
569 | return scnprintf(bf, size, "%-6s %s,%s", ins->name, | 569 | return scnprintf(bf, size, "%-*s %s,%s", max_ins_name, ins->name, |
570 | ops->source.name ?: ops->source.raw, | 570 | ops->source.name ?: ops->source.raw, |
571 | ops->target.name ?: ops->target.raw); | 571 | ops->target.name ?: ops->target.raw); |
572 | } | 572 | } |
@@ -604,9 +604,9 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops | |||
604 | } | 604 | } |
605 | 605 | ||
606 | static int dec__scnprintf(struct ins *ins, char *bf, size_t size, | 606 | static int dec__scnprintf(struct ins *ins, char *bf, size_t size, |
607 | struct ins_operands *ops) | 607 | struct ins_operands *ops, int max_ins_name) |
608 | { | 608 | { |
609 | return scnprintf(bf, size, "%-6s %s", ins->name, | 609 | return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, |
610 | ops->target.name ?: ops->target.raw); | 610 | ops->target.name ?: ops->target.raw); |
611 | } | 611 | } |
612 | 612 | ||
@@ -616,9 +616,9 @@ static struct ins_ops dec_ops = { | |||
616 | }; | 616 | }; |
617 | 617 | ||
618 | static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, | 618 | static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, |
619 | struct ins_operands *ops __maybe_unused) | 619 | struct ins_operands *ops __maybe_unused, int max_ins_name) |
620 | { | 620 | { |
621 | return scnprintf(bf, size, "%-6s", "nop"); | 621 | return scnprintf(bf, size, "%-*s", max_ins_name, "nop"); |
622 | } | 622 | } |
623 | 623 | ||
624 | static struct ins_ops nop_ops = { | 624 | static struct ins_ops nop_ops = { |
@@ -1232,12 +1232,12 @@ void disasm_line__free(struct disasm_line *dl) | |||
1232 | annotation_line__delete(&dl->al); | 1232 | annotation_line__delete(&dl->al); |
1233 | } | 1233 | } |
1234 | 1234 | ||
1235 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) | 1235 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name) |
1236 | { | 1236 | { |
1237 | if (raw || !dl->ins.ops) | 1237 | if (raw || !dl->ins.ops) |
1238 | return scnprintf(bf, size, "%-6s %s", dl->ins.name, dl->ops.raw); | 1238 | return scnprintf(bf, size, "%-*s %s", max_ins_name, dl->ins.name, dl->ops.raw); |
1239 | 1239 | ||
1240 | return ins__scnprintf(&dl->ins, bf, size, &dl->ops); | 1240 | return ins__scnprintf(&dl->ins, bf, size, &dl->ops, max_ins_name); |
1241 | } | 1241 | } |
1242 | 1242 | ||
1243 | static void annotation_line__add(struct annotation_line *al, struct list_head *head) | 1243 | static void annotation_line__add(struct annotation_line *al, struct list_head *head) |
@@ -2414,12 +2414,30 @@ static inline int width_jumps(int n) | |||
2414 | return 1; | 2414 | return 1; |
2415 | } | 2415 | } |
2416 | 2416 | ||
2417 | static int annotation__max_ins_name(struct annotation *notes) | ||
2418 | { | ||
2419 | int max_name = 0, len; | ||
2420 | struct annotation_line *al; | ||
2421 | |||
2422 | list_for_each_entry(al, ¬es->src->source, node) { | ||
2423 | if (al->offset == -1) | ||
2424 | continue; | ||
2425 | |||
2426 | len = strlen(disasm_line(al)->ins.name); | ||
2427 | if (max_name < len) | ||
2428 | max_name = len; | ||
2429 | } | ||
2430 | |||
2431 | return max_name; | ||
2432 | } | ||
2433 | |||
2417 | void annotation__init_column_widths(struct annotation *notes, struct symbol *sym) | 2434 | void annotation__init_column_widths(struct annotation *notes, struct symbol *sym) |
2418 | { | 2435 | { |
2419 | notes->widths.addr = notes->widths.target = | 2436 | notes->widths.addr = notes->widths.target = |
2420 | notes->widths.min_addr = hex_width(symbol__size(sym)); | 2437 | notes->widths.min_addr = hex_width(symbol__size(sym)); |
2421 | notes->widths.max_addr = hex_width(sym->end); | 2438 | notes->widths.max_addr = hex_width(sym->end); |
2422 | notes->widths.jumps = width_jumps(notes->max_jump_sources); | 2439 | notes->widths.jumps = width_jumps(notes->max_jump_sources); |
2440 | notes->widths.max_ins_name = annotation__max_ins_name(notes); | ||
2423 | } | 2441 | } |
2424 | 2442 | ||
2425 | void annotation__update_column_widths(struct annotation *notes) | 2443 | void annotation__update_column_widths(struct annotation *notes) |
@@ -2583,7 +2601,7 @@ call_like: | |||
2583 | obj__printf(obj, " "); | 2601 | obj__printf(obj, " "); |
2584 | } | 2602 | } |
2585 | 2603 | ||
2586 | disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset); | 2604 | disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset, notes->widths.max_ins_name); |
2587 | } | 2605 | } |
2588 | 2606 | ||
2589 | static void ipc_coverage_string(char *bf, int size, struct annotation *notes) | 2607 | static void ipc_coverage_string(char *bf, int size, struct annotation *notes) |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 95053cab41fe..df34fe483164 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -59,14 +59,14 @@ struct ins_ops { | |||
59 | void (*free)(struct ins_operands *ops); | 59 | void (*free)(struct ins_operands *ops); |
60 | int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms); | 60 | int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms); |
61 | int (*scnprintf)(struct ins *ins, char *bf, size_t size, | 61 | int (*scnprintf)(struct ins *ins, char *bf, size_t size, |
62 | struct ins_operands *ops); | 62 | struct ins_operands *ops, int max_ins_name); |
63 | }; | 63 | }; |
64 | 64 | ||
65 | bool ins__is_jump(const struct ins *ins); | 65 | bool ins__is_jump(const struct ins *ins); |
66 | bool ins__is_call(const struct ins *ins); | 66 | bool ins__is_call(const struct ins *ins); |
67 | bool ins__is_ret(const struct ins *ins); | 67 | bool ins__is_ret(const struct ins *ins); |
68 | bool ins__is_lock(const struct ins *ins); | 68 | bool ins__is_lock(const struct ins *ins); |
69 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); | 69 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name); |
70 | bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); | 70 | bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); |
71 | 71 | ||
72 | #define ANNOTATION__IPC_WIDTH 6 | 72 | #define ANNOTATION__IPC_WIDTH 6 |
@@ -219,7 +219,7 @@ int __annotation__scnprintf_samples_period(struct annotation *notes, | |||
219 | struct perf_evsel *evsel, | 219 | struct perf_evsel *evsel, |
220 | bool show_freq); | 220 | bool show_freq); |
221 | 221 | ||
222 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); | 222 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name); |
223 | size_t disasm__fprintf(struct list_head *head, FILE *fp); | 223 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
224 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); | 224 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); |
225 | 225 | ||
@@ -289,6 +289,7 @@ struct annotation { | |||
289 | u8 target; | 289 | u8 target; |
290 | u8 min_addr; | 290 | u8 min_addr; |
291 | u8 max_addr; | 291 | u8 max_addr; |
292 | u8 max_ins_name; | ||
292 | } widths; | 293 | } widths; |
293 | bool have_cycles; | 294 | bool have_cycles; |
294 | struct annotated_source *src; | 295 | struct annotated_source *src; |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 267e54df511b..fb76b6b232d4 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -1918,7 +1918,8 @@ static struct dso *load_dso(const char *name) | |||
1918 | if (!map) | 1918 | if (!map) |
1919 | return NULL; | 1919 | return NULL; |
1920 | 1920 | ||
1921 | map__load(map); | 1921 | if (map__load(map) < 0) |
1922 | pr_err("File '%s' not found or has no symbols.\n", name); | ||
1922 | 1923 | ||
1923 | dso = dso__get(map->dso); | 1924 | dso = dso__get(map->dso); |
1924 | 1925 | ||
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index 39c0004f2886..fc361c3f8570 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp | |||
@@ -156,7 +156,7 @@ getBPFObjectFromModule(llvm::Module *Module) | |||
156 | #endif | 156 | #endif |
157 | if (NotAdded) { | 157 | if (NotAdded) { |
158 | llvm::errs() << "TargetMachine can't emit a file of this type\n"; | 158 | llvm::errs() << "TargetMachine can't emit a file of this type\n"; |
159 | return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);; | 159 | return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr); |
160 | } | 160 | } |
161 | PM.run(*Module); | 161 | PM.run(*Module); |
162 | 162 | ||
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 7bd5ddeb7a41..e098e189f93e 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c | |||
@@ -237,7 +237,7 @@ static int open_file(struct perf_data *data) | |||
237 | open_file_read(data) : open_file_write(data); | 237 | open_file_read(data) : open_file_write(data); |
238 | 238 | ||
239 | if (fd < 0) { | 239 | if (fd < 0) { |
240 | free(data->file.path); | 240 | zfree(&data->file.path); |
241 | return -1; | 241 | return -1; |
242 | } | 242 | } |
243 | 243 | ||
@@ -270,7 +270,7 @@ int perf_data__open(struct perf_data *data) | |||
270 | 270 | ||
271 | void perf_data__close(struct perf_data *data) | 271 | void perf_data__close(struct perf_data *data) |
272 | { | 272 | { |
273 | free(data->file.path); | 273 | zfree(&data->file.path); |
274 | close(data->file.fd); | 274 | close(data->file.fd); |
275 | } | 275 | } |
276 | 276 | ||
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index de9b4769d06c..d7315a00c731 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c | |||
@@ -510,18 +510,23 @@ int db_export__call_path(struct db_export *dbe, struct call_path *cp) | |||
510 | return 0; | 510 | return 0; |
511 | } | 511 | } |
512 | 512 | ||
513 | int db_export__call_return(struct db_export *dbe, struct call_return *cr) | 513 | int db_export__call_return(struct db_export *dbe, struct call_return *cr, |
514 | u64 *parent_db_id) | ||
514 | { | 515 | { |
515 | int err; | 516 | int err; |
516 | 517 | ||
517 | if (cr->db_id) | ||
518 | return 0; | ||
519 | |||
520 | err = db_export__call_path(dbe, cr->cp); | 518 | err = db_export__call_path(dbe, cr->cp); |
521 | if (err) | 519 | if (err) |
522 | return err; | 520 | return err; |
523 | 521 | ||
524 | cr->db_id = ++dbe->call_return_last_db_id; | 522 | if (!cr->db_id) |
523 | cr->db_id = ++dbe->call_return_last_db_id; | ||
524 | |||
525 | if (parent_db_id) { | ||
526 | if (!*parent_db_id) | ||
527 | *parent_db_id = ++dbe->call_return_last_db_id; | ||
528 | cr->parent_db_id = *parent_db_id; | ||
529 | } | ||
525 | 530 | ||
526 | if (dbe->export_call_return) | 531 | if (dbe->export_call_return) |
527 | return dbe->export_call_return(dbe, cr); | 532 | return dbe->export_call_return(dbe, cr); |
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h index 67bc6b8ad2d6..4e2424c89df9 100644 --- a/tools/perf/util/db-export.h +++ b/tools/perf/util/db-export.h | |||
@@ -104,6 +104,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, | |||
104 | int db_export__branch_types(struct db_export *dbe); | 104 | int db_export__branch_types(struct db_export *dbe); |
105 | 105 | ||
106 | int db_export__call_path(struct db_export *dbe, struct call_path *cp); | 106 | int db_export__call_path(struct db_export *dbe, struct call_path *cp); |
107 | int db_export__call_return(struct db_export *dbe, struct call_return *cr); | 107 | int db_export__call_return(struct db_export *dbe, struct call_return *cr, |
108 | u64 *parent_db_id); | ||
108 | 109 | ||
109 | #endif | 110 | #endif |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 08cedb643ea6..ed20f4379956 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -230,18 +230,33 @@ void perf_evlist__set_leader(struct perf_evlist *evlist) | |||
230 | } | 230 | } |
231 | } | 231 | } |
232 | 232 | ||
233 | void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr) | 233 | void perf_event_attr__set_max_precise_ip(struct perf_event_attr *pattr) |
234 | { | 234 | { |
235 | attr->precise_ip = 3; | 235 | struct perf_event_attr attr = { |
236 | .type = PERF_TYPE_HARDWARE, | ||
237 | .config = PERF_COUNT_HW_CPU_CYCLES, | ||
238 | .exclude_kernel = 1, | ||
239 | .precise_ip = 3, | ||
240 | }; | ||
236 | 241 | ||
237 | while (attr->precise_ip != 0) { | 242 | event_attr_init(&attr); |
238 | int fd = sys_perf_event_open(attr, 0, -1, -1, 0); | 243 | |
244 | /* | ||
245 | * Unnamed union member, not supported as struct member named | ||
246 | * initializer in older compilers such as gcc 4.4.7 | ||
247 | */ | ||
248 | attr.sample_period = 1; | ||
249 | |||
250 | while (attr.precise_ip != 0) { | ||
251 | int fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | ||
239 | if (fd != -1) { | 252 | if (fd != -1) { |
240 | close(fd); | 253 | close(fd); |
241 | break; | 254 | break; |
242 | } | 255 | } |
243 | --attr->precise_ip; | 256 | --attr.precise_ip; |
244 | } | 257 | } |
258 | |||
259 | pattr->precise_ip = attr.precise_ip; | ||
245 | } | 260 | } |
246 | 261 | ||
247 | int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise) | 262 | int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise) |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index dfe2958e6287..3bbf73e979c0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -294,20 +294,12 @@ struct perf_evsel *perf_evsel__new_cycles(bool precise) | |||
294 | 294 | ||
295 | if (!precise) | 295 | if (!precise) |
296 | goto new_event; | 296 | goto new_event; |
297 | /* | ||
298 | * Unnamed union member, not supported as struct member named | ||
299 | * initializer in older compilers such as gcc 4.4.7 | ||
300 | * | ||
301 | * Just for probing the precise_ip: | ||
302 | */ | ||
303 | attr.sample_period = 1; | ||
304 | 297 | ||
305 | perf_event_attr__set_max_precise_ip(&attr); | 298 | perf_event_attr__set_max_precise_ip(&attr); |
306 | /* | 299 | /* |
307 | * Now let the usual logic to set up the perf_event_attr defaults | 300 | * Now let the usual logic to set up the perf_event_attr defaults |
308 | * to kick in when we return and before perf_evsel__open() is called. | 301 | * to kick in when we return and before perf_evsel__open() is called. |
309 | */ | 302 | */ |
310 | attr.sample_period = 0; | ||
311 | new_event: | 303 | new_event: |
312 | evsel = perf_evsel__new(&attr); | 304 | evsel = perf_evsel__new(&attr); |
313 | if (evsel == NULL) | 305 | if (evsel == NULL) |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 669f961316f0..f9eb95bf3938 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -396,11 +396,8 @@ static int hist_entry__init(struct hist_entry *he, | |||
396 | * adding new entries. So we need to save a copy. | 396 | * adding new entries. So we need to save a copy. |
397 | */ | 397 | */ |
398 | he->branch_info = malloc(sizeof(*he->branch_info)); | 398 | he->branch_info = malloc(sizeof(*he->branch_info)); |
399 | if (he->branch_info == NULL) { | 399 | if (he->branch_info == NULL) |
400 | map__zput(he->ms.map); | 400 | goto err; |
401 | free(he->stat_acc); | ||
402 | return -ENOMEM; | ||
403 | } | ||
404 | 401 | ||
405 | memcpy(he->branch_info, template->branch_info, | 402 | memcpy(he->branch_info, template->branch_info, |
406 | sizeof(*he->branch_info)); | 403 | sizeof(*he->branch_info)); |
@@ -419,22 +416,16 @@ static int hist_entry__init(struct hist_entry *he, | |||
419 | 416 | ||
420 | if (he->raw_data) { | 417 | if (he->raw_data) { |
421 | he->raw_data = memdup(he->raw_data, he->raw_size); | 418 | he->raw_data = memdup(he->raw_data, he->raw_size); |
419 | if (he->raw_data == NULL) | ||
420 | goto err_infos; | ||
421 | } | ||
422 | 422 | ||
423 | if (he->raw_data == NULL) { | 423 | if (he->srcline) { |
424 | map__put(he->ms.map); | 424 | he->srcline = strdup(he->srcline); |
425 | if (he->branch_info) { | 425 | if (he->srcline == NULL) |
426 | map__put(he->branch_info->from.map); | 426 | goto err_rawdata; |
427 | map__put(he->branch_info->to.map); | ||
428 | free(he->branch_info); | ||
429 | } | ||
430 | if (he->mem_info) { | ||
431 | map__put(he->mem_info->iaddr.map); | ||
432 | map__put(he->mem_info->daddr.map); | ||
433 | } | ||
434 | free(he->stat_acc); | ||
435 | return -ENOMEM; | ||
436 | } | ||
437 | } | 427 | } |
428 | |||
438 | INIT_LIST_HEAD(&he->pairs.node); | 429 | INIT_LIST_HEAD(&he->pairs.node); |
439 | thread__get(he->thread); | 430 | thread__get(he->thread); |
440 | he->hroot_in = RB_ROOT_CACHED; | 431 | he->hroot_in = RB_ROOT_CACHED; |
@@ -444,6 +435,24 @@ static int hist_entry__init(struct hist_entry *he, | |||
444 | he->leaf = true; | 435 | he->leaf = true; |
445 | 436 | ||
446 | return 0; | 437 | return 0; |
438 | |||
439 | err_rawdata: | ||
440 | free(he->raw_data); | ||
441 | |||
442 | err_infos: | ||
443 | if (he->branch_info) { | ||
444 | map__put(he->branch_info->from.map); | ||
445 | map__put(he->branch_info->to.map); | ||
446 | free(he->branch_info); | ||
447 | } | ||
448 | if (he->mem_info) { | ||
449 | map__put(he->mem_info->iaddr.map); | ||
450 | map__put(he->mem_info->daddr.map); | ||
451 | } | ||
452 | err: | ||
453 | map__zput(he->ms.map); | ||
454 | free(he->stat_acc); | ||
455 | return -ENOMEM; | ||
447 | } | 456 | } |
448 | 457 | ||
449 | static void *hist_entry__zalloc(size_t size) | 458 | static void *hist_entry__zalloc(size_t size) |
@@ -606,7 +615,7 @@ __hists__add_entry(struct hists *hists, | |||
606 | .map = al->map, | 615 | .map = al->map, |
607 | .sym = al->sym, | 616 | .sym = al->sym, |
608 | }, | 617 | }, |
609 | .srcline = al->srcline ? strdup(al->srcline) : NULL, | 618 | .srcline = (char *) al->srcline, |
610 | .socket = al->socket, | 619 | .socket = al->socket, |
611 | .cpu = al->cpu, | 620 | .cpu = al->cpu, |
612 | .cpumode = al->cpumode, | 621 | .cpumode = al->cpumode, |
@@ -963,7 +972,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, | |||
963 | .map = al->map, | 972 | .map = al->map, |
964 | .sym = al->sym, | 973 | .sym = al->sym, |
965 | }, | 974 | }, |
966 | .srcline = al->srcline ? strdup(al->srcline) : NULL, | 975 | .srcline = (char *) al->srcline, |
967 | .parent = iter->parent, | 976 | .parent = iter->parent, |
968 | .raw_data = sample->raw_data, | 977 | .raw_data = sample->raw_data, |
969 | .raw_size = sample->raw_size, | 978 | .raw_size = sample->raw_size, |
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 0c0180c67574..47025bc727e1 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c | |||
@@ -328,35 +328,19 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip) | |||
328 | { | 328 | { |
329 | struct machine *machine = btsq->bts->machine; | 329 | struct machine *machine = btsq->bts->machine; |
330 | struct thread *thread; | 330 | struct thread *thread; |
331 | struct addr_location al; | ||
332 | unsigned char buf[INTEL_PT_INSN_BUF_SZ]; | 331 | unsigned char buf[INTEL_PT_INSN_BUF_SZ]; |
333 | ssize_t len; | 332 | ssize_t len; |
334 | int x86_64; | 333 | bool x86_64; |
335 | uint8_t cpumode; | ||
336 | int err = -1; | 334 | int err = -1; |
337 | 335 | ||
338 | if (machine__kernel_ip(machine, ip)) | ||
339 | cpumode = PERF_RECORD_MISC_KERNEL; | ||
340 | else | ||
341 | cpumode = PERF_RECORD_MISC_USER; | ||
342 | |||
343 | thread = machine__find_thread(machine, -1, btsq->tid); | 336 | thread = machine__find_thread(machine, -1, btsq->tid); |
344 | if (!thread) | 337 | if (!thread) |
345 | return -1; | 338 | return -1; |
346 | 339 | ||
347 | if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso) | 340 | len = thread__memcpy(thread, machine, buf, ip, INTEL_PT_INSN_BUF_SZ, &x86_64); |
348 | goto out_put; | ||
349 | |||
350 | len = dso__data_read_addr(al.map->dso, al.map, machine, ip, buf, | ||
351 | INTEL_PT_INSN_BUF_SZ); | ||
352 | if (len <= 0) | 341 | if (len <= 0) |
353 | goto out_put; | 342 | goto out_put; |
354 | 343 | ||
355 | /* Load maps to ensure dso->is_64_bit has been updated */ | ||
356 | map__load(al.map); | ||
357 | |||
358 | x86_64 = al.map->dso->is_64_bit; | ||
359 | |||
360 | if (intel_pt_get_insn(buf, len, x86_64, &btsq->intel_pt_insn)) | 344 | if (intel_pt_get_insn(buf, len, x86_64, &btsq->intel_pt_insn)) |
361 | goto out_put; | 345 | goto out_put; |
362 | 346 | ||
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 3b497bab4324..6d288237887b 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c | |||
@@ -2531,6 +2531,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event, | |||
2531 | } | 2531 | } |
2532 | 2532 | ||
2533 | pt->timeless_decoding = intel_pt_timeless_decoding(pt); | 2533 | pt->timeless_decoding = intel_pt_timeless_decoding(pt); |
2534 | if (pt->timeless_decoding && !pt->tc.time_mult) | ||
2535 | pt->tc.time_mult = 1; | ||
2534 | pt->have_tsc = intel_pt_have_tsc(pt); | 2536 | pt->have_tsc = intel_pt_have_tsc(pt); |
2535 | pt->sampling_mode = false; | 2537 | pt->sampling_mode = false; |
2536 | pt->est_tsc = !pt->timeless_decoding; | 2538 | pt->est_tsc = !pt->timeless_decoding; |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 51d437f55d18..6199a3174ab9 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -752,6 +752,19 @@ perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) | |||
752 | return NULL; | 752 | return NULL; |
753 | } | 753 | } |
754 | 754 | ||
755 | static int pmu_max_precise(const char *name) | ||
756 | { | ||
757 | char path[PATH_MAX]; | ||
758 | int max_precise = -1; | ||
759 | |||
760 | scnprintf(path, PATH_MAX, | ||
761 | "bus/event_source/devices/%s/caps/max_precise", | ||
762 | name); | ||
763 | |||
764 | sysfs__read_int(path, &max_precise); | ||
765 | return max_precise; | ||
766 | } | ||
767 | |||
755 | static struct perf_pmu *pmu_lookup(const char *name) | 768 | static struct perf_pmu *pmu_lookup(const char *name) |
756 | { | 769 | { |
757 | struct perf_pmu *pmu; | 770 | struct perf_pmu *pmu; |
@@ -784,6 +797,7 @@ static struct perf_pmu *pmu_lookup(const char *name) | |||
784 | pmu->name = strdup(name); | 797 | pmu->name = strdup(name); |
785 | pmu->type = type; | 798 | pmu->type = type; |
786 | pmu->is_uncore = pmu_is_uncore(name); | 799 | pmu->is_uncore = pmu_is_uncore(name); |
800 | pmu->max_precise = pmu_max_precise(name); | ||
787 | pmu_add_cpu_aliases(&aliases, pmu); | 801 | pmu_add_cpu_aliases(&aliases, pmu); |
788 | 802 | ||
789 | INIT_LIST_HEAD(&pmu->format); | 803 | INIT_LIST_HEAD(&pmu->format); |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 47253c3daf55..bd9ec2704a57 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -26,6 +26,7 @@ struct perf_pmu { | |||
26 | __u32 type; | 26 | __u32 type; |
27 | bool selectable; | 27 | bool selectable; |
28 | bool is_uncore; | 28 | bool is_uncore; |
29 | int max_precise; | ||
29 | struct perf_event_attr *default_config; | 30 | struct perf_event_attr *default_config; |
30 | struct cpu_map *cpus; | 31 | struct cpu_map *cpus; |
31 | struct list_head format; /* HEAD struct perf_pmu_format -> list */ | 32 | struct list_head format; /* HEAD struct perf_pmu_format -> list */ |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 0030f9b9bf7e..a1b8d9649ca7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -472,9 +472,12 @@ static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi, | |||
472 | strcpy(reason, "(unknown)"); | 472 | strcpy(reason, "(unknown)"); |
473 | } else | 473 | } else |
474 | dso__strerror_load(dso, reason, STRERR_BUFSIZE); | 474 | dso__strerror_load(dso, reason, STRERR_BUFSIZE); |
475 | if (!silent) | 475 | if (!silent) { |
476 | pr_err("Failed to find the path for %s: %s\n", | 476 | if (module) |
477 | module ?: "kernel", reason); | 477 | pr_err("Module %s is not loaded, please specify its full path name.\n", module); |
478 | else | ||
479 | pr_err("Failed to find the path for the kernel: %s\n", reason); | ||
480 | } | ||
478 | return NULL; | 481 | return NULL; |
479 | } | 482 | } |
480 | path = dso->long_name; | 483 | path = dso->long_name; |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 0e17db41b49b..09604c6508f0 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -1173,7 +1173,7 @@ static int python_export_call_return(struct db_export *dbe, | |||
1173 | u64 comm_db_id = cr->comm ? cr->comm->db_id : 0; | 1173 | u64 comm_db_id = cr->comm ? cr->comm->db_id : 0; |
1174 | PyObject *t; | 1174 | PyObject *t; |
1175 | 1175 | ||
1176 | t = tuple_new(11); | 1176 | t = tuple_new(12); |
1177 | 1177 | ||
1178 | tuple_set_u64(t, 0, cr->db_id); | 1178 | tuple_set_u64(t, 0, cr->db_id); |
1179 | tuple_set_u64(t, 1, cr->thread->db_id); | 1179 | tuple_set_u64(t, 1, cr->thread->db_id); |
@@ -1186,6 +1186,7 @@ static int python_export_call_return(struct db_export *dbe, | |||
1186 | tuple_set_u64(t, 8, cr->return_ref); | 1186 | tuple_set_u64(t, 8, cr->return_ref); |
1187 | tuple_set_u64(t, 9, cr->cp->parent->db_id); | 1187 | tuple_set_u64(t, 9, cr->cp->parent->db_id); |
1188 | tuple_set_s32(t, 10, cr->flags); | 1188 | tuple_set_s32(t, 10, cr->flags); |
1189 | tuple_set_u64(t, 11, cr->parent_db_id); | ||
1189 | 1190 | ||
1190 | call_object(tables->call_return_handler, t, "call_return_table"); | 1191 | call_object(tables->call_return_handler, t, "call_return_table"); |
1191 | 1192 | ||
@@ -1194,11 +1195,12 @@ static int python_export_call_return(struct db_export *dbe, | |||
1194 | return 0; | 1195 | return 0; |
1195 | } | 1196 | } |
1196 | 1197 | ||
1197 | static int python_process_call_return(struct call_return *cr, void *data) | 1198 | static int python_process_call_return(struct call_return *cr, u64 *parent_db_id, |
1199 | void *data) | ||
1198 | { | 1200 | { |
1199 | struct db_export *dbe = data; | 1201 | struct db_export *dbe = data; |
1200 | 1202 | ||
1201 | return db_export__call_return(dbe, cr); | 1203 | return db_export__call_return(dbe, cr, parent_db_id); |
1202 | } | 1204 | } |
1203 | 1205 | ||
1204 | static void python_process_general_event(struct perf_sample *sample, | 1206 | static void python_process_general_event(struct perf_sample *sample, |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c764bbc91009..db643f3c2b95 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -140,7 +140,7 @@ struct perf_session *perf_session__new(struct perf_data *data, | |||
140 | 140 | ||
141 | if (perf_data__is_read(data)) { | 141 | if (perf_data__is_read(data)) { |
142 | if (perf_session__open(session) < 0) | 142 | if (perf_session__open(session) < 0) |
143 | goto out_close; | 143 | goto out_delete; |
144 | 144 | ||
145 | /* | 145 | /* |
146 | * set session attributes that are present in perf.data | 146 | * set session attributes that are present in perf.data |
@@ -181,8 +181,6 @@ struct perf_session *perf_session__new(struct perf_data *data, | |||
181 | 181 | ||
182 | return session; | 182 | return session; |
183 | 183 | ||
184 | out_close: | ||
185 | perf_data__close(data); | ||
186 | out_delete: | 184 | out_delete: |
187 | perf_session__delete(session); | 185 | perf_session__delete(session); |
188 | out: | 186 | out: |
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index a8b45168513c..41942c2aaa18 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c | |||
@@ -49,6 +49,7 @@ enum retpoline_state_t { | |||
49 | * @timestamp: timestamp (if known) | 49 | * @timestamp: timestamp (if known) |
50 | * @ref: external reference (e.g. db_id of sample) | 50 | * @ref: external reference (e.g. db_id of sample) |
51 | * @branch_count: the branch count when the entry was created | 51 | * @branch_count: the branch count when the entry was created |
52 | * @db_id: id used for db-export | ||
52 | * @cp: call path | 53 | * @cp: call path |
53 | * @no_call: a 'call' was not seen | 54 | * @no_call: a 'call' was not seen |
54 | * @trace_end: a 'call' but trace ended | 55 | * @trace_end: a 'call' but trace ended |
@@ -59,6 +60,7 @@ struct thread_stack_entry { | |||
59 | u64 timestamp; | 60 | u64 timestamp; |
60 | u64 ref; | 61 | u64 ref; |
61 | u64 branch_count; | 62 | u64 branch_count; |
63 | u64 db_id; | ||
62 | struct call_path *cp; | 64 | struct call_path *cp; |
63 | bool no_call; | 65 | bool no_call; |
64 | bool trace_end; | 66 | bool trace_end; |
@@ -280,12 +282,14 @@ static int thread_stack__call_return(struct thread *thread, | |||
280 | .comm = ts->comm, | 282 | .comm = ts->comm, |
281 | .db_id = 0, | 283 | .db_id = 0, |
282 | }; | 284 | }; |
285 | u64 *parent_db_id; | ||
283 | 286 | ||
284 | tse = &ts->stack[idx]; | 287 | tse = &ts->stack[idx]; |
285 | cr.cp = tse->cp; | 288 | cr.cp = tse->cp; |
286 | cr.call_time = tse->timestamp; | 289 | cr.call_time = tse->timestamp; |
287 | cr.return_time = timestamp; | 290 | cr.return_time = timestamp; |
288 | cr.branch_count = ts->branch_count - tse->branch_count; | 291 | cr.branch_count = ts->branch_count - tse->branch_count; |
292 | cr.db_id = tse->db_id; | ||
289 | cr.call_ref = tse->ref; | 293 | cr.call_ref = tse->ref; |
290 | cr.return_ref = ref; | 294 | cr.return_ref = ref; |
291 | if (tse->no_call) | 295 | if (tse->no_call) |
@@ -295,7 +299,14 @@ static int thread_stack__call_return(struct thread *thread, | |||
295 | if (tse->non_call) | 299 | if (tse->non_call) |
296 | cr.flags |= CALL_RETURN_NON_CALL; | 300 | cr.flags |= CALL_RETURN_NON_CALL; |
297 | 301 | ||
298 | return crp->process(&cr, crp->data); | 302 | /* |
303 | * The parent db_id must be assigned before exporting the child. Note | ||
304 | * it is not possible to export the parent first because its information | ||
305 | * is not yet complete because its 'return' has not yet been processed. | ||
306 | */ | ||
307 | parent_db_id = idx ? &(tse - 1)->db_id : NULL; | ||
308 | |||
309 | return crp->process(&cr, parent_db_id, crp->data); | ||
299 | } | 310 | } |
300 | 311 | ||
301 | static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts) | 312 | static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts) |
@@ -484,7 +495,7 @@ void thread_stack__sample(struct thread *thread, int cpu, | |||
484 | } | 495 | } |
485 | 496 | ||
486 | struct call_return_processor * | 497 | struct call_return_processor * |
487 | call_return_processor__new(int (*process)(struct call_return *cr, void *data), | 498 | call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data), |
488 | void *data) | 499 | void *data) |
489 | { | 500 | { |
490 | struct call_return_processor *crp; | 501 | struct call_return_processor *crp; |
@@ -537,6 +548,7 @@ static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr, | |||
537 | tse->no_call = no_call; | 548 | tse->no_call = no_call; |
538 | tse->trace_end = trace_end; | 549 | tse->trace_end = trace_end; |
539 | tse->non_call = false; | 550 | tse->non_call = false; |
551 | tse->db_id = 0; | ||
540 | 552 | ||
541 | return 0; | 553 | return 0; |
542 | } | 554 | } |
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h index b7c04e19ad41..9c45f947f5a9 100644 --- a/tools/perf/util/thread-stack.h +++ b/tools/perf/util/thread-stack.h | |||
@@ -55,6 +55,7 @@ enum { | |||
55 | * @call_ref: external reference to 'call' sample (e.g. db_id) | 55 | * @call_ref: external reference to 'call' sample (e.g. db_id) |
56 | * @return_ref: external reference to 'return' sample (e.g. db_id) | 56 | * @return_ref: external reference to 'return' sample (e.g. db_id) |
57 | * @db_id: id used for db-export | 57 | * @db_id: id used for db-export |
58 | * @parent_db_id: id of parent call used for db-export | ||
58 | * @flags: Call/Return flags | 59 | * @flags: Call/Return flags |
59 | */ | 60 | */ |
60 | struct call_return { | 61 | struct call_return { |
@@ -67,6 +68,7 @@ struct call_return { | |||
67 | u64 call_ref; | 68 | u64 call_ref; |
68 | u64 return_ref; | 69 | u64 return_ref; |
69 | u64 db_id; | 70 | u64 db_id; |
71 | u64 parent_db_id; | ||
70 | u32 flags; | 72 | u32 flags; |
71 | }; | 73 | }; |
72 | 74 | ||
@@ -79,7 +81,7 @@ struct call_return { | |||
79 | */ | 81 | */ |
80 | struct call_return_processor { | 82 | struct call_return_processor { |
81 | struct call_path_root *cpr; | 83 | struct call_path_root *cpr; |
82 | int (*process)(struct call_return *cr, void *data); | 84 | int (*process)(struct call_return *cr, u64 *parent_db_id, void *data); |
83 | void *data; | 85 | void *data; |
84 | }; | 86 | }; |
85 | 87 | ||
@@ -93,7 +95,7 @@ void thread_stack__free(struct thread *thread); | |||
93 | size_t thread_stack__depth(struct thread *thread, int cpu); | 95 | size_t thread_stack__depth(struct thread *thread, int cpu); |
94 | 96 | ||
95 | struct call_return_processor * | 97 | struct call_return_processor * |
96 | call_return_processor__new(int (*process)(struct call_return *cr, void *data), | 98 | call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data), |
97 | void *data); | 99 | void *data); |
98 | void call_return_processor__free(struct call_return_processor *crp); | 100 | void call_return_processor__free(struct call_return_processor *crp); |
99 | int thread_stack__process(struct thread *thread, struct comm *comm, | 101 | int thread_stack__process(struct thread *thread, struct comm *comm, |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 4c179fef442d..50678d318185 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "debug.h" | 12 | #include "debug.h" |
13 | #include "namespaces.h" | 13 | #include "namespaces.h" |
14 | #include "comm.h" | 14 | #include "comm.h" |
15 | #include "map.h" | ||
15 | #include "symbol.h" | 16 | #include "symbol.h" |
16 | #include "unwind.h" | 17 | #include "unwind.h" |
17 | 18 | ||
@@ -393,3 +394,25 @@ struct thread *thread__main_thread(struct machine *machine, struct thread *threa | |||
393 | 394 | ||
394 | return machine__find_thread(machine, thread->pid_, thread->pid_); | 395 | return machine__find_thread(machine, thread->pid_, thread->pid_); |
395 | } | 396 | } |
397 | |||
398 | int thread__memcpy(struct thread *thread, struct machine *machine, | ||
399 | void *buf, u64 ip, int len, bool *is64bit) | ||
400 | { | ||
401 | u8 cpumode = PERF_RECORD_MISC_USER; | ||
402 | struct addr_location al; | ||
403 | long offset; | ||
404 | |||
405 | if (machine__kernel_ip(machine, ip)) | ||
406 | cpumode = PERF_RECORD_MISC_KERNEL; | ||
407 | |||
408 | if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso || | ||
409 | al.map->dso->data.status == DSO_DATA_STATUS_ERROR || | ||
410 | map__load(al.map) < 0) | ||
411 | return -1; | ||
412 | |||
413 | offset = al.map->map_ip(al.map, ip); | ||
414 | if (is64bit) | ||
415 | *is64bit = al.map->dso->is_64_bit; | ||
416 | |||
417 | return dso__data_read_offset(al.map->dso, machine, offset, buf, len); | ||
418 | } | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 8276ffeec556..cf8375c017a0 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -113,6 +113,9 @@ struct symbol *thread__find_symbol_fb(struct thread *thread, u8 cpumode, | |||
113 | void thread__find_cpumode_addr_location(struct thread *thread, u64 addr, | 113 | void thread__find_cpumode_addr_location(struct thread *thread, u64 addr, |
114 | struct addr_location *al); | 114 | struct addr_location *al); |
115 | 115 | ||
116 | int thread__memcpy(struct thread *thread, struct machine *machine, | ||
117 | void *buf, u64 ip, int len, bool *is64bit); | ||
118 | |||
116 | static inline void *thread__priv(struct thread *thread) | 119 | static inline void *thread__priv(struct thread *thread) |
117 | { | 120 | { |
118 | return thread->priv; | 121 | return thread->priv; |
diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c index 6193b46050a5..0f53baec660e 100644 --- a/tools/perf/util/time-utils.c +++ b/tools/perf/util/time-utils.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include "perf.h" | 11 | #include "perf.h" |
12 | #include "debug.h" | 12 | #include "debug.h" |
13 | #include "time-utils.h" | 13 | #include "time-utils.h" |
14 | #include "session.h" | ||
15 | #include "evlist.h" | ||
14 | 16 | ||
15 | int parse_nsec_time(const char *str, u64 *ptime) | 17 | int parse_nsec_time(const char *str, u64 *ptime) |
16 | { | 18 | { |
@@ -374,7 +376,7 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, | |||
374 | struct perf_time_interval *ptime; | 376 | struct perf_time_interval *ptime; |
375 | int i; | 377 | int i; |
376 | 378 | ||
377 | if ((timestamp == 0) || (num == 0)) | 379 | if ((!ptime_buf) || (timestamp == 0) || (num == 0)) |
378 | return false; | 380 | return false; |
379 | 381 | ||
380 | if (num == 1) | 382 | if (num == 1) |
@@ -396,6 +398,53 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, | |||
396 | return (i == num) ? true : false; | 398 | return (i == num) ? true : false; |
397 | } | 399 | } |
398 | 400 | ||
401 | int perf_time__parse_for_ranges(const char *time_str, | ||
402 | struct perf_session *session, | ||
403 | struct perf_time_interval **ranges, | ||
404 | int *range_size, int *range_num) | ||
405 | { | ||
406 | struct perf_time_interval *ptime_range; | ||
407 | int size, num, ret; | ||
408 | |||
409 | ptime_range = perf_time__range_alloc(time_str, &size); | ||
410 | if (!ptime_range) | ||
411 | return -ENOMEM; | ||
412 | |||
413 | if (perf_time__parse_str(ptime_range, time_str) != 0) { | ||
414 | if (session->evlist->first_sample_time == 0 && | ||
415 | session->evlist->last_sample_time == 0) { | ||
416 | pr_err("HINT: no first/last sample time found in perf data.\n" | ||
417 | "Please use latest perf binary to execute 'perf record'\n" | ||
418 | "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n"); | ||
419 | ret = -EINVAL; | ||
420 | goto error; | ||
421 | } | ||
422 | |||
423 | num = perf_time__percent_parse_str( | ||
424 | ptime_range, size, | ||
425 | time_str, | ||
426 | session->evlist->first_sample_time, | ||
427 | session->evlist->last_sample_time); | ||
428 | |||
429 | if (num < 0) { | ||
430 | pr_err("Invalid time string\n"); | ||
431 | ret = -EINVAL; | ||
432 | goto error; | ||
433 | } | ||
434 | } else { | ||
435 | num = 1; | ||
436 | } | ||
437 | |||
438 | *range_size = size; | ||
439 | *range_num = num; | ||
440 | *ranges = ptime_range; | ||
441 | return 0; | ||
442 | |||
443 | error: | ||
444 | free(ptime_range); | ||
445 | return ret; | ||
446 | } | ||
447 | |||
399 | int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz) | 448 | int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz) |
400 | { | 449 | { |
401 | u64 sec = timestamp / NSEC_PER_SEC; | 450 | u64 sec = timestamp / NSEC_PER_SEC; |
diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h index 70b177d2b98c..b923de44e36f 100644 --- a/tools/perf/util/time-utils.h +++ b/tools/perf/util/time-utils.h | |||
@@ -23,6 +23,12 @@ bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp); | |||
23 | bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, | 23 | bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, |
24 | int num, u64 timestamp); | 24 | int num, u64 timestamp); |
25 | 25 | ||
26 | struct perf_session; | ||
27 | |||
28 | int perf_time__parse_for_ranges(const char *str, struct perf_session *session, | ||
29 | struct perf_time_interval **ranges, | ||
30 | int *range_size, int *range_num); | ||
31 | |||
26 | int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz); | 32 | int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz); |
27 | 33 | ||
28 | int fetch_current_timestamp(char *buf, size_t sz); | 34 | int fetch_current_timestamp(char *buf, size_t sz); |