Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf annotate: Use a hashmap to save type data

It can slowdown annotation browser if objdump is processing large DWARF
data. Let's add a hashmap to save the data type info for each line.

Note that this is needed for TUI only because stdio only processes each
line once. TUI will display the same line whenever it refreshes the
screen.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20250816031635.25318-13-namhyung@kernel.org
[ Add lines around an if block and use zfree() in one case, acked by Namhyung ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
1086237f 53a61a6c

+62 -3
+33 -1
tools/perf/ui/browsers/annotate.c
··· 6 6 #include "../../util/debug.h" 7 7 #include "../../util/debuginfo.h" 8 8 #include "../../util/dso.h" 9 + #include "../../util/hashmap.h" 9 10 #include "../../util/hist.h" 10 11 #include "../../util/sort.h" 11 12 #include "../../util/map.h" ··· 16 15 #include "../../util/evlist.h" 17 16 #include "../../util/thread.h" 18 17 #include <inttypes.h> 18 + #include <linux/err.h> 19 19 #include <linux/kernel.h> 20 20 #include <linux/string.h> 21 21 #include <linux/zalloc.h> ··· 38 36 struct hist_entry *he; 39 37 struct debuginfo *dbg; 40 38 struct evsel *evsel; 39 + struct hashmap *type_hash; 41 40 bool searching_backwards; 42 41 char search_bf[128]; 43 42 }; 44 43 45 44 /* A copy of target hist_entry for perf top. */ 46 45 static struct hist_entry annotate_he; 46 + 47 + static size_t type_hash(long key, void *ctx __maybe_unused) 48 + { 49 + return key; 50 + } 51 + 52 + static bool type_equal(long key1, long key2, void *ctx __maybe_unused) 53 + { 54 + return key1 == key2; 55 + } 47 56 48 57 static inline struct annotation *browser__annotation(struct ui_browser *browser) 49 58 { ··· 142 129 /* The scroll bar isn't being used */ 143 130 if (!browser->navkeypressed) 144 131 ops.width += 1; 132 + 133 + if (!IS_ERR_OR_NULL(ab->type_hash)) 134 + apd.type_hash = ab->type_hash; 145 135 146 136 annotation_line__write(al, notes, &ops, &apd); 147 137 ··· 1067 1051 annotate_opts.code_with_type ^= 1; 1068 1052 if (browser->dbg == NULL) 1069 1053 browser->dbg = dso__debuginfo(map__dso(ms->map)); 1054 + if (browser->type_hash == NULL) { 1055 + browser->type_hash = hashmap__new(type_hash, type_equal, 1056 + /*ctx=*/NULL); 1057 + } 1070 1058 annotate_browser__show(&browser->b, title, help); 1071 1059 annotate_browser__debuginfo_warning(browser); 1072 1060 continue; ··· 1165 1145 1166 1146 ui_helpline__push("Press ESC to exit"); 1167 1147 1168 - if (annotate_opts.code_with_type) 1148 + if (annotate_opts.code_with_type) { 1169 1149 browser.dbg = dso__debuginfo(dso); 1150 + browser.type_hash = hashmap__new(type_hash, type_equal, /*ctx=*/NULL); 1151 + } 1170 1152 1171 1153 browser.b.width = notes->src->widths.max_line_len; 1172 1154 browser.b.nr_entries = notes->src->nr_entries; ··· 1181 1159 ret = annotate_browser__run(&browser, evsel, hbt); 1182 1160 1183 1161 debuginfo__delete(browser.dbg); 1162 + 1163 + if (!IS_ERR_OR_NULL(browser.type_hash)) { 1164 + struct hashmap_entry *cur; 1165 + size_t bkt; 1166 + 1167 + hashmap__for_each_entry(browser.type_hash, cur, bkt) 1168 + zfree(&cur->pvalue); 1169 + hashmap__free(browser.type_hash); 1170 + } 1171 + 1184 1172 if (not_annotated && !notes->src->tried_source) 1185 1173 annotated_source__purge(notes->src); 1186 1174
+27 -2
tools/perf/util/annotate.c
··· 1954 1954 return -ENOMEM; 1955 1955 } 1956 1956 1957 + struct type_hash_entry { 1958 + struct annotated_data_type *type; 1959 + int offset; 1960 + }; 1961 + 1957 1962 static int disasm_line__snprint_type_info(struct disasm_line *dl, 1958 1963 char *buf, int len, 1959 1964 struct annotation_print_data *apd) 1960 1965 { 1961 - struct annotated_data_type *data_type; 1966 + struct annotated_data_type *data_type = NULL; 1967 + struct type_hash_entry *entry = NULL; 1962 1968 char member[256]; 1963 1969 int offset = 0; 1964 1970 int printed; ··· 1974 1968 if (!annotate_opts.code_with_type || apd->dbg == NULL) 1975 1969 return 1; 1976 1970 1977 - data_type = __hist_entry__get_data_type(apd->he, apd->arch, apd->dbg, dl, &offset); 1971 + if (apd->type_hash) { 1972 + hashmap__find(apd->type_hash, dl->al.offset, &entry); 1973 + if (entry != NULL) { 1974 + data_type = entry->type; 1975 + offset = entry->offset; 1976 + } 1977 + } 1978 + 1979 + if (data_type == NULL) 1980 + data_type = __hist_entry__get_data_type(apd->he, apd->arch, apd->dbg, dl, &offset); 1981 + 1982 + if (apd->type_hash && entry == NULL) { 1983 + entry = malloc(sizeof(*entry)); 1984 + if (entry != NULL) { 1985 + entry->type = data_type; 1986 + entry->offset = offset; 1987 + hashmap__add(apd->type_hash, dl->al.offset, entry); 1988 + } 1989 + } 1990 + 1978 1991 if (!needs_type_info(data_type)) 1979 1992 return 1; 1980 1993
+2
tools/perf/util/annotate.h
··· 204 204 struct evsel *evsel; 205 205 struct arch *arch; 206 206 struct debuginfo *dbg; 207 + /* save data type info keyed by al->offset */ 208 + struct hashmap *type_hash; 207 209 /* It'll be set in hist_entry__annotate_printf() */ 208 210 int addr_fmt_width; 209 211 };