diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-12-08 01:44:38 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-12-08 01:45:23 -0500 |
commit | e460bfdcf3b243abebc4682d4312670a4a7dc7a4 (patch) | |
tree | 3334e4934bf37f03325e064fcd940997648145ff | |
parent | 4e6e311e596eadba30d4f56f64eae7d45611a01c (diff) | |
parent | 1d9e446b91e182055d874fbb30150aad479a4981 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
- Callchain improvements from Andi Kleen including:
* Enable printing the srcline in the history
* Make get_srcline fall back to sym+offset
- Allow to force redirect pr_debug to stderr. (Andi Kleen)
- TUI hist_entry browser fixes, including showing missing overhead
value for first level callchain. Detected comparing the output of
--stdio/--gui (that matched) with --tui, that had this problem. (Namhyung Kim)
- Fix segfault due to invalid kernel dso access (Namhyung Kim)
Infrastructure changes:
- Move bfd_demangle stubbing to its only user (Arnaldo Carvalho de Melo)
- 'perf stat' refactorings, moving stuff from it to evsel.c to use in
per-pkg/snapshot format changes (Jiri Olsa)
- Add per-pkg format file parsing (Matt Fleming)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 25 | ||||
-rw-r--r-- | tools/perf/util/annotate.c | 2 | ||||
-rw-r--r-- | tools/perf/util/callchain.c | 12 | ||||
-rw-r--r-- | tools/perf/util/callchain.h | 1 | ||||
-rw-r--r-- | tools/perf/util/debug.c | 4 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 72 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 15 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 4 | ||||
-rw-r--r-- | tools/perf/util/map.c | 2 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 2 | ||||
-rw-r--r-- | tools/perf/util/pmu.c | 74 | ||||
-rw-r--r-- | tools/perf/util/pmu.h | 4 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 6 | ||||
-rw-r--r-- | tools/perf/util/srcline.c | 15 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 21 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 21 | ||||
-rw-r--r-- | tools/perf/util/util.h | 4 |
17 files changed, 205 insertions, 79 deletions
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 12c17c5a3d68..502daff76ceb 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -227,10 +227,14 @@ static void callchain_node__init_have_children_rb_tree(struct callchain_node *no | |||
227 | } | 227 | } |
228 | } | 228 | } |
229 | 229 | ||
230 | static void callchain_node__init_have_children(struct callchain_node *node) | 230 | static void callchain_node__init_have_children(struct callchain_node *node, |
231 | bool has_sibling) | ||
231 | { | 232 | { |
232 | struct callchain_list *chain; | 233 | struct callchain_list *chain; |
233 | 234 | ||
235 | chain = list_entry(node->val.next, struct callchain_list, list); | ||
236 | chain->ms.has_children = has_sibling; | ||
237 | |||
234 | if (!list_empty(&node->val)) { | 238 | if (!list_empty(&node->val)) { |
235 | chain = list_entry(node->val.prev, struct callchain_list, list); | 239 | chain = list_entry(node->val.prev, struct callchain_list, list); |
236 | chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); | 240 | chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); |
@@ -241,11 +245,12 @@ static void callchain_node__init_have_children(struct callchain_node *node) | |||
241 | 245 | ||
242 | static void callchain__init_have_children(struct rb_root *root) | 246 | static void callchain__init_have_children(struct rb_root *root) |
243 | { | 247 | { |
244 | struct rb_node *nd; | 248 | struct rb_node *nd = rb_first(root); |
249 | bool has_sibling = nd && rb_next(nd); | ||
245 | 250 | ||
246 | for (nd = rb_first(root); nd; nd = rb_next(nd)) { | 251 | for (nd = rb_first(root); nd; nd = rb_next(nd)) { |
247 | struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); | 252 | struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); |
248 | callchain_node__init_have_children(node); | 253 | callchain_node__init_have_children(node, has_sibling); |
249 | } | 254 | } |
250 | } | 255 | } |
251 | 256 | ||
@@ -542,8 +547,11 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
542 | struct rb_node *node; | 547 | struct rb_node *node; |
543 | int first_row = row, offset = level * LEVEL_OFFSET_STEP; | 548 | int first_row = row, offset = level * LEVEL_OFFSET_STEP; |
544 | u64 new_total; | 549 | u64 new_total; |
550 | bool need_percent; | ||
545 | 551 | ||
546 | node = rb_first(root); | 552 | node = rb_first(root); |
553 | need_percent = !!rb_next(node); | ||
554 | |||
547 | while (node) { | 555 | while (node) { |
548 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); | 556 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); |
549 | struct rb_node *next = rb_next(node); | 557 | struct rb_node *next = rb_next(node); |
@@ -560,7 +568,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
560 | 568 | ||
561 | if (first) | 569 | if (first) |
562 | first = false; | 570 | first = false; |
563 | else if (level > 1) | 571 | else if (need_percent) |
564 | extra_offset = LEVEL_OFFSET_STEP; | 572 | extra_offset = LEVEL_OFFSET_STEP; |
565 | 573 | ||
566 | folded_sign = callchain_list__folded(chain); | 574 | folded_sign = callchain_list__folded(chain); |
@@ -573,7 +581,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
573 | str = callchain_list__sym_name(chain, bf, sizeof(bf), | 581 | str = callchain_list__sym_name(chain, bf, sizeof(bf), |
574 | browser->show_dso); | 582 | browser->show_dso); |
575 | 583 | ||
576 | if (was_first && level > 1) { | 584 | if (was_first && need_percent) { |
577 | double percent = cumul * 100.0 / total; | 585 | double percent = cumul * 100.0 / total; |
578 | 586 | ||
579 | if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) | 587 | if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) |
@@ -790,6 +798,13 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
790 | .is_current_entry = current_entry, | 798 | .is_current_entry = current_entry, |
791 | }; | 799 | }; |
792 | 800 | ||
801 | if (callchain_param.mode == CHAIN_GRAPH_REL) { | ||
802 | if (symbol_conf.cumulate_callchain) | ||
803 | total = entry->stat_acc->period; | ||
804 | else | ||
805 | total = entry->stat.period; | ||
806 | } | ||
807 | |||
793 | printed += hist_browser__show_callchain(browser, | 808 | printed += hist_browser__show_callchain(browser, |
794 | &entry->sorted_chain, 1, row, total, | 809 | &entry->sorted_chain, 1, row, total, |
795 | hist_browser__show_callchain_entry, &arg, | 810 | hist_browser__show_callchain_entry, &arg, |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e5670f1af737..79999ceaf2be 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -1192,7 +1192,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, | |||
1192 | goto next; | 1192 | goto next; |
1193 | 1193 | ||
1194 | offset = start + i; | 1194 | offset = start + i; |
1195 | src_line->path = get_srcline(map->dso, offset); | 1195 | src_line->path = get_srcline(map->dso, offset, NULL, false); |
1196 | insert_source_line(&tmp_root, src_line); | 1196 | insert_source_line(&tmp_root, src_line); |
1197 | 1197 | ||
1198 | next: | 1198 | next: |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 38da69c8c1ff..517ed84db97a 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -815,7 +815,17 @@ char *callchain_list__sym_name(struct callchain_list *cl, | |||
815 | int printed; | 815 | int printed; |
816 | 816 | ||
817 | if (cl->ms.sym) { | 817 | if (cl->ms.sym) { |
818 | printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name); | 818 | if (callchain_param.key == CCKEY_ADDRESS && |
819 | cl->ms.map && !cl->srcline) | ||
820 | cl->srcline = get_srcline(cl->ms.map->dso, | ||
821 | map__rip_2objdump(cl->ms.map, | ||
822 | cl->ip), | ||
823 | cl->ms.sym, false); | ||
824 | if (cl->srcline) | ||
825 | printed = scnprintf(bf, bfsize, "%s %s", | ||
826 | cl->ms.sym->name, cl->srcline); | ||
827 | else | ||
828 | printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name); | ||
819 | } else | 829 | } else |
820 | printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip); | 830 | printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip); |
821 | 831 | ||
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 3e1ed15d11f1..3f158474c892 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -70,6 +70,7 @@ extern struct callchain_param callchain_param; | |||
70 | struct callchain_list { | 70 | struct callchain_list { |
71 | u64 ip; | 71 | u64 ip; |
72 | struct map_symbol ms; | 72 | struct map_symbol ms; |
73 | char *srcline; | ||
73 | struct list_head list; | 74 | struct list_head list; |
74 | }; | 75 | }; |
75 | 76 | ||
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index ba357f3226c6..ad60b2f20258 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -19,13 +19,14 @@ | |||
19 | int verbose; | 19 | int verbose; |
20 | bool dump_trace = false, quiet = false; | 20 | bool dump_trace = false, quiet = false; |
21 | int debug_ordered_events; | 21 | int debug_ordered_events; |
22 | static int redirect_to_stderr; | ||
22 | 23 | ||
23 | static int _eprintf(int level, int var, const char *fmt, va_list args) | 24 | static int _eprintf(int level, int var, const char *fmt, va_list args) |
24 | { | 25 | { |
25 | int ret = 0; | 26 | int ret = 0; |
26 | 27 | ||
27 | if (var >= level) { | 28 | if (var >= level) { |
28 | if (use_browser >= 1) | 29 | if (use_browser >= 1 && !redirect_to_stderr) |
29 | ui_helpline__vshow(fmt, args); | 30 | ui_helpline__vshow(fmt, args); |
30 | else | 31 | else |
31 | ret = vfprintf(stderr, fmt, args); | 32 | ret = vfprintf(stderr, fmt, args); |
@@ -145,6 +146,7 @@ static struct debug_variable { | |||
145 | } debug_variables[] = { | 146 | } debug_variables[] = { |
146 | { .name = "verbose", .ptr = &verbose }, | 147 | { .name = "verbose", .ptr = &verbose }, |
147 | { .name = "ordered-events", .ptr = &debug_ordered_events}, | 148 | { .name = "ordered-events", .ptr = &debug_ordered_events}, |
149 | { .name = "stderr", .ptr = &redirect_to_stderr}, | ||
148 | { .name = NULL, } | 150 | { .name = NULL, } |
149 | }; | 151 | }; |
150 | 152 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f2dc91fb87fa..2d26b7ad6fe0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -876,9 +876,8 @@ void perf_evsel__delete(struct perf_evsel *evsel) | |||
876 | free(evsel); | 876 | free(evsel); |
877 | } | 877 | } |
878 | 878 | ||
879 | static inline void compute_deltas(struct perf_evsel *evsel, | 879 | void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, |
880 | int cpu, | 880 | struct perf_counts_values *count) |
881 | struct perf_counts_values *count) | ||
882 | { | 881 | { |
883 | struct perf_counts_values tmp; | 882 | struct perf_counts_values tmp; |
884 | 883 | ||
@@ -898,6 +897,42 @@ static inline void compute_deltas(struct perf_evsel *evsel, | |||
898 | count->run = count->run - tmp.run; | 897 | count->run = count->run - tmp.run; |
899 | } | 898 | } |
900 | 899 | ||
900 | void perf_counts_values__scale(struct perf_counts_values *count, | ||
901 | bool scale, s8 *pscaled) | ||
902 | { | ||
903 | s8 scaled = 0; | ||
904 | |||
905 | if (scale) { | ||
906 | if (count->run == 0) { | ||
907 | scaled = -1; | ||
908 | count->val = 0; | ||
909 | } else if (count->run < count->ena) { | ||
910 | scaled = 1; | ||
911 | count->val = (u64)((double) count->val * count->ena / count->run + 0.5); | ||
912 | } | ||
913 | } else | ||
914 | count->ena = count->run = 0; | ||
915 | |||
916 | if (pscaled) | ||
917 | *pscaled = scaled; | ||
918 | } | ||
919 | |||
920 | int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread, | ||
921 | perf_evsel__read_cb_t cb) | ||
922 | { | ||
923 | struct perf_counts_values count; | ||
924 | |||
925 | memset(&count, 0, sizeof(count)); | ||
926 | |||
927 | if (FD(evsel, cpu, thread) < 0) | ||
928 | return -EINVAL; | ||
929 | |||
930 | if (readn(FD(evsel, cpu, thread), &count, sizeof(count)) < 0) | ||
931 | return -errno; | ||
932 | |||
933 | return cb(evsel, cpu, thread, &count); | ||
934 | } | ||
935 | |||
901 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 936 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
902 | int cpu, int thread, bool scale) | 937 | int cpu, int thread, bool scale) |
903 | { | 938 | { |
@@ -913,16 +948,8 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | |||
913 | if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) | 948 | if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) |
914 | return -errno; | 949 | return -errno; |
915 | 950 | ||
916 | compute_deltas(evsel, cpu, &count); | 951 | perf_evsel__compute_deltas(evsel, cpu, &count); |
917 | 952 | perf_counts_values__scale(&count, scale, NULL); | |
918 | if (scale) { | ||
919 | if (count.run == 0) | ||
920 | count.val = 0; | ||
921 | else if (count.run < count.ena) | ||
922 | count.val = (u64)((double)count.val * count.ena / count.run + 0.5); | ||
923 | } else | ||
924 | count.ena = count.run = 0; | ||
925 | |||
926 | evsel->counts->cpu[cpu] = count; | 953 | evsel->counts->cpu[cpu] = count; |
927 | return 0; | 954 | return 0; |
928 | } | 955 | } |
@@ -956,23 +983,8 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
956 | } | 983 | } |
957 | } | 984 | } |
958 | 985 | ||
959 | compute_deltas(evsel, -1, aggr); | 986 | perf_evsel__compute_deltas(evsel, -1, aggr); |
960 | 987 | perf_counts_values__scale(aggr, scale, &evsel->counts->scaled); | |
961 | evsel->counts->scaled = 0; | ||
962 | if (scale) { | ||
963 | if (aggr->run == 0) { | ||
964 | evsel->counts->scaled = -1; | ||
965 | aggr->val = 0; | ||
966 | return 0; | ||
967 | } | ||
968 | |||
969 | if (aggr->run < aggr->ena) { | ||
970 | evsel->counts->scaled = 1; | ||
971 | aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5); | ||
972 | } | ||
973 | } else | ||
974 | aggr->ena = aggr->run = 0; | ||
975 | |||
976 | return 0; | 988 | return 0; |
977 | } | 989 | } |
978 | 990 | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 979790951bfb..b18d58da580b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -73,6 +73,7 @@ struct perf_evsel { | |||
73 | char *name; | 73 | char *name; |
74 | double scale; | 74 | double scale; |
75 | const char *unit; | 75 | const char *unit; |
76 | bool snapshot; | ||
76 | struct event_format *tp_format; | 77 | struct event_format *tp_format; |
77 | union { | 78 | union { |
78 | void *priv; | 79 | void *priv; |
@@ -91,6 +92,7 @@ struct perf_evsel { | |||
91 | bool immediate; | 92 | bool immediate; |
92 | bool system_wide; | 93 | bool system_wide; |
93 | bool tracking; | 94 | bool tracking; |
95 | bool per_pkg; | ||
94 | /* parse modifier helper */ | 96 | /* parse modifier helper */ |
95 | int exclude_GH; | 97 | int exclude_GH; |
96 | int nr_members; | 98 | int nr_members; |
@@ -110,6 +112,12 @@ struct thread_map; | |||
110 | struct perf_evlist; | 112 | struct perf_evlist; |
111 | struct record_opts; | 113 | struct record_opts; |
112 | 114 | ||
115 | void perf_counts_values__scale(struct perf_counts_values *count, | ||
116 | bool scale, s8 *pscaled); | ||
117 | |||
118 | void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, | ||
119 | struct perf_counts_values *count); | ||
120 | |||
113 | int perf_evsel__object_config(size_t object_size, | 121 | int perf_evsel__object_config(size_t object_size, |
114 | int (*init)(struct perf_evsel *evsel), | 122 | int (*init)(struct perf_evsel *evsel), |
115 | void (*fini)(struct perf_evsel *evsel)); | 123 | void (*fini)(struct perf_evsel *evsel)); |
@@ -227,6 +235,13 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1, | |||
227 | (a)->attr.type == (b)->attr.type && \ | 235 | (a)->attr.type == (b)->attr.type && \ |
228 | (a)->attr.config == (b)->attr.config) | 236 | (a)->attr.config == (b)->attr.config) |
229 | 237 | ||
238 | typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel, | ||
239 | int cpu, int thread, | ||
240 | struct perf_counts_values *count); | ||
241 | |||
242 | int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread, | ||
243 | perf_evsel__read_cb_t cb); | ||
244 | |||
230 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 245 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
231 | int cpu, int thread, bool scale); | 246 | int cpu, int thread, bool scale); |
232 | 247 | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index d97309c87bd6..b75b487574c7 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -1106,8 +1106,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
1106 | if (__machine__create_kernel_maps(machine, kernel) < 0) | 1106 | if (__machine__create_kernel_maps(machine, kernel) < 0) |
1107 | goto out_problem; | 1107 | goto out_problem; |
1108 | 1108 | ||
1109 | if (strstr(dso->long_name, "vmlinux")) | 1109 | if (strstr(kernel->long_name, "vmlinux")) |
1110 | dso__set_short_name(dso, "[kernel.vmlinux]", false); | 1110 | dso__set_short_name(kernel, "[kernel.vmlinux]", false); |
1111 | 1111 | ||
1112 | machine__set_kernel_mmap_len(machine, event); | 1112 | machine__set_kernel_mmap_len(machine, event); |
1113 | 1113 | ||
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 040a785c857b..62ca9f2607d5 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -360,7 +360,7 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | |||
360 | 360 | ||
361 | if (map && map->dso) { | 361 | if (map && map->dso) { |
362 | srcline = get_srcline(map->dso, | 362 | srcline = get_srcline(map->dso, |
363 | map__rip_2objdump(map, addr)); | 363 | map__rip_2objdump(map, addr), NULL, true); |
364 | if (srcline != SRCLINE_UNKNOWN) | 364 | if (srcline != SRCLINE_UNKNOWN) |
365 | ret = fprintf(fp, "%s%s", prefix, srcline); | 365 | ret = fprintf(fp, "%s%s", prefix, srcline); |
366 | free_srcline(srcline); | 366 | free_srcline(srcline); |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c659a3ca1283..77b43fe43d55 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -681,6 +681,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
681 | if (evsel) { | 681 | if (evsel) { |
682 | evsel->unit = info.unit; | 682 | evsel->unit = info.unit; |
683 | evsel->scale = info.scale; | 683 | evsel->scale = info.scale; |
684 | evsel->per_pkg = info.per_pkg; | ||
685 | evsel->snapshot = info.snapshot; | ||
684 | } | 686 | } |
685 | 687 | ||
686 | return evsel ? 0 : -ENOMEM; | 688 | return evsel ? 0 : -ENOMEM; |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 881b75490533..5c9c4947cfb4 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -163,6 +163,41 @@ error: | |||
163 | return -1; | 163 | return -1; |
164 | } | 164 | } |
165 | 165 | ||
166 | static int | ||
167 | perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) | ||
168 | { | ||
169 | char path[PATH_MAX]; | ||
170 | int fd; | ||
171 | |||
172 | snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); | ||
173 | |||
174 | fd = open(path, O_RDONLY); | ||
175 | if (fd == -1) | ||
176 | return -1; | ||
177 | |||
178 | close(fd); | ||
179 | |||
180 | alias->per_pkg = true; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, | ||
185 | char *dir, char *name) | ||
186 | { | ||
187 | char path[PATH_MAX]; | ||
188 | int fd; | ||
189 | |||
190 | snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); | ||
191 | |||
192 | fd = open(path, O_RDONLY); | ||
193 | if (fd == -1) | ||
194 | return -1; | ||
195 | |||
196 | alias->snapshot = true; | ||
197 | close(fd); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
166 | static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) | 201 | static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) |
167 | { | 202 | { |
168 | struct perf_pmu_alias *alias; | 203 | struct perf_pmu_alias *alias; |
@@ -181,6 +216,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI | |||
181 | INIT_LIST_HEAD(&alias->terms); | 216 | INIT_LIST_HEAD(&alias->terms); |
182 | alias->scale = 1.0; | 217 | alias->scale = 1.0; |
183 | alias->unit[0] = '\0'; | 218 | alias->unit[0] = '\0'; |
219 | alias->per_pkg = false; | ||
184 | 220 | ||
185 | ret = parse_events_terms(&alias->terms, buf); | 221 | ret = parse_events_terms(&alias->terms, buf); |
186 | if (ret) { | 222 | if (ret) { |
@@ -194,6 +230,8 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI | |||
194 | */ | 230 | */ |
195 | perf_pmu__parse_unit(alias, dir, name); | 231 | perf_pmu__parse_unit(alias, dir, name); |
196 | perf_pmu__parse_scale(alias, dir, name); | 232 | perf_pmu__parse_scale(alias, dir, name); |
233 | perf_pmu__parse_per_pkg(alias, dir, name); | ||
234 | perf_pmu__parse_snapshot(alias, dir, name); | ||
197 | 235 | ||
198 | list_add_tail(&alias->list, list); | 236 | list_add_tail(&alias->list, list); |
199 | 237 | ||
@@ -209,6 +247,10 @@ static inline bool pmu_alias_info_file(char *name) | |||
209 | return true; | 247 | return true; |
210 | if (len > 6 && !strcmp(name + len - 6, ".scale")) | 248 | if (len > 6 && !strcmp(name + len - 6, ".scale")) |
211 | return true; | 249 | return true; |
250 | if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) | ||
251 | return true; | ||
252 | if (len > 9 && !strcmp(name + len - 9, ".snapshot")) | ||
253 | return true; | ||
212 | 254 | ||
213 | return false; | 255 | return false; |
214 | } | 256 | } |
@@ -617,23 +659,27 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, | |||
617 | } | 659 | } |
618 | 660 | ||
619 | 661 | ||
620 | static int check_unit_scale(struct perf_pmu_alias *alias, | 662 | static int check_info_data(struct perf_pmu_alias *alias, |
621 | const char **unit, double *scale) | 663 | struct perf_pmu_info *info) |
622 | { | 664 | { |
623 | /* | 665 | /* |
624 | * Only one term in event definition can | 666 | * Only one term in event definition can |
625 | * define unit and scale, fail if there's | 667 | * define unit, scale and snapshot, fail |
626 | * more than one. | 668 | * if there's more than one. |
627 | */ | 669 | */ |
628 | if ((*unit && alias->unit) || | 670 | if ((info->unit && alias->unit) || |
629 | (*scale && alias->scale)) | 671 | (info->scale && alias->scale) || |
672 | (info->snapshot && alias->snapshot)) | ||
630 | return -EINVAL; | 673 | return -EINVAL; |
631 | 674 | ||
632 | if (alias->unit) | 675 | if (alias->unit) |
633 | *unit = alias->unit; | 676 | info->unit = alias->unit; |
634 | 677 | ||
635 | if (alias->scale) | 678 | if (alias->scale) |
636 | *scale = alias->scale; | 679 | info->scale = alias->scale; |
680 | |||
681 | if (alias->snapshot) | ||
682 | info->snapshot = alias->snapshot; | ||
637 | 683 | ||
638 | return 0; | 684 | return 0; |
639 | } | 685 | } |
@@ -649,12 +695,15 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | |||
649 | struct perf_pmu_alias *alias; | 695 | struct perf_pmu_alias *alias; |
650 | int ret; | 696 | int ret; |
651 | 697 | ||
698 | info->per_pkg = false; | ||
699 | |||
652 | /* | 700 | /* |
653 | * Mark unit and scale as not set | 701 | * Mark unit and scale as not set |
654 | * (different from default values, see below) | 702 | * (different from default values, see below) |
655 | */ | 703 | */ |
656 | info->unit = NULL; | 704 | info->unit = NULL; |
657 | info->scale = 0.0; | 705 | info->scale = 0.0; |
706 | info->snapshot = false; | ||
658 | 707 | ||
659 | list_for_each_entry_safe(term, h, head_terms, list) { | 708 | list_for_each_entry_safe(term, h, head_terms, list) { |
660 | alias = pmu_find_alias(pmu, term); | 709 | alias = pmu_find_alias(pmu, term); |
@@ -664,10 +713,13 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | |||
664 | if (ret) | 713 | if (ret) |
665 | return ret; | 714 | return ret; |
666 | 715 | ||
667 | ret = check_unit_scale(alias, &info->unit, &info->scale); | 716 | ret = check_info_data(alias, info); |
668 | if (ret) | 717 | if (ret) |
669 | return ret; | 718 | return ret; |
670 | 719 | ||
720 | if (alias->per_pkg) | ||
721 | info->per_pkg = true; | ||
722 | |||
671 | list_del(&term->list); | 723 | list_del(&term->list); |
672 | free(term); | 724 | free(term); |
673 | } | 725 | } |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 8092de78e818..6b1249fbdb5f 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -29,6 +29,8 @@ struct perf_pmu { | |||
29 | struct perf_pmu_info { | 29 | struct perf_pmu_info { |
30 | const char *unit; | 30 | const char *unit; |
31 | double scale; | 31 | double scale; |
32 | bool per_pkg; | ||
33 | bool snapshot; | ||
32 | }; | 34 | }; |
33 | 35 | ||
34 | #define UNIT_MAX_LEN 31 /* max length for event unit name */ | 36 | #define UNIT_MAX_LEN 31 /* max length for event unit name */ |
@@ -39,6 +41,8 @@ struct perf_pmu_alias { | |||
39 | struct list_head list; /* ELEM */ | 41 | struct list_head list; /* ELEM */ |
40 | char unit[UNIT_MAX_LEN+1]; | 42 | char unit[UNIT_MAX_LEN+1]; |
41 | double scale; | 43 | double scale; |
44 | bool per_pkg; | ||
45 | bool snapshot; | ||
42 | }; | 46 | }; |
43 | 47 | ||
44 | struct perf_pmu *perf_pmu__find(const char *name); | 48 | struct perf_pmu *perf_pmu__find(const char *name); |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 82a5596241a7..9139dda9f9a3 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -291,7 +291,8 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) | |||
291 | else { | 291 | else { |
292 | struct map *map = left->ms.map; | 292 | struct map *map = left->ms.map; |
293 | left->srcline = get_srcline(map->dso, | 293 | left->srcline = get_srcline(map->dso, |
294 | map__rip_2objdump(map, left->ip)); | 294 | map__rip_2objdump(map, left->ip), |
295 | left->ms.sym, true); | ||
295 | } | 296 | } |
296 | } | 297 | } |
297 | if (!right->srcline) { | 298 | if (!right->srcline) { |
@@ -300,7 +301,8 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) | |||
300 | else { | 301 | else { |
301 | struct map *map = right->ms.map; | 302 | struct map *map = right->ms.map; |
302 | right->srcline = get_srcline(map->dso, | 303 | right->srcline = get_srcline(map->dso, |
303 | map__rip_2objdump(map, right->ip)); | 304 | map__rip_2objdump(map, right->ip), |
305 | right->ms.sym, true); | ||
304 | } | 306 | } |
305 | } | 307 | } |
306 | return strcmp(right->srcline, left->srcline); | 308 | return strcmp(right->srcline, left->srcline); |
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 77c180637138..e73b6a5c9e0f 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include "util/util.h" | 8 | #include "util/util.h" |
9 | #include "util/debug.h" | 9 | #include "util/debug.h" |
10 | 10 | ||
11 | #include "symbol.h" | ||
12 | |||
11 | #ifdef HAVE_LIBBFD_SUPPORT | 13 | #ifdef HAVE_LIBBFD_SUPPORT |
12 | 14 | ||
13 | /* | 15 | /* |
@@ -250,7 +252,8 @@ void dso__free_a2l(struct dso *dso __maybe_unused) | |||
250 | */ | 252 | */ |
251 | #define A2L_FAIL_LIMIT 123 | 253 | #define A2L_FAIL_LIMIT 123 |
252 | 254 | ||
253 | char *get_srcline(struct dso *dso, unsigned long addr) | 255 | char *get_srcline(struct dso *dso, unsigned long addr, struct symbol *sym, |
256 | bool show_sym) | ||
254 | { | 257 | { |
255 | char *file = NULL; | 258 | char *file = NULL; |
256 | unsigned line = 0; | 259 | unsigned line = 0; |
@@ -258,7 +261,7 @@ char *get_srcline(struct dso *dso, unsigned long addr) | |||
258 | const char *dso_name; | 261 | const char *dso_name; |
259 | 262 | ||
260 | if (!dso->has_srcline) | 263 | if (!dso->has_srcline) |
261 | return SRCLINE_UNKNOWN; | 264 | goto out; |
262 | 265 | ||
263 | if (dso->symsrc_filename) | 266 | if (dso->symsrc_filename) |
264 | dso_name = dso->symsrc_filename; | 267 | dso_name = dso->symsrc_filename; |
@@ -289,7 +292,13 @@ out: | |||
289 | dso->has_srcline = 0; | 292 | dso->has_srcline = 0; |
290 | dso__free_a2l(dso); | 293 | dso__free_a2l(dso); |
291 | } | 294 | } |
292 | return SRCLINE_UNKNOWN; | 295 | if (sym) { |
296 | if (asprintf(&srcline, "%s+%ld", show_sym ? sym->name : "", | ||
297 | addr - sym->start) < 0) | ||
298 | return SRCLINE_UNKNOWN; | ||
299 | } else if (asprintf(&srcline, "%s[%lx]", dso->short_name, addr) < 0) | ||
300 | return SRCLINE_UNKNOWN; | ||
301 | return srcline; | ||
293 | } | 302 | } |
294 | 303 | ||
295 | void free_srcline(char *srcline) | 304 | void free_srcline(char *srcline) |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index efc7eb6b8f0f..06fcd1bf98b6 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -11,6 +11,27 @@ | |||
11 | #include <symbol/kallsyms.h> | 11 | #include <symbol/kallsyms.h> |
12 | #include "debug.h" | 12 | #include "debug.h" |
13 | 13 | ||
14 | #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT | ||
15 | extern char *cplus_demangle(const char *, int); | ||
16 | |||
17 | static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i) | ||
18 | { | ||
19 | return cplus_demangle(c, i); | ||
20 | } | ||
21 | #else | ||
22 | #ifdef NO_DEMANGLE | ||
23 | static inline char *bfd_demangle(void __maybe_unused *v, | ||
24 | const char __maybe_unused *c, | ||
25 | int __maybe_unused i) | ||
26 | { | ||
27 | return NULL; | ||
28 | } | ||
29 | #else | ||
30 | #define PACKAGE 'perf' | ||
31 | #include <bfd.h> | ||
32 | #endif | ||
33 | #endif | ||
34 | |||
14 | #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT | 35 | #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT |
15 | static int elf_getphdrnum(Elf *elf, size_t *dst) | 36 | static int elf_getphdrnum(Elf *elf, size_t *dst) |
16 | { | 37 | { |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ded3ca7266de..e0b297c50f9d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -23,27 +23,6 @@ | |||
23 | 23 | ||
24 | #include "dso.h" | 24 | #include "dso.h" |
25 | 25 | ||
26 | #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT | ||
27 | extern char *cplus_demangle(const char *, int); | ||
28 | |||
29 | static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i) | ||
30 | { | ||
31 | return cplus_demangle(c, i); | ||
32 | } | ||
33 | #else | ||
34 | #ifdef NO_DEMANGLE | ||
35 | static inline char *bfd_demangle(void __maybe_unused *v, | ||
36 | const char __maybe_unused *c, | ||
37 | int __maybe_unused i) | ||
38 | { | ||
39 | return NULL; | ||
40 | } | ||
41 | #else | ||
42 | #define PACKAGE 'perf' | ||
43 | #include <bfd.h> | ||
44 | #endif | ||
45 | #endif | ||
46 | |||
47 | /* | 26 | /* |
48 | * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; | 27 | * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; |
49 | * for newer versions we can use mmap to reduce memory usage: | 28 | * for newer versions we can use mmap to reduce memory usage: |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 76d23d83eae5..419bee030f83 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -337,8 +337,10 @@ static inline int path__join3(char *bf, size_t size, | |||
337 | } | 337 | } |
338 | 338 | ||
339 | struct dso; | 339 | struct dso; |
340 | struct symbol; | ||
340 | 341 | ||
341 | char *get_srcline(struct dso *dso, unsigned long addr); | 342 | char *get_srcline(struct dso *dso, unsigned long addr, struct symbol *sym, |
343 | bool show_sym); | ||
342 | void free_srcline(char *srcline); | 344 | void free_srcline(char *srcline); |
343 | 345 | ||
344 | int filename__read_int(const char *filename, int *value); | 346 | int filename__read_int(const char *filename, int *value); |