diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-05-06 02:35:14 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-05-06 02:35:14 -0400 |
commit | c0edb7467c3d21b213ff734bfe810d81d2c6ed61 (patch) | |
tree | 731d887c8bae23eb0408dcfd2193bc2077f621ee /tools | |
parent | 1b6de5917172967acd8db4d222df4225d23a8a60 (diff) | |
parent | b6b85dad30ad7e7394990e2317a780577974a4e6 (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')
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 | |||
3 | endif | 3 | endif |
4 | 4 | ||
5 | HAVE_KVM_STAT_SUPPORT := 1 | 5 | HAVE_KVM_STAT_SUPPORT := 1 |
6 | PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 | ||
6 | PERF_HAVE_JITDUMP := 1 | 7 | PERF_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 | ||
16 | struct pt_regs_dwarfnum { | 20 | struct 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 | |||
97 | int 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 | ||
23 | void 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 | ||
63 | void 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 | ||
70 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, | 71 | void 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 | ||
920 | static int callchain_param__setup_sample_type(struct callchain_param *callchain) | 920 | static 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 | ||
2788 | DEFINE_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 | |||
2787 | static size_t thread__dump_stats(struct thread_trace *ttrace, | 2802 | static 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 */ | 2845 | static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace) |
2833 | struct summary_data { | ||
2834 | FILE *fp; | ||
2835 | struct trace *trace; | ||
2836 | size_t printed; | ||
2837 | }; | ||
2838 | |||
2839 | static 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 | |||
2873 | static unsigned long thread__nr_events(struct thread_trace *ttrace) | ||
2874 | { | ||
2875 | return ttrace ? ttrace->nr_events : 0; | ||
2876 | } | ||
2864 | 2877 | ||
2865 | return 0; | 2878 | DEFINE_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 | ||
2868 | static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) | 2885 | static 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 | ||
2881 | static int trace__set_duration(const struct option *opt, const char *str, | 2904 | static 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 | |||
2407 | add_dso_opt(struct hist_browser *browser, struct popup_action *act, | 2409 | add_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 | ||
2431 | static int | 2433 | static int |
2432 | add_map_opt(struct hist_browser *browser __maybe_unused, | 2434 | add_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, | |||
2534 | static int | 2536 | static int |
2535 | do_zoom_socket(struct hist_browser *browser, struct popup_action *act) | 2537 | do_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 | |||
2556 | add_socket_opt(struct hist_browser *browser, struct popup_action *act, | 2558 | add_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 | ||
1666 | bool ui__has_annotation(void) | 1666 | bool 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 | ||
682 | union 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 */ |
683 | static union perf_event * | ||
684 | perf_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 | ||
753 | broken_event: | 745 | broken_event: |
754 | md->prev = old; | 746 | if (prev) |
747 | *prev = start; | ||
755 | 748 | ||
756 | return event; | 749 | return event; |
757 | } | 750 | } |
758 | 751 | ||
752 | union 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 | |||
759 | static bool perf_mmap__empty(struct perf_mmap *md) | 769 | static 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 | |||
85 | struct hist_entry_iter; | 87 | struct hist_entry_iter; |
86 | 88 | ||
87 | struct hist_iter_ops { | 89 | struct hist_iter_ops { |
@@ -238,6 +240,14 @@ struct perf_hpp_fmt { | |||
238 | struct perf_hpp_list { | 240 | struct 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 | ||
243 | extern struct perf_hpp_list perf_hpp_list; | 253 | extern 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 | ||
682 | size_t machine__fprintf(struct machine *machine, FILE *fp) | 684 | size_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 | ||
2478 | void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, | 2478 | void __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, | |||
154 | int show_available_funcs(const char *module, struct strfilter *filter, bool user); | 154 | int show_available_funcs(const char *module, struct strfilter *filter, bool user); |
155 | bool arch__prefers_symtab(void); | 155 | bool arch__prefers_symtab(void); |
156 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, | 156 | void 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. */ |
160 | int e_snprintf(char *str, size_t size, const char *format, ...) | 161 | int 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 | |||
20 | DEFINE_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, ...) \ | ||
55 | struct __name##_sorted_entry { \ | ||
56 | struct rb_node rb_node; \ | ||
57 | __VA_ARGS__ \ | ||
58 | }; \ | ||
59 | static void __name##_sorted__init_entry(struct rb_node *nd, \ | ||
60 | struct __name##_sorted_entry *entry); \ | ||
61 | \ | ||
62 | static 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 | \ | ||
70 | struct __name##_sorted { \ | ||
71 | struct rb_root entries; \ | ||
72 | struct __name##_sorted_entry nd[0]; \ | ||
73 | }; \ | ||
74 | \ | ||
75 | static 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 | \ | ||
90 | static 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 | \ | ||
102 | static 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 | \ | ||
114 | static void __name##_sorted__delete(struct __name##_sorted *sorted) \ | ||
115 | { \ | ||
116 | free(sorted); \ | ||
117 | } \ | ||
118 | \ | ||
119 | static void __name##_sorted__init_entry(struct rb_node *nd, \ | ||
120 | struct __name##_sorted_entry *entry) | ||
121 | |||
122 | #define DECLARE_RESORT_RB(__name) \ | ||
123 | struct __name##_sorted_entry *__name##_entry; \ | ||
124 | struct __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; | |||
21 | const char *field_order; | 21 | const char *field_order; |
22 | regex_t ignore_callees_regex; | 22 | regex_t ignore_callees_regex; |
23 | int have_ignore_callees = 0; | 23 | int have_ignore_callees = 0; |
24 | int sort__need_collapse = 0; | ||
25 | int sort__has_parent = 0; | ||
26 | int sort__has_sym = 0; | ||
27 | int sort__has_dso = 0; | ||
28 | int sort__has_socket = 0; | ||
29 | int sort__has_thread = 0; | ||
30 | int sort__has_comm = 0; | ||
31 | enum sort_mode sort__mode = SORT_MODE__NORMAL; | 24 | enum 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 | ||
2747 | void reset_output_field(void) | 2740 | void 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; | |||
31 | extern const char default_sort_order[]; | 31 | extern const char default_sort_order[]; |
32 | extern regex_t ignore_callees_regex; | 32 | extern regex_t ignore_callees_regex; |
33 | extern int have_ignore_callees; | 33 | extern int have_ignore_callees; |
34 | extern int sort__need_collapse; | ||
35 | extern int sort__has_dso; | ||
36 | extern int sort__has_parent; | ||
37 | extern int sort__has_sym; | ||
38 | extern int sort__has_socket; | ||
39 | extern int sort__has_thread; | ||
40 | extern int sort__has_comm; | ||
41 | extern enum sort_mode sort__mode; | 34 | extern enum sort_mode sort__mode; |
42 | extern struct sort_entry sort_comm; | 35 | extern struct sort_entry sort_comm; |
43 | extern struct sort_entry sort_dso; | 36 | extern 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 | ||
773 | void __weak arch__elf_sym_adjust(GElf_Sym *sym __maybe_unused) { } | 773 | void __weak arch__sym_update(struct symbol *s __maybe_unused, |
774 | GElf_Sym *sym __maybe_unused) { } | ||
774 | 775 | ||
775 | int dso__load_sym(struct dso *dso, struct map *map, | 776 | int 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 |
325 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); | 326 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); |
326 | void arch__elf_sym_adjust(GElf_Sym *sym); | 327 | void 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 |