aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-05-06 02:35:14 -0400
committerIngo Molnar <mingo@kernel.org>2016-05-06 02:35:14 -0400
commitc0edb7467c3d21b213ff734bfe810d81d2c6ed61 (patch)
tree731d887c8bae23eb0408dcfd2193bc2077f621ee /tools
parent1b6de5917172967acd8db4d222df4225d23a8a60 (diff)
parentb6b85dad30ad7e7394990e2317a780577974a4e6 (diff)
Merge tag 'perf-core-for-mingo-20160505' 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: - Order output of 'perf trace --summary' better, now the threads will appear ascending order of number of events, and then, for each, in descending order of syscalls by the time spent in the syscalls, so that the last page produced can be the one about the most interesting thread straced, suggested by Milian Wolff (Arnaldo Carvalho de Melo) - Do not show the runtime_ms for a thread when not collecting it, that is done so far only with 'perf trace --sched' (Arnaldo Carvalho de Melo) - Fix kallsyms perf test on ppc64le (Naveen N. Rao) Infrastructure changes: - Move global variables related to presence of some keys in the sort order to a per hist struct, to allow code like the hists browser to work with multiple hists with different lists of columns (Jiri Olsa) - Add support for generating bpf prologue in powerpc (Naveen N. Rao) - Fix kprobe and kretprobe handling with kallsyms on ppc64le (Naveen N. Rao) - evlist mmap changes, prep work for supporting reading backwards (Wang Nan) 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/arch/powerpc/Makefile1
-rw-r--r--tools/perf/arch/powerpc/util/dwarf-regs.c40
-rw-r--r--tools/perf/arch/powerpc/util/sym-handling.c43
-rw-r--r--tools/perf/builtin-diff.c4
-rw-r--r--tools/perf/builtin-report.c4
-rw-r--r--tools/perf/builtin-top.c8
-rw-r--r--tools/perf/builtin-trace.c87
-rw-r--r--tools/perf/tests/hists_common.c2
-rw-r--r--tools/perf/tests/hists_cumulate.c2
-rw-r--r--tools/perf/tests/hists_link.c4
-rw-r--r--tools/perf/tests/hists_output.c2
-rw-r--r--tools/perf/ui/browsers/hists.c32
-rw-r--r--tools/perf/ui/gtk/hists.c2
-rw-r--r--tools/perf/ui/hist.c2
-rw-r--r--tools/perf/util/annotate.c2
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/evlist.c56
-rw-r--r--tools/perf/util/hist.c14
-rw-r--r--tools/perf/util/hist.h10
-rw-r--r--tools/perf/util/machine.c9
-rw-r--r--tools/perf/util/machine.h1
-rw-r--r--tools/perf/util/probe-event.c5
-rw-r--r--tools/perf/util/probe-event.h3
-rw-r--r--tools/perf/util/rb_resort.h149
-rw-r--r--tools/perf/util/sort.c35
-rw-r--r--tools/perf/util/sort.h7
-rw-r--r--tools/perf/util/symbol-elf.c7
-rw-r--r--tools/perf/util/symbol.h3
28 files changed, 382 insertions, 154 deletions
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 56e05f126ad8..cc3930904d68 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -3,4 +3,5 @@ PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4 4
5HAVE_KVM_STAT_SUPPORT := 1 5HAVE_KVM_STAT_SUPPORT := 1
6PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
6PERF_HAVE_JITDUMP := 1 7PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c
index 733151cdf46e..41bdf9530d82 100644
--- a/tools/perf/arch/powerpc/util/dwarf-regs.c
+++ b/tools/perf/arch/powerpc/util/dwarf-regs.c
@@ -10,19 +10,26 @@
10 */ 10 */
11 11
12#include <stddef.h> 12#include <stddef.h>
13#include <errno.h>
14#include <string.h>
13#include <dwarf-regs.h> 15#include <dwarf-regs.h>
14 16#include <linux/ptrace.h>
17#include <linux/kernel.h>
18#include "util.h"
15 19
16struct pt_regs_dwarfnum { 20struct pt_regs_dwarfnum {
17 const char *name; 21 const char *name;
18 unsigned int dwarfnum; 22 unsigned int dwarfnum;
23 unsigned int ptregs_offset;
19}; 24};
20 25
21#define STR(s) #s 26#define REG_DWARFNUM_NAME(r, num) \
22#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} 27 {.name = STR(%)STR(r), .dwarfnum = num, \
23#define GPR_DWARFNUM_NAME(num) \ 28 .ptregs_offset = offsetof(struct pt_regs, r)}
24 {.name = STR(%gpr##num), .dwarfnum = num} 29#define GPR_DWARFNUM_NAME(num) \
25#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} 30 {.name = STR(%gpr##num), .dwarfnum = num, \
31 .ptregs_offset = offsetof(struct pt_regs, gpr[num])}
32#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0, .ptregs_offset = 0}
26 33
27/* 34/*
28 * Reference: 35 * Reference:
@@ -61,12 +68,12 @@ static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
61 GPR_DWARFNUM_NAME(29), 68 GPR_DWARFNUM_NAME(29),
62 GPR_DWARFNUM_NAME(30), 69 GPR_DWARFNUM_NAME(30),
63 GPR_DWARFNUM_NAME(31), 70 GPR_DWARFNUM_NAME(31),
64 REG_DWARFNUM_NAME("%msr", 66), 71 REG_DWARFNUM_NAME(msr, 66),
65 REG_DWARFNUM_NAME("%ctr", 109), 72 REG_DWARFNUM_NAME(ctr, 109),
66 REG_DWARFNUM_NAME("%link", 108), 73 REG_DWARFNUM_NAME(link, 108),
67 REG_DWARFNUM_NAME("%xer", 101), 74 REG_DWARFNUM_NAME(xer, 101),
68 REG_DWARFNUM_NAME("%dar", 119), 75 REG_DWARFNUM_NAME(dar, 119),
69 REG_DWARFNUM_NAME("%dsisr", 118), 76 REG_DWARFNUM_NAME(dsisr, 118),
70 REG_DWARFNUM_END, 77 REG_DWARFNUM_END,
71}; 78};
72 79
@@ -86,3 +93,12 @@ const char *get_arch_regstr(unsigned int n)
86 return roff->name; 93 return roff->name;
87 return NULL; 94 return NULL;
88} 95}
96
97int regs_query_register_offset(const char *name)
98{
99 const struct pt_regs_dwarfnum *roff;
100 for (roff = regdwarfnum_table; roff->name != NULL; roff++)
101 if (!strcmp(roff->name, name))
102 return roff->ptregs_offset;
103 return -EINVAL;
104}
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
index bbc1a50768dd..c6d0f91731a1 100644
--- a/tools/perf/arch/powerpc/util/sym-handling.c
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -19,12 +19,6 @@ bool elf__needs_adjust_symbols(GElf_Ehdr ehdr)
19 ehdr.e_type == ET_DYN; 19 ehdr.e_type == ET_DYN;
20} 20}
21 21
22#if defined(_CALL_ELF) && _CALL_ELF == 2
23void arch__elf_sym_adjust(GElf_Sym *sym)
24{
25 sym->st_value += PPC64_LOCAL_ENTRY_OFFSET(sym->st_other);
26}
27#endif
28#endif 22#endif
29 23
30#if !defined(_CALL_ELF) || _CALL_ELF != 2 24#if !defined(_CALL_ELF) || _CALL_ELF != 2
@@ -65,18 +59,45 @@ bool arch__prefers_symtab(void)
65 return true; 59 return true;
66} 60}
67 61
62#ifdef HAVE_LIBELF_SUPPORT
63void arch__sym_update(struct symbol *s, GElf_Sym *sym)
64{
65 s->arch_sym = sym->st_other;
66}
67#endif
68
68#define PPC64LE_LEP_OFFSET 8 69#define PPC64LE_LEP_OFFSET 8
69 70
70void arch__fix_tev_from_maps(struct perf_probe_event *pev, 71void arch__fix_tev_from_maps(struct perf_probe_event *pev,
71 struct probe_trace_event *tev, struct map *map) 72 struct probe_trace_event *tev, struct map *map,
73 struct symbol *sym)
72{ 74{
75 int lep_offset;
76
73 /* 77 /*
74 * ppc64 ABIv2 local entry point is currently always 2 instructions 78 * When probing at a function entry point, we normally always want the
75 * (8 bytes) after the global entry point. 79 * LEP since that catches calls to the function through both the GEP and
80 * the LEP. Hence, we would like to probe at an offset of 8 bytes if
81 * the user only specified the function entry.
82 *
83 * However, if the user specifies an offset, we fall back to using the
84 * GEP since all userspace applications (objdump/readelf) show function
85 * disassembly with offsets from the GEP.
86 *
87 * In addition, we shouldn't specify an offset for kretprobes.
76 */ 88 */
77 if (!pev->uprobes && map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { 89 if (pev->point.offset || pev->point.retprobe || !map || !sym)
78 tev->point.address += PPC64LE_LEP_OFFSET; 90 return;
91
92 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym);
93
94 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS)
79 tev->point.offset += PPC64LE_LEP_OFFSET; 95 tev->point.offset += PPC64LE_LEP_OFFSET;
96 else if (lep_offset) {
97 if (pev->uprobes)
98 tev->point.address += lep_offset;
99 else
100 tev->point.offset += lep_offset;
80 } 101 }
81} 102}
82#endif 103#endif
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 8053a8ceefda..9ce354f469dc 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -428,7 +428,7 @@ static void hists__baseline_only(struct hists *hists)
428 struct rb_root *root; 428 struct rb_root *root;
429 struct rb_node *next; 429 struct rb_node *next;
430 430
431 if (sort__need_collapse) 431 if (hists__has(hists, need_collapse))
432 root = &hists->entries_collapsed; 432 root = &hists->entries_collapsed;
433 else 433 else
434 root = hists->entries_in; 434 root = hists->entries_in;
@@ -450,7 +450,7 @@ static void hists__precompute(struct hists *hists)
450 struct rb_root *root; 450 struct rb_root *root;
451 struct rb_node *next; 451 struct rb_node *next;
452 452
453 if (sort__need_collapse) 453 if (hists__has(hists, need_collapse))
454 root = &hists->entries_collapsed; 454 root = &hists->entries_collapsed;
455 else 455 else
456 root = hists->entries_in; 456 root = hists->entries_in;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 8d9b88af901d..87d40e3c4078 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -234,7 +234,7 @@ static int report__setup_sample_type(struct report *rep)
234 sample_type |= PERF_SAMPLE_BRANCH_STACK; 234 sample_type |= PERF_SAMPLE_BRANCH_STACK;
235 235
236 if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 236 if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
237 if (sort__has_parent) { 237 if (perf_hpp_list.parent) {
238 ui__error("Selected --sort parent, but no " 238 ui__error("Selected --sort parent, but no "
239 "callchain data. Did you call " 239 "callchain data. Did you call "
240 "'perf record' without -g?\n"); 240 "'perf record' without -g?\n");
@@ -936,7 +936,7 @@ repeat:
936 goto error; 936 goto error;
937 } 937 }
938 938
939 sort__need_collapse = true; 939 perf_hpp_list.need_collapse = true;
940 } 940 }
941 941
942 /* Force tty output for header output and per-thread stat. */ 942 /* Force tty output for header output and per-thread stat. */
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index da18517b1d40..1793da585676 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -688,7 +688,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter,
688 struct hist_entry *he = iter->he; 688 struct hist_entry *he = iter->he;
689 struct perf_evsel *evsel = iter->evsel; 689 struct perf_evsel *evsel = iter->evsel;
690 690
691 if (sort__has_sym && single) 691 if (perf_hpp_list.sym && single)
692 perf_top__record_precise_ip(top, he, evsel->idx, al->addr); 692 perf_top__record_precise_ip(top, he, evsel->idx, al->addr);
693 693
694 hist__account_cycles(iter->sample->branch_stack, al, iter->sample, 694 hist__account_cycles(iter->sample->branch_stack, al, iter->sample,
@@ -919,7 +919,7 @@ out_err:
919 919
920static int callchain_param__setup_sample_type(struct callchain_param *callchain) 920static int callchain_param__setup_sample_type(struct callchain_param *callchain)
921{ 921{
922 if (!sort__has_sym) { 922 if (!perf_hpp_list.sym) {
923 if (callchain->enabled) { 923 if (callchain->enabled) {
924 ui__error("Selected -g but \"sym\" not present in --sort/-s."); 924 ui__error("Selected -g but \"sym\" not present in --sort/-s.");
925 return -EINVAL; 925 return -EINVAL;
@@ -962,7 +962,7 @@ static int __cmd_top(struct perf_top *top)
962 machine__synthesize_threads(&top->session->machines.host, &opts->target, 962 machine__synthesize_threads(&top->session->machines.host, &opts->target,
963 top->evlist->threads, false, opts->proc_map_timeout); 963 top->evlist->threads, false, opts->proc_map_timeout);
964 964
965 if (sort__has_socket) { 965 if (perf_hpp_list.socket) {
966 ret = perf_env__read_cpu_topology_map(&perf_env); 966 ret = perf_env__read_cpu_topology_map(&perf_env);
967 if (ret < 0) 967 if (ret < 0)
968 goto out_err_cpu_topo; 968 goto out_err_cpu_topo;
@@ -1255,7 +1255,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1255 1255
1256 sort__mode = SORT_MODE__TOP; 1256 sort__mode = SORT_MODE__TOP;
1257 /* display thread wants entries to be collapsed in a different tree */ 1257 /* display thread wants entries to be collapsed in a different tree */
1258 sort__need_collapse = 1; 1258 perf_hpp_list.need_collapse = 1;
1259 1259
1260 if (top.use_stdio) 1260 if (top.use_stdio)
1261 use_browser = 0; 1261 use_browser = 0;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 9e38fe973f0c..66aa2a00414b 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -36,6 +36,7 @@
36#include "util/bpf-loader.h" 36#include "util/bpf-loader.h"
37#include "callchain.h" 37#include "callchain.h"
38#include "syscalltbl.h" 38#include "syscalltbl.h"
39#include "rb_resort.h"
39 40
40#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */ 41#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
41#include <stdlib.h> 42#include <stdlib.h>
@@ -2784,15 +2785,29 @@ static size_t trace__fprintf_threads_header(FILE *fp)
2784 return printed; 2785 return printed;
2785} 2786}
2786 2787
2788DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2789 struct stats *stats;
2790 double msecs;
2791 int syscall;
2792)
2793{
2794 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2795 struct stats *stats = source->priv;
2796
2797 entry->syscall = source->i;
2798 entry->stats = stats;
2799 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2800}
2801
2787static size_t thread__dump_stats(struct thread_trace *ttrace, 2802static size_t thread__dump_stats(struct thread_trace *ttrace,
2788 struct trace *trace, FILE *fp) 2803 struct trace *trace, FILE *fp)
2789{ 2804{
2790 struct stats *stats;
2791 size_t printed = 0; 2805 size_t printed = 0;
2792 struct syscall *sc; 2806 struct syscall *sc;
2793 struct int_node *inode = intlist__first(ttrace->syscall_stats); 2807 struct rb_node *nd;
2808 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
2794 2809
2795 if (inode == NULL) 2810 if (syscall_stats == NULL)
2796 return 0; 2811 return 0;
2797 2812
2798 printed += fprintf(fp, "\n"); 2813 printed += fprintf(fp, "\n");
@@ -2801,9 +2816,8 @@ static size_t thread__dump_stats(struct thread_trace *ttrace,
2801 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); 2816 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2802 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n"); 2817 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
2803 2818
2804 /* each int_node is a syscall */ 2819 resort_rb__for_each(nd, syscall_stats) {
2805 while (inode) { 2820 struct stats *stats = syscall_stats_entry->stats;
2806 stats = inode->priv;
2807 if (stats) { 2821 if (stats) {
2808 double min = (double)(stats->min) / NSEC_PER_MSEC; 2822 double min = (double)(stats->min) / NSEC_PER_MSEC;
2809 double max = (double)(stats->max) / NSEC_PER_MSEC; 2823 double max = (double)(stats->max) / NSEC_PER_MSEC;
@@ -2814,34 +2828,23 @@ static size_t thread__dump_stats(struct thread_trace *ttrace,
2814 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0; 2828 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2815 avg /= NSEC_PER_MSEC; 2829 avg /= NSEC_PER_MSEC;
2816 2830
2817 sc = &trace->syscalls.table[inode->i]; 2831 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
2818 printed += fprintf(fp, " %-15s", sc->name); 2832 printed += fprintf(fp, " %-15s", sc->name);
2819 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f", 2833 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2820 n, avg * n, min, avg); 2834 n, syscall_stats_entry->msecs, min, avg);
2821 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct); 2835 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
2822 } 2836 }
2823
2824 inode = intlist__next(inode);
2825 } 2837 }
2826 2838
2839 resort_rb__delete(syscall_stats);
2827 printed += fprintf(fp, "\n\n"); 2840 printed += fprintf(fp, "\n\n");
2828 2841
2829 return printed; 2842 return printed;
2830} 2843}
2831 2844
2832/* struct used to pass data to per-thread function */ 2845static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
2833struct summary_data {
2834 FILE *fp;
2835 struct trace *trace;
2836 size_t printed;
2837};
2838
2839static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2840{ 2846{
2841 struct summary_data *data = priv; 2847 size_t printed = 0;
2842 FILE *fp = data->fp;
2843 size_t printed = data->printed;
2844 struct trace *trace = data->trace;
2845 struct thread_trace *ttrace = thread__priv(thread); 2848 struct thread_trace *ttrace = thread__priv(thread);
2846 double ratio; 2849 double ratio;
2847 2850
@@ -2857,25 +2860,45 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2857 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj); 2860 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2858 if (ttrace->pfmin) 2861 if (ttrace->pfmin)
2859 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin); 2862 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
2860 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); 2863 if (trace->sched)
2864 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2865 else if (fputc('\n', fp) != EOF)
2866 ++printed;
2867
2861 printed += thread__dump_stats(ttrace, trace, fp); 2868 printed += thread__dump_stats(ttrace, trace, fp);
2862 2869
2863 data->printed += printed; 2870 return printed;
2871}
2872
2873static unsigned long thread__nr_events(struct thread_trace *ttrace)
2874{
2875 return ttrace ? ttrace->nr_events : 0;
2876}
2864 2877
2865 return 0; 2878DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2879 struct thread *thread;
2880)
2881{
2882 entry->thread = rb_entry(nd, struct thread, rb_node);
2866} 2883}
2867 2884
2868static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) 2885static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2869{ 2886{
2870 struct summary_data data = { 2887 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2871 .fp = fp, 2888 size_t printed = trace__fprintf_threads_header(fp);
2872 .trace = trace 2889 struct rb_node *nd;
2873 }; 2890
2874 data.printed = trace__fprintf_threads_header(fp); 2891 if (threads == NULL) {
2892 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2893 return 0;
2894 }
2895
2896 resort_rb__for_each(nd, threads)
2897 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2875 2898
2876 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data); 2899 resort_rb__delete(threads);
2877 2900
2878 return data.printed; 2901 return printed;
2879} 2902}
2880 2903
2881static int trace__set_duration(const struct option *opt, const char *str, 2904static int trace__set_duration(const struct option *opt, const char *str,
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index f55f4bd47932..6b21746d6eec 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -161,7 +161,7 @@ void print_hists_in(struct hists *hists)
161 struct rb_root *root; 161 struct rb_root *root;
162 struct rb_node *node; 162 struct rb_node *node;
163 163
164 if (sort__need_collapse) 164 if (hists__has(hists, need_collapse))
165 root = &hists->entries_collapsed; 165 root = &hists->entries_collapsed;
166 else 166 else
167 root = hists->entries_in; 167 root = hists->entries_in;
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 4a2bbff9b1ee..a9e3db3afac4 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -126,7 +126,7 @@ static void del_hist_entries(struct hists *hists)
126 struct rb_root *root_out; 126 struct rb_root *root_out;
127 struct rb_node *node; 127 struct rb_node *node;
128 128
129 if (sort__need_collapse) 129 if (hists__has(hists, need_collapse))
130 root_in = &hists->entries_collapsed; 130 root_in = &hists->entries_collapsed;
131 else 131 else
132 root_in = hists->entries_in; 132 root_in = hists->entries_in;
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 358324e47805..acf5a1301c07 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -145,7 +145,7 @@ static int __validate_match(struct hists *hists)
145 /* 145 /*
146 * Only entries from fake_common_samples should have a pair. 146 * Only entries from fake_common_samples should have a pair.
147 */ 147 */
148 if (sort__need_collapse) 148 if (hists__has(hists, need_collapse))
149 root = &hists->entries_collapsed; 149 root = &hists->entries_collapsed;
150 else 150 else
151 root = hists->entries_in; 151 root = hists->entries_in;
@@ -197,7 +197,7 @@ static int __validate_link(struct hists *hists, int idx)
197 * and some entries will have no pair. However every entry 197 * and some entries will have no pair. However every entry
198 * in other hists should have (dummy) pair. 198 * in other hists should have (dummy) pair.
199 */ 199 */
200 if (sort__need_collapse) 200 if (hists__has(hists, need_collapse))
201 root = &hists->entries_collapsed; 201 root = &hists->entries_collapsed;
202 else 202 else
203 root = hists->entries_in; 203 root = hists->entries_in;
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index 7cd8738e842f..63c5efaba1b5 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -92,7 +92,7 @@ static void del_hist_entries(struct hists *hists)
92 struct rb_root *root_out; 92 struct rb_root *root_out;
93 struct rb_node *node; 93 struct rb_node *node;
94 94
95 if (sort__need_collapse) 95 if (hists__has(hists, need_collapse))
96 root_in = &hists->entries_collapsed; 96 root_in = &hists->entries_collapsed;
97 else 97 else
98 root_in = hists->entries_in; 98 root_in = hists->entries_in;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 6a4681932ba5..538bae880bfe 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2135,7 +2135,7 @@ static int hists__browser_title(struct hists *hists,
2135 printed += snprintf(bf + printed, size - printed, 2135 printed += snprintf(bf + printed, size - printed,
2136 ", UID: %s", hists->uid_filter_str); 2136 ", UID: %s", hists->uid_filter_str);
2137 if (thread) { 2137 if (thread) {
2138 if (sort__has_thread) { 2138 if (hists__has(hists, thread)) {
2139 printed += scnprintf(bf + printed, size - printed, 2139 printed += scnprintf(bf + printed, size - printed,
2140 ", Thread: %s(%d)", 2140 ", Thread: %s(%d)",
2141 (thread->comm_set ? thread__comm_str(thread) : ""), 2141 (thread->comm_set ? thread__comm_str(thread) : ""),
@@ -2320,7 +2320,8 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2320{ 2320{
2321 struct thread *thread = act->thread; 2321 struct thread *thread = act->thread;
2322 2322
2323 if ((!sort__has_thread && !sort__has_comm) || thread == NULL) 2323 if ((!hists__has(browser->hists, thread) &&
2324 !hists__has(browser->hists, comm)) || thread == NULL)
2324 return 0; 2325 return 0;
2325 2326
2326 if (browser->hists->thread_filter) { 2327 if (browser->hists->thread_filter) {
@@ -2329,7 +2330,7 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
2329 thread__zput(browser->hists->thread_filter); 2330 thread__zput(browser->hists->thread_filter);
2330 ui_helpline__pop(); 2331 ui_helpline__pop();
2331 } else { 2332 } else {
2332 if (sort__has_thread) { 2333 if (hists__has(browser->hists, thread)) {
2333 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 2334 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
2334 thread->comm_set ? thread__comm_str(thread) : "", 2335 thread->comm_set ? thread__comm_str(thread) : "",
2335 thread->tid); 2336 thread->tid);
@@ -2354,10 +2355,11 @@ add_thread_opt(struct hist_browser *browser, struct popup_action *act,
2354{ 2355{
2355 int ret; 2356 int ret;
2356 2357
2357 if ((!sort__has_thread && !sort__has_comm) || thread == NULL) 2358 if ((!hists__has(browser->hists, thread) &&
2359 !hists__has(browser->hists, comm)) || thread == NULL)
2358 return 0; 2360 return 0;
2359 2361
2360 if (sort__has_thread) { 2362 if (hists__has(browser->hists, thread)) {
2361 ret = asprintf(optstr, "Zoom %s %s(%d) thread", 2363 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
2362 browser->hists->thread_filter ? "out of" : "into", 2364 browser->hists->thread_filter ? "out of" : "into",
2363 thread->comm_set ? thread__comm_str(thread) : "", 2365 thread->comm_set ? thread__comm_str(thread) : "",
@@ -2380,7 +2382,7 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2380{ 2382{
2381 struct map *map = act->ms.map; 2383 struct map *map = act->ms.map;
2382 2384
2383 if (!sort__has_dso || map == NULL) 2385 if (!hists__has(browser->hists, dso) || map == NULL)
2384 return 0; 2386 return 0;
2385 2387
2386 if (browser->hists->dso_filter) { 2388 if (browser->hists->dso_filter) {
@@ -2407,7 +2409,7 @@ static int
2407add_dso_opt(struct hist_browser *browser, struct popup_action *act, 2409add_dso_opt(struct hist_browser *browser, struct popup_action *act,
2408 char **optstr, struct map *map) 2410 char **optstr, struct map *map)
2409{ 2411{
2410 if (!sort__has_dso || map == NULL) 2412 if (!hists__has(browser->hists, dso) || map == NULL)
2411 return 0; 2413 return 0;
2412 2414
2413 if (asprintf(optstr, "Zoom %s %s DSO", 2415 if (asprintf(optstr, "Zoom %s %s DSO",
@@ -2429,10 +2431,10 @@ do_browse_map(struct hist_browser *browser __maybe_unused,
2429} 2431}
2430 2432
2431static int 2433static int
2432add_map_opt(struct hist_browser *browser __maybe_unused, 2434add_map_opt(struct hist_browser *browser,
2433 struct popup_action *act, char **optstr, struct map *map) 2435 struct popup_action *act, char **optstr, struct map *map)
2434{ 2436{
2435 if (!sort__has_dso || map == NULL) 2437 if (!hists__has(browser->hists, dso) || map == NULL)
2436 return 0; 2438 return 0;
2437 2439
2438 if (asprintf(optstr, "Browse map details") < 0) 2440 if (asprintf(optstr, "Browse map details") < 0)
@@ -2534,7 +2536,7 @@ add_exit_opt(struct hist_browser *browser __maybe_unused,
2534static int 2536static int
2535do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 2537do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
2536{ 2538{
2537 if (!sort__has_socket || act->socket < 0) 2539 if (!hists__has(browser->hists, socket) || act->socket < 0)
2538 return 0; 2540 return 0;
2539 2541
2540 if (browser->hists->socket_filter > -1) { 2542 if (browser->hists->socket_filter > -1) {
@@ -2556,7 +2558,7 @@ static int
2556add_socket_opt(struct hist_browser *browser, struct popup_action *act, 2558add_socket_opt(struct hist_browser *browser, struct popup_action *act,
2557 char **optstr, int socket_id) 2559 char **optstr, int socket_id)
2558{ 2560{
2559 if (!sort__has_socket || socket_id < 0) 2561 if (!hists__has(browser->hists, socket) || socket_id < 0)
2560 return 0; 2562 return 0;
2561 2563
2562 if (asprintf(optstr, "Zoom %s Processor Socket %d", 2564 if (asprintf(optstr, "Zoom %s Processor Socket %d",
@@ -2747,7 +2749,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2747 */ 2749 */
2748 goto out_free_stack; 2750 goto out_free_stack;
2749 case 'a': 2751 case 'a':
2750 if (!sort__has_sym) { 2752 if (!hists__has(hists, sym)) {
2751 ui_browser__warning(&browser->b, delay_secs * 2, 2753 ui_browser__warning(&browser->b, delay_secs * 2,
2752 "Annotation is only available for symbolic views, " 2754 "Annotation is only available for symbolic views, "
2753 "include \"sym*\" in --sort to use it."); 2755 "include \"sym*\" in --sort to use it.");
@@ -2910,7 +2912,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2910 continue; 2912 continue;
2911 } 2913 }
2912 2914
2913 if (!sort__has_sym || browser->selection == NULL) 2915 if (!hists__has(hists, sym) || browser->selection == NULL)
2914 goto skip_annotation; 2916 goto skip_annotation;
2915 2917
2916 if (sort__mode == SORT_MODE__BRANCH) { 2918 if (sort__mode == SORT_MODE__BRANCH) {
@@ -2954,7 +2956,7 @@ skip_annotation:
2954 goto skip_scripting; 2956 goto skip_scripting;
2955 2957
2956 if (browser->he_selection) { 2958 if (browser->he_selection) {
2957 if (sort__has_thread && thread) { 2959 if (hists__has(hists, thread) && thread) {
2958 nr_options += add_script_opt(browser, 2960 nr_options += add_script_opt(browser,
2959 &actions[nr_options], 2961 &actions[nr_options],
2960 &options[nr_options], 2962 &options[nr_options],
@@ -2969,7 +2971,7 @@ skip_annotation:
2969 * 2971 *
2970 * See hist_browser__show_entry. 2972 * See hist_browser__show_entry.
2971 */ 2973 */
2972 if (sort__has_sym && browser->selection->sym) { 2974 if (hists__has(hists, sym) && browser->selection->sym) {
2973 nr_options += add_script_opt(browser, 2975 nr_options += add_script_opt(browser,
2974 &actions[nr_options], 2976 &actions[nr_options],
2975 &options[nr_options], 2977 &options[nr_options],
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 2aa45b606fa4..932adfaa05af 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -379,7 +379,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
379 gtk_tree_store_set(store, &iter, col_idx++, s, -1); 379 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
380 } 380 }
381 381
382 if (symbol_conf.use_callchain && sort__has_sym) { 382 if (symbol_conf.use_callchain && hists__has(hists, sym)) {
383 if (callchain_param.mode == CHAIN_GRAPH_REL) 383 if (callchain_param.mode == CHAIN_GRAPH_REL)
384 total = symbol_conf.cumulate_callchain ? 384 total = symbol_conf.cumulate_callchain ?
385 h->stat_acc->period : h->stat.period; 385 h->stat_acc->period : h->stat.period;
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 3baeaa6e71b5..af07ffb129ca 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -635,7 +635,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
635 ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); 635 ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
636 } 636 }
637 637
638 if (verbose && sort__has_sym) /* Addr + origin */ 638 if (verbose && hists__has(hists, sym)) /* Addr + origin */
639 ret += 3 + BITS_PER_LONG / 4; 639 ret += 3 + BITS_PER_LONG / 4;
640 640
641 return ret; 641 return ret;
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index b795b6994144..d4b3d034c503 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1665,5 +1665,5 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1665 1665
1666bool ui__has_annotation(void) 1666bool ui__has_annotation(void)
1667{ 1667{
1668 return use_browser == 1 && sort__has_sym; 1668 return use_browser == 1 && perf_hpp_list.sym;
1669} 1669}
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index aa248dcb4440..07fd30bc2f81 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -799,7 +799,7 @@ int sample__resolve_callchain(struct perf_sample *sample,
799 return 0; 799 return 0;
800 800
801 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || 801 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
802 sort__has_parent) { 802 perf_hpp_list.parent) {
803 return thread__resolve_callchain(al->thread, cursor, evsel, sample, 803 return thread__resolve_callchain(al->thread, cursor, evsel, sample,
804 parent, al, max_stack); 804 parent, al, max_stack);
805 } 805 }
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 85271e54a63b..17cd01421e7f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -679,39 +679,31 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
679 return NULL; 679 return NULL;
680} 680}
681 681
682union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 682/* When check_messup is true, 'end' must points to a good entry */
683static union perf_event *
684perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start,
685 u64 end, u64 *prev)
683{ 686{
684 struct perf_mmap *md = &evlist->mmap[idx];
685 u64 head;
686 u64 old = md->prev;
687 int diff;
688 unsigned char *data = md->base + page_size; 687 unsigned char *data = md->base + page_size;
689 union perf_event *event = NULL; 688 union perf_event *event = NULL;
689 int diff = end - start;
690 690
691 /* 691 if (check_messup) {
692 * Check if event was unmapped due to a POLLHUP/POLLERR.
693 */
694 if (!atomic_read(&md->refcnt))
695 return NULL;
696
697 head = perf_mmap__read_head(md);
698 diff = head - old;
699 if (evlist->overwrite) {
700 /* 692 /*
701 * If we're further behind than half the buffer, there's a chance 693 * If we're further behind than half the buffer, there's a chance
702 * the writer will bite our tail and mess up the samples under us. 694 * the writer will bite our tail and mess up the samples under us.
703 * 695 *
704 * If we somehow ended up ahead of the head, we got messed up. 696 * If we somehow ended up ahead of the 'end', we got messed up.
705 * 697 *
706 * In either case, truncate and restart at head. 698 * In either case, truncate and restart at 'end'.
707 */ 699 */
708 if (diff > md->mask / 2 || diff < 0) { 700 if (diff > md->mask / 2 || diff < 0) {
709 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); 701 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
710 702
711 /* 703 /*
712 * head points to a known good entry, start there. 704 * 'end' points to a known good entry, start there.
713 */ 705 */
714 old = head; 706 start = end;
715 diff = 0; 707 diff = 0;
716 } 708 }
717 } 709 }
@@ -719,7 +711,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
719 if (diff >= (int)sizeof(event->header)) { 711 if (diff >= (int)sizeof(event->header)) {
720 size_t size; 712 size_t size;
721 713
722 event = (union perf_event *)&data[old & md->mask]; 714 event = (union perf_event *)&data[start & md->mask];
723 size = event->header.size; 715 size = event->header.size;
724 716
725 if (size < sizeof(event->header) || diff < (int)size) { 717 if (size < sizeof(event->header) || diff < (int)size) {
@@ -731,8 +723,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
731 * Event straddles the mmap boundary -- header should always 723 * Event straddles the mmap boundary -- header should always
732 * be inside due to u64 alignment of output. 724 * be inside due to u64 alignment of output.
733 */ 725 */
734 if ((old & md->mask) + size != ((old + size) & md->mask)) { 726 if ((start & md->mask) + size != ((start + size) & md->mask)) {
735 unsigned int offset = old; 727 unsigned int offset = start;
736 unsigned int len = min(sizeof(*event), size), cpy; 728 unsigned int len = min(sizeof(*event), size), cpy;
737 void *dst = md->event_copy; 729 void *dst = md->event_copy;
738 730
@@ -747,15 +739,33 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
747 event = (union perf_event *) md->event_copy; 739 event = (union perf_event *) md->event_copy;
748 } 740 }
749 741
750 old += size; 742 start += size;
751 } 743 }
752 744
753broken_event: 745broken_event:
754 md->prev = old; 746 if (prev)
747 *prev = start;
755 748
756 return event; 749 return event;
757} 750}
758 751
752union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
753{
754 struct perf_mmap *md = &evlist->mmap[idx];
755 u64 head;
756 u64 old = md->prev;
757
758 /*
759 * Check if event was unmapped due to a POLLHUP/POLLERR.
760 */
761 if (!atomic_read(&md->refcnt))
762 return NULL;
763
764 head = perf_mmap__read_head(md);
765
766 return perf_mmap__read(md, evlist->overwrite, old, head, &md->prev);
767}
768
759static bool perf_mmap__empty(struct perf_mmap *md) 769static bool perf_mmap__empty(struct perf_mmap *md)
760{ 770{
761 return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base; 771 return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 0f33d7e698c4..cfab531437c7 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -295,7 +295,7 @@ static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
295 root_in = &he->parent_he->hroot_in; 295 root_in = &he->parent_he->hroot_in;
296 root_out = &he->parent_he->hroot_out; 296 root_out = &he->parent_he->hroot_out;
297 } else { 297 } else {
298 if (sort__need_collapse) 298 if (hists__has(hists, need_collapse))
299 root_in = &hists->entries_collapsed; 299 root_in = &hists->entries_collapsed;
300 else 300 else
301 root_in = hists->entries_in; 301 root_in = hists->entries_in;
@@ -1373,7 +1373,7 @@ int hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1373 struct hist_entry *n; 1373 struct hist_entry *n;
1374 int ret; 1374 int ret;
1375 1375
1376 if (!sort__need_collapse) 1376 if (!hists__has(hists, need_collapse))
1377 return 0; 1377 return 0;
1378 1378
1379 hists->nr_entries = 0; 1379 hists->nr_entries = 0;
@@ -1632,7 +1632,7 @@ static void output_resort(struct hists *hists, struct ui_progress *prog,
1632 return; 1632 return;
1633 } 1633 }
1634 1634
1635 if (sort__need_collapse) 1635 if (hists__has(hists, need_collapse))
1636 root = &hists->entries_collapsed; 1636 root = &hists->entries_collapsed;
1637 else 1637 else
1638 root = hists->entries_in; 1638 root = hists->entries_in;
@@ -2036,7 +2036,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
2036 struct hist_entry *he; 2036 struct hist_entry *he;
2037 int64_t cmp; 2037 int64_t cmp;
2038 2038
2039 if (sort__need_collapse) 2039 if (hists__has(hists, need_collapse))
2040 root = &hists->entries_collapsed; 2040 root = &hists->entries_collapsed;
2041 else 2041 else
2042 root = hists->entries_in; 2042 root = hists->entries_in;
@@ -2078,7 +2078,7 @@ static struct hist_entry *hists__find_entry(struct hists *hists,
2078{ 2078{
2079 struct rb_node *n; 2079 struct rb_node *n;
2080 2080
2081 if (sort__need_collapse) 2081 if (hists__has(hists, need_collapse))
2082 n = hists->entries_collapsed.rb_node; 2082 n = hists->entries_collapsed.rb_node;
2083 else 2083 else
2084 n = hists->entries_in->rb_node; 2084 n = hists->entries_in->rb_node;
@@ -2107,7 +2107,7 @@ void hists__match(struct hists *leader, struct hists *other)
2107 struct rb_node *nd; 2107 struct rb_node *nd;
2108 struct hist_entry *pos, *pair; 2108 struct hist_entry *pos, *pair;
2109 2109
2110 if (sort__need_collapse) 2110 if (hists__has(leader, need_collapse))
2111 root = &leader->entries_collapsed; 2111 root = &leader->entries_collapsed;
2112 else 2112 else
2113 root = leader->entries_in; 2113 root = leader->entries_in;
@@ -2132,7 +2132,7 @@ int hists__link(struct hists *leader, struct hists *other)
2132 struct rb_node *nd; 2132 struct rb_node *nd;
2133 struct hist_entry *pos, *pair; 2133 struct hist_entry *pos, *pair;
2134 2134
2135 if (sort__need_collapse) 2135 if (hists__has(other, need_collapse))
2136 root = &other->entries_collapsed; 2136 root = &other->entries_collapsed;
2137 else 2137 else
2138 root = other->entries_in; 2138 root = other->entries_in;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 588596561cb3..0f84bfb42bb1 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -82,6 +82,8 @@ struct hists {
82 int nr_hpp_node; 82 int nr_hpp_node;
83}; 83};
84 84
85#define hists__has(__h, __f) (__h)->hpp_list->__f
86
85struct hist_entry_iter; 87struct hist_entry_iter;
86 88
87struct hist_iter_ops { 89struct hist_iter_ops {
@@ -238,6 +240,14 @@ struct perf_hpp_fmt {
238struct perf_hpp_list { 240struct perf_hpp_list {
239 struct list_head fields; 241 struct list_head fields;
240 struct list_head sorts; 242 struct list_head sorts;
243
244 int need_collapse;
245 int parent;
246 int sym;
247 int dso;
248 int socket;
249 int thread;
250 int comm;
241}; 251};
242 252
243extern struct perf_hpp_list perf_hpp_list; 253extern struct perf_hpp_list perf_hpp_list;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 2cb95bbf9ea6..8c7bf4dbd479 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -32,6 +32,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
32 32
33 machine->threads = RB_ROOT; 33 machine->threads = RB_ROOT;
34 pthread_rwlock_init(&machine->threads_lock, NULL); 34 pthread_rwlock_init(&machine->threads_lock, NULL);
35 machine->nr_threads = 0;
35 INIT_LIST_HEAD(&machine->dead_threads); 36 INIT_LIST_HEAD(&machine->dead_threads);
36 machine->last_match = NULL; 37 machine->last_match = NULL;
37 38
@@ -430,6 +431,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
430 */ 431 */
431 thread__get(th); 432 thread__get(th);
432 machine->last_match = th; 433 machine->last_match = th;
434 ++machine->nr_threads;
433 } 435 }
434 436
435 return th; 437 return th;
@@ -681,11 +683,13 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
681 683
682size_t machine__fprintf(struct machine *machine, FILE *fp) 684size_t machine__fprintf(struct machine *machine, FILE *fp)
683{ 685{
684 size_t ret = 0; 686 size_t ret;
685 struct rb_node *nd; 687 struct rb_node *nd;
686 688
687 pthread_rwlock_rdlock(&machine->threads_lock); 689 pthread_rwlock_rdlock(&machine->threads_lock);
688 690
691 ret = fprintf(fp, "Threads: %u\n", machine->nr_threads);
692
689 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { 693 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
690 struct thread *pos = rb_entry(nd, struct thread, rb_node); 694 struct thread *pos = rb_entry(nd, struct thread, rb_node);
691 695
@@ -1419,6 +1423,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th,
1419 pthread_rwlock_wrlock(&machine->threads_lock); 1423 pthread_rwlock_wrlock(&machine->threads_lock);
1420 rb_erase_init(&th->rb_node, &machine->threads); 1424 rb_erase_init(&th->rb_node, &machine->threads);
1421 RB_CLEAR_NODE(&th->rb_node); 1425 RB_CLEAR_NODE(&th->rb_node);
1426 --machine->nr_threads;
1422 /* 1427 /*
1423 * Move it first to the dead_threads list, then drop the reference, 1428 * Move it first to the dead_threads list, then drop the reference,
1424 * if this is the last reference, then the thread__delete destructor 1429 * if this is the last reference, then the thread__delete destructor
@@ -1647,7 +1652,7 @@ static int add_callchain_ip(struct thread *thread,
1647 } 1652 }
1648 1653
1649 if (al.sym != NULL) { 1654 if (al.sym != NULL) {
1650 if (sort__has_parent && !*parent && 1655 if (perf_hpp_list.parent && !*parent &&
1651 symbol__match_regex(al.sym, &parent_regex)) 1656 symbol__match_regex(al.sym, &parent_regex))
1652 *parent = al.sym; 1657 *parent = al.sym;
1653 else if (have_ignore_callees && root_al && 1658 else if (have_ignore_callees && root_al &&
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 4822de5e4544..83f46790c52f 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -31,6 +31,7 @@ struct machine {
31 char *root_dir; 31 char *root_dir;
32 struct rb_root threads; 32 struct rb_root threads;
33 pthread_rwlock_t threads_lock; 33 pthread_rwlock_t threads_lock;
34 unsigned int nr_threads;
34 struct list_head dead_threads; 35 struct list_head dead_threads;
35 struct thread *last_match; 36 struct thread *last_match;
36 struct vdso_info *vdso_info; 37 struct vdso_info *vdso_info;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 85d82f4dc5e9..c82c625395ab 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2477,7 +2477,8 @@ static int find_probe_functions(struct map *map, char *name,
2477 2477
2478void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, 2478void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused,
2479 struct probe_trace_event *tev __maybe_unused, 2479 struct probe_trace_event *tev __maybe_unused,
2480 struct map *map __maybe_unused) { } 2480 struct map *map __maybe_unused,
2481 struct symbol *sym __maybe_unused) { }
2481 2482
2482/* 2483/*
2483 * Find probe function addresses from map. 2484 * Find probe function addresses from map.
@@ -2614,7 +2615,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2614 strdup_or_goto(pev->args[i].type, 2615 strdup_or_goto(pev->args[i].type,
2615 nomem_out); 2616 nomem_out);
2616 } 2617 }
2617 arch__fix_tev_from_maps(pev, tev, map); 2618 arch__fix_tev_from_maps(pev, tev, map, sym);
2618 } 2619 }
2619 if (ret == skipped) { 2620 if (ret == skipped) {
2620 ret = -ENOENT; 2621 ret = -ENOENT;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index e2209623f981..5a27eb4fad05 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -154,7 +154,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
154int show_available_funcs(const char *module, struct strfilter *filter, bool user); 154int show_available_funcs(const char *module, struct strfilter *filter, bool user);
155bool arch__prefers_symtab(void); 155bool arch__prefers_symtab(void);
156void arch__fix_tev_from_maps(struct perf_probe_event *pev, 156void arch__fix_tev_from_maps(struct perf_probe_event *pev,
157 struct probe_trace_event *tev, struct map *map); 157 struct probe_trace_event *tev, struct map *map,
158 struct symbol *sym);
158 159
159/* If there is no space to write, returns -E2BIG. */ 160/* If there is no space to write, returns -E2BIG. */
160int e_snprintf(char *str, size_t size, const char *format, ...) 161int e_snprintf(char *str, size_t size, const char *format, ...)
diff --git a/tools/perf/util/rb_resort.h b/tools/perf/util/rb_resort.h
new file mode 100644
index 000000000000..abc76e3d3098
--- /dev/null
+++ b/tools/perf/util/rb_resort.h
@@ -0,0 +1,149 @@
1#ifndef _PERF_RESORT_RB_H_
2#define _PERF_RESORT_RB_H_
3/*
4 * Template for creating a class to resort an existing rb_tree according to
5 * a new sort criteria, that must be present in the entries of the source
6 * rb_tree.
7 *
8 * (c) 2016 Arnaldo Carvalho de Melo <acme@redhat.com>
9 *
10 * Quick example, resorting threads by its shortname:
11 *
12 * First define the prefix (threads) to be used for the functions and data
13 * structures created, and provide an expression for the sorting, then the
14 * fields to be present in each of the entries in the new, sorted, rb_tree.
15 *
16 * The body of the init function should collect the fields, maybe
17 * pre-calculating them from multiple entries in the original 'entry' from
18 * the rb_tree used as a source for the entries to be sorted:
19
20DEFINE_RB_RESORT_RB(threads, strcmp(a->thread->shortname,
21 b->thread->shortname) < 0,
22 struct thread *thread;
23)
24{
25 entry->thread = rb_entry(nd, struct thread, rb_node);
26}
27
28 * After this it is just a matter of instantiating it and iterating it,
29 * for a few data structures with existing rb_trees, such as 'struct machine',
30 * helpers are available to get the rb_root and the nr_entries:
31
32 DECLARE_RESORT_RB_MACHINE_THREADS(threads, machine_ptr);
33
34 * This will instantiate the new rb_tree and a cursor for it, that can be used as:
35
36 struct rb_node *nd;
37
38 resort_rb__for_each(nd, threads) {
39 struct thread *t = threads_entry;
40 printf("%s: %d\n", t->shortname, t->tid);
41 }
42
43 * Then delete it:
44
45 resort_rb__delete(threads);
46
47 * The name of the data structures and functions will have a _sorted suffix
48 * right before the method names, i.e. will look like:
49 *
50 * struct threads_sorted_entry {}
51 * threads_sorted__insert()
52 */
53
54#define DEFINE_RESORT_RB(__name, __comp, ...) \
55struct __name##_sorted_entry { \
56 struct rb_node rb_node; \
57 __VA_ARGS__ \
58}; \
59static void __name##_sorted__init_entry(struct rb_node *nd, \
60 struct __name##_sorted_entry *entry); \
61 \
62static int __name##_sorted__cmp(struct rb_node *nda, struct rb_node *ndb) \
63{ \
64 struct __name##_sorted_entry *a, *b; \
65 a = rb_entry(nda, struct __name##_sorted_entry, rb_node); \
66 b = rb_entry(ndb, struct __name##_sorted_entry, rb_node); \
67 return __comp; \
68} \
69 \
70struct __name##_sorted { \
71 struct rb_root entries; \
72 struct __name##_sorted_entry nd[0]; \
73}; \
74 \
75static void __name##_sorted__insert(struct __name##_sorted *sorted, \
76 struct rb_node *sorted_nd) \
77{ \
78 struct rb_node **p = &sorted->entries.rb_node, *parent = NULL; \
79 while (*p != NULL) { \
80 parent = *p; \
81 if (__name##_sorted__cmp(sorted_nd, parent)) \
82 p = &(*p)->rb_left; \
83 else \
84 p = &(*p)->rb_right; \
85 } \
86 rb_link_node(sorted_nd, parent, p); \
87 rb_insert_color(sorted_nd, &sorted->entries); \
88} \
89 \
90static void __name##_sorted__sort(struct __name##_sorted *sorted, \
91 struct rb_root *entries) \
92{ \
93 struct rb_node *nd; \
94 unsigned int i = 0; \
95 for (nd = rb_first(entries); nd; nd = rb_next(nd)) { \
96 struct __name##_sorted_entry *snd = &sorted->nd[i++]; \
97 __name##_sorted__init_entry(nd, snd); \
98 __name##_sorted__insert(sorted, &snd->rb_node); \
99 } \
100} \
101 \
102static struct __name##_sorted *__name##_sorted__new(struct rb_root *entries, \
103 int nr_entries) \
104{ \
105 struct __name##_sorted *sorted; \
106 sorted = malloc(sizeof(*sorted) + sizeof(sorted->nd[0]) * nr_entries); \
107 if (sorted) { \
108 sorted->entries = RB_ROOT; \
109 __name##_sorted__sort(sorted, entries); \
110 } \
111 return sorted; \
112} \
113 \
114static void __name##_sorted__delete(struct __name##_sorted *sorted) \
115{ \
116 free(sorted); \
117} \
118 \
119static void __name##_sorted__init_entry(struct rb_node *nd, \
120 struct __name##_sorted_entry *entry)
121
122#define DECLARE_RESORT_RB(__name) \
123struct __name##_sorted_entry *__name##_entry; \
124struct __name##_sorted *__name = __name##_sorted__new
125
126#define resort_rb__for_each(__nd, __name) \
127 for (__nd = rb_first(&__name->entries); \
128 __name##_entry = rb_entry(__nd, struct __name##_sorted_entry, \
129 rb_node), __nd; \
130 __nd = rb_next(__nd))
131
132#define resort_rb__delete(__name) \
133 __name##_sorted__delete(__name), __name = NULL
134
135/*
136 * Helpers for other classes that contains both an rbtree and the
137 * number of entries in it:
138 */
139
140/* For 'struct intlist' */
141#define DECLARE_RESORT_RB_INTLIST(__name, __ilist) \
142 DECLARE_RESORT_RB(__name)(&__ilist->rblist.entries, \
143 __ilist->rblist.nr_entries)
144
145/* For 'struct machine->threads' */
146#define DECLARE_RESORT_RB_MACHINE_THREADS(__name, __machine) \
147 DECLARE_RESORT_RB(__name)(&__machine->threads, __machine->nr_threads)
148
149#endif /* _PERF_RESORT_RB_H_ */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 47966a1618c7..772e2e461ec3 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -21,13 +21,6 @@ const char *sort_order;
21const char *field_order; 21const char *field_order;
22regex_t ignore_callees_regex; 22regex_t ignore_callees_regex;
23int have_ignore_callees = 0; 23int have_ignore_callees = 0;
24int sort__need_collapse = 0;
25int sort__has_parent = 0;
26int sort__has_sym = 0;
27int sort__has_dso = 0;
28int sort__has_socket = 0;
29int sort__has_thread = 0;
30int sort__has_comm = 0;
31enum sort_mode sort__mode = SORT_MODE__NORMAL; 24enum sort_mode sort__mode = SORT_MODE__NORMAL;
32 25
33/* 26/*
@@ -244,7 +237,7 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
244 * comparing symbol address alone is not enough since it's a 237 * comparing symbol address alone is not enough since it's a
245 * relative address within a dso. 238 * relative address within a dso.
246 */ 239 */
247 if (!sort__has_dso) { 240 if (!hists__has(left->hists, dso) || hists__has(right->hists, dso)) {
248 ret = sort__dso_cmp(left, right); 241 ret = sort__dso_cmp(left, right);
249 if (ret != 0) 242 if (ret != 0)
250 return ret; 243 return ret;
@@ -2163,7 +2156,7 @@ static int __sort_dimension__add(struct sort_dimension *sd,
2163 return -1; 2156 return -1;
2164 2157
2165 if (sd->entry->se_collapse) 2158 if (sd->entry->se_collapse)
2166 sort__need_collapse = 1; 2159 list->need_collapse = 1;
2167 2160
2168 sd->taken = 1; 2161 sd->taken = 1;
2169 2162
@@ -2245,9 +2238,9 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
2245 pr_err("Invalid regex: %s\n%s", parent_pattern, err); 2238 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
2246 return -EINVAL; 2239 return -EINVAL;
2247 } 2240 }
2248 sort__has_parent = 1; 2241 list->parent = 1;
2249 } else if (sd->entry == &sort_sym) { 2242 } else if (sd->entry == &sort_sym) {
2250 sort__has_sym = 1; 2243 list->sym = 1;
2251 /* 2244 /*
2252 * perf diff displays the performance difference amongst 2245 * perf diff displays the performance difference amongst
2253 * two or more perf.data files. Those files could come 2246 * two or more perf.data files. Those files could come
@@ -2258,13 +2251,13 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
2258 sd->entry->se_collapse = sort__sym_sort; 2251 sd->entry->se_collapse = sort__sym_sort;
2259 2252
2260 } else if (sd->entry == &sort_dso) { 2253 } else if (sd->entry == &sort_dso) {
2261 sort__has_dso = 1; 2254 list->dso = 1;
2262 } else if (sd->entry == &sort_socket) { 2255 } else if (sd->entry == &sort_socket) {
2263 sort__has_socket = 1; 2256 list->socket = 1;
2264 } else if (sd->entry == &sort_thread) { 2257 } else if (sd->entry == &sort_thread) {
2265 sort__has_thread = 1; 2258 list->thread = 1;
2266 } else if (sd->entry == &sort_comm) { 2259 } else if (sd->entry == &sort_comm) {
2267 sort__has_comm = 1; 2260 list->comm = 1;
2268 } 2261 }
2269 2262
2270 return __sort_dimension__add(sd, list, level); 2263 return __sort_dimension__add(sd, list, level);
@@ -2289,7 +2282,7 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
2289 return -EINVAL; 2282 return -EINVAL;
2290 2283
2291 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 2284 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2292 sort__has_sym = 1; 2285 list->sym = 1;
2293 2286
2294 __sort_dimension__add(sd, list, level); 2287 __sort_dimension__add(sd, list, level);
2295 return 0; 2288 return 0;
@@ -2305,7 +2298,7 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
2305 return -EINVAL; 2298 return -EINVAL;
2306 2299
2307 if (sd->entry == &sort_mem_daddr_sym) 2300 if (sd->entry == &sort_mem_daddr_sym)
2308 sort__has_sym = 1; 2301 list->sym = 1;
2309 2302
2310 __sort_dimension__add(sd, list, level); 2303 __sort_dimension__add(sd, list, level);
2311 return 0; 2304 return 0;
@@ -2746,10 +2739,10 @@ int setup_sorting(struct perf_evlist *evlist)
2746 2739
2747void reset_output_field(void) 2740void reset_output_field(void)
2748{ 2741{
2749 sort__need_collapse = 0; 2742 perf_hpp_list.need_collapse = 0;
2750 sort__has_parent = 0; 2743 perf_hpp_list.parent = 0;
2751 sort__has_sym = 0; 2744 perf_hpp_list.sym = 0;
2752 sort__has_dso = 0; 2745 perf_hpp_list.dso = 0;
2753 2746
2754 field_order = NULL; 2747 field_order = NULL;
2755 sort_order = NULL; 2748 sort_order = NULL;
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 3f4e35998119..42927f448bcb 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -31,13 +31,6 @@ extern const char *parent_pattern;
31extern const char default_sort_order[]; 31extern const char default_sort_order[];
32extern regex_t ignore_callees_regex; 32extern regex_t ignore_callees_regex;
33extern int have_ignore_callees; 33extern int have_ignore_callees;
34extern int sort__need_collapse;
35extern int sort__has_dso;
36extern int sort__has_parent;
37extern int sort__has_sym;
38extern int sort__has_socket;
39extern int sort__has_thread;
40extern int sort__has_comm;
41extern enum sort_mode sort__mode; 34extern enum sort_mode sort__mode;
42extern struct sort_entry sort_comm; 35extern struct sort_entry sort_comm;
43extern struct sort_entry sort_dso; 36extern struct sort_entry sort_dso;
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 3f9d6798bd18..87a297dd8901 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -770,7 +770,8 @@ static bool want_demangle(bool is_kernel_sym)
770 return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; 770 return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
771} 771}
772 772
773void __weak arch__elf_sym_adjust(GElf_Sym *sym __maybe_unused) { } 773void __weak arch__sym_update(struct symbol *s __maybe_unused,
774 GElf_Sym *sym __maybe_unused) { }
774 775
775int dso__load_sym(struct dso *dso, struct map *map, 776int dso__load_sym(struct dso *dso, struct map *map,
776 struct symsrc *syms_ss, struct symsrc *runtime_ss, 777 struct symsrc *syms_ss, struct symsrc *runtime_ss,
@@ -947,8 +948,6 @@ int dso__load_sym(struct dso *dso, struct map *map,
947 (sym.st_value & 1)) 948 (sym.st_value & 1))
948 --sym.st_value; 949 --sym.st_value;
949 950
950 arch__elf_sym_adjust(&sym);
951
952 if (dso->kernel || kmodule) { 951 if (dso->kernel || kmodule) {
953 char dso_name[PATH_MAX]; 952 char dso_name[PATH_MAX];
954 953
@@ -1082,6 +1081,8 @@ new_symbol:
1082 if (!f) 1081 if (!f)
1083 goto out_elf_end; 1082 goto out_elf_end;
1084 1083
1084 arch__sym_update(f, &sym);
1085
1085 if (filter && filter(curr_map, f)) 1086 if (filter && filter(curr_map, f))
1086 symbol__delete(f); 1087 symbol__delete(f);
1087 else { 1088 else {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index c8e43979ed5c..07211c2f8456 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -55,6 +55,7 @@ struct symbol {
55 u16 namelen; 55 u16 namelen;
56 u8 binding; 56 u8 binding;
57 bool ignore; 57 bool ignore;
58 u8 arch_sym;
58 char name[0]; 59 char name[0];
59}; 60};
60 61
@@ -323,7 +324,7 @@ int setup_intlist(struct intlist **list, const char *list_str,
323 324
324#ifdef HAVE_LIBELF_SUPPORT 325#ifdef HAVE_LIBELF_SUPPORT
325bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); 326bool elf__needs_adjust_symbols(GElf_Ehdr ehdr);
326void arch__elf_sym_adjust(GElf_Sym *sym); 327void arch__sym_update(struct symbol *s, GElf_Sym *sym);
327#endif 328#endif
328 329
329#define SYMBOL_A 0 330#define SYMBOL_A 0