diff options
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 |