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 /tools | |
| 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>
Diffstat (limited to 'tools')
| -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); |
