aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-12-08 01:44:38 -0500
committerIngo Molnar <mingo@kernel.org>2014-12-08 01:45:23 -0500
commite460bfdcf3b243abebc4682d4312670a4a7dc7a4 (patch)
tree3334e4934bf37f03325e064fcd940997648145ff
parent4e6e311e596eadba30d4f56f64eae7d45611a01c (diff)
parent1d9e446b91e182055d874fbb30150aad479a4981 (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.c25
-rw-r--r--tools/perf/util/annotate.c2
-rw-r--r--tools/perf/util/callchain.c12
-rw-r--r--tools/perf/util/callchain.h1
-rw-r--r--tools/perf/util/debug.c4
-rw-r--r--tools/perf/util/evsel.c72
-rw-r--r--tools/perf/util/evsel.h15
-rw-r--r--tools/perf/util/machine.c4
-rw-r--r--tools/perf/util/map.c2
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/pmu.c74
-rw-r--r--tools/perf/util/pmu.h4
-rw-r--r--tools/perf/util/sort.c6
-rw-r--r--tools/perf/util/srcline.c15
-rw-r--r--tools/perf/util/symbol-elf.c21
-rw-r--r--tools/perf/util/symbol.h21
-rw-r--r--tools/perf/util/util.h4
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
230static void callchain_node__init_have_children(struct callchain_node *node) 230static 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
242static void callchain__init_have_children(struct rb_root *root) 246static 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;
70struct callchain_list { 70struct 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 @@
19int verbose; 19int verbose;
20bool dump_trace = false, quiet = false; 20bool dump_trace = false, quiet = false;
21int debug_ordered_events; 21int debug_ordered_events;
22static int redirect_to_stderr;
22 23
23static int _eprintf(int level, int var, const char *fmt, va_list args) 24static 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
879static inline void compute_deltas(struct perf_evsel *evsel, 879void 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
900void 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
920int 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
901int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 936int __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;
110struct perf_evlist; 112struct perf_evlist;
111struct record_opts; 113struct record_opts;
112 114
115void perf_counts_values__scale(struct perf_counts_values *count,
116 bool scale, s8 *pscaled);
117
118void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
119 struct perf_counts_values *count);
120
113int perf_evsel__object_config(size_t object_size, 121int 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
238typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel,
239 int cpu, int thread,
240 struct perf_counts_values *count);
241
242int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
243 perf_evsel__read_cb_t cb);
244
230int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 245int __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
166static int
167perf_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
184static 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
166static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 201static 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
620static int check_unit_scale(struct perf_pmu_alias *alias, 662static 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 {
29struct perf_pmu_info { 29struct 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
44struct perf_pmu *perf_pmu__find(const char *name); 48struct 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
253char *get_srcline(struct dso *dso, unsigned long addr) 255char *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
295void free_srcline(char *srcline) 304void 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
15extern char *cplus_demangle(const char *, int);
16
17static 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
23static 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
15static int elf_getphdrnum(Elf *elf, size_t *dst) 36static 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
27extern char *cplus_demangle(const char *, int);
28
29static 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
35static 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
339struct dso; 339struct dso;
340struct symbol;
340 341
341char *get_srcline(struct dso *dso, unsigned long addr); 342char *get_srcline(struct dso *dso, unsigned long addr, struct symbol *sym,
343 bool show_sym);
342void free_srcline(char *srcline); 344void free_srcline(char *srcline);
343 345
344int filename__read_int(const char *filename, int *value); 346int filename__read_int(const char *filename, int *value);