]> www.infradead.org Git - users/hch/misc.git/commitdiff
perf annotate: Use a hashmap to save type data
authorNamhyung Kim <namhyung@kernel.org>
Sat, 16 Aug 2025 03:16:35 +0000 (20:16 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 2 Sep 2025 20:14:00 +0000 (17:14 -0300)
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>
tools/perf/ui/browsers/annotate.c
tools/perf/util/annotate.c
tools/perf/util/annotate.h

index 9aa3c1ba22f52789d40319da8234171cd5f6fd93..b770a8d4623ef1fb526e42782088dc6ceb85d99c 100644 (file)
@@ -6,6 +6,7 @@
 #include "../../util/debug.h"
 #include "../../util/debuginfo.h"
 #include "../../util/dso.h"
+#include "../../util/hashmap.h"
 #include "../../util/hist.h"
 #include "../../util/sort.h"
 #include "../../util/map.h"
@@ -15,6 +16,7 @@
 #include "../../util/evlist.h"
 #include "../../util/thread.h"
 #include <inttypes.h>
+#include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/zalloc.h>
@@ -36,6 +38,7 @@ struct annotate_browser {
        struct hist_entry          *he;
        struct debuginfo           *dbg;
        struct evsel               *evsel;
+       struct hashmap             *type_hash;
        bool                        searching_backwards;
        char                        search_bf[128];
 };
@@ -43,6 +46,16 @@ struct annotate_browser {
 /* A copy of target hist_entry for perf top. */
 static struct hist_entry annotate_he;
 
+static size_t type_hash(long key, void *ctx __maybe_unused)
+{
+       return key;
+}
+
+static bool type_equal(long key1, long key2, void *ctx __maybe_unused)
+{
+       return key1 == key2;
+}
+
 static inline struct annotation *browser__annotation(struct ui_browser *browser)
 {
        struct map_symbol *ms = browser->priv;
@@ -130,6 +143,9 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
        if (!browser->navkeypressed)
                ops.width += 1;
 
+       if (!IS_ERR_OR_NULL(ab->type_hash))
+               apd.type_hash = ab->type_hash;
+
        annotation_line__write(al, notes, &ops, &apd);
 
        if (ops.current_entry)
@@ -1051,6 +1067,10 @@ show_sup_ins:
                        annotate_opts.code_with_type ^= 1;
                        if (browser->dbg == NULL)
                                browser->dbg = dso__debuginfo(map__dso(ms->map));
+                       if (browser->type_hash == NULL) {
+                               browser->type_hash = hashmap__new(type_hash, type_equal,
+                                                                 /*ctx=*/NULL);
+                       }
                        annotate_browser__show(&browser->b, title, help);
                        annotate_browser__debuginfo_warning(browser);
                        continue;
@@ -1145,8 +1165,10 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms,
 
        ui_helpline__push("Press ESC to exit");
 
-       if (annotate_opts.code_with_type)
+       if (annotate_opts.code_with_type) {
                browser.dbg = dso__debuginfo(dso);
+               browser.type_hash = hashmap__new(type_hash, type_equal, /*ctx=*/NULL);
+       }
 
        browser.b.width = notes->src->widths.max_line_len;
        browser.b.nr_entries = notes->src->nr_entries;
@@ -1159,6 +1181,16 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms,
        ret = annotate_browser__run(&browser, evsel, hbt);
 
        debuginfo__delete(browser.dbg);
+
+       if (!IS_ERR_OR_NULL(browser.type_hash)) {
+               struct hashmap_entry *cur;
+               size_t bkt;
+
+               hashmap__for_each_entry(browser.type_hash, cur, bkt)
+                       zfree(&cur->pvalue);
+               hashmap__free(browser.type_hash);
+       }
+
        if (not_annotated && !notes->src->tried_source)
                annotated_source__purge(notes->src);
 
index bea3457a00632fd7cfaf2c11f4ef695592f03b73..c9b220d9f924ec575e0b3aec2484b80d673e4024 100644 (file)
@@ -1954,11 +1954,17 @@ err:
        return -ENOMEM;
 }
 
+struct type_hash_entry {
+       struct annotated_data_type *type;
+       int offset;
+};
+
 static int disasm_line__snprint_type_info(struct disasm_line *dl,
                                          char *buf, int len,
                                          struct annotation_print_data *apd)
 {
-       struct annotated_data_type *data_type;
+       struct annotated_data_type *data_type = NULL;
+       struct type_hash_entry *entry = NULL;
        char member[256];
        int offset = 0;
        int printed;
@@ -1968,7 +1974,26 @@ static int disasm_line__snprint_type_info(struct disasm_line *dl,
        if (!annotate_opts.code_with_type || apd->dbg == NULL)
                return 1;
 
-       data_type = __hist_entry__get_data_type(apd->he, apd->arch, apd->dbg, dl, &offset);
+       if (apd->type_hash) {
+               hashmap__find(apd->type_hash, dl->al.offset, &entry);
+               if (entry != NULL) {
+                       data_type = entry->type;
+                       offset = entry->offset;
+               }
+       }
+
+       if (data_type == NULL)
+               data_type = __hist_entry__get_data_type(apd->he, apd->arch, apd->dbg, dl, &offset);
+
+       if (apd->type_hash && entry == NULL) {
+               entry = malloc(sizeof(*entry));
+               if (entry != NULL) {
+                       entry->type = data_type;
+                       entry->offset = offset;
+                       hashmap__add(apd->type_hash, dl->al.offset, entry);
+               }
+       }
+
        if (!needs_type_info(data_type))
                return 1;
 
index 86e858f5bf17315244be080fc5af0c8a41b88cb0..eaf6c8aa7f4739595c97715f8d9898b5b48e3b51 100644 (file)
@@ -204,6 +204,8 @@ struct annotation_print_data {
        struct evsel *evsel;
        struct arch *arch;
        struct debuginfo *dbg;
+       /* save data type info keyed by al->offset */
+       struct hashmap *type_hash;
        /* It'll be set in hist_entry__annotate_printf() */
        int addr_fmt_width;
 };