* [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking
@ 2026-09-28 7:52 Ian Rogers
2026-09-28 7:52 ` [PATCH v1 1/7] perf symbol: Add accessor functions for struct symbol fields Ian Rogers
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Ian Rogers @ 2026-09-28 7:52 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter, James Clark,
linux-perf-users, linux-kernel, Alireza Haghdoost
This series modernizes struct symbol memory management and backing storage in
tools/perf to support reference counting (DECLARE_RC_STRUCT(symbol)) and
periodic LRU memory shrinking during long or large profiling sessions:
1. Field accessors (Patch 1): Introduces inline getters/setters for
struct symbol fields across tools/perf in preparation for wrapping
struct symbol with DECLARE_RC_STRUCT(symbol).
2. Remove negative-offset private allocations (Patch 2): Replaces
symbol_conf.priv_size and symbol__priv() negative-offset allocations in
util/annotate.c and util/db-export.c with hashmaps keyed by symbol
pointer (struct annotated_symbol protected by an rw_semaphore, and
sym_db_ids on struct db_export).
3. Flat sorted array backing storage (Patch 3): Replaces the dual
address-sorted and name-sorted red-black trees (rb_node) in struct dso
with a struct symbols container backed by dynamically sorted flat arrays
protected by struct rw_semaphore (util/rwsem.h) with Clang thread-safety
annotations. Saves 48 bytes per struct symbol (two rb_nodes) and provides
cache-friendly binary search (bsearch) and callback-based iteration.
4. Reference counting and DECLARE_RC_STRUCT(symbol) (Patch 4): Wraps
struct symbol with DECLARE_RC_STRUCT(symbol) and adds refcount_t refcnt
along with symbol__get(), symbol__put(), and symbol__zput(). Lookup
functions return a counted reference acquired under symbols->lock, and
lifetime holders (addr_location, map_symbol, hist_entry, call_path,
block_info, disasm_line, thread_stack, db_export, etc.) properly
manage symbol references.
5. LRU memory shrinking (Patch 5): Adds an accessed bit to struct dso
and implements symbols__shrink(), dso__shrink_symbols(), dsos__shrink(),
machine__shrink(), and machines__shrink(). Unreferenced symbols (refcnt == 1)
in cold DSOs are reclaimed, and shrunken DSOs transparently reload on demand
via dso__load() while preserving live symbols and their RC_STRUCT(symbol)
identity.
6. Periodic session shrinking (Patch 6): Hooks machines__shrink() into
perf_session event processing so long-running sessions periodically reclaim
cold symbols and DSOs.
7. Unit tests (Patch 7): Adds unit tests in tools/perf/tests/symbols.c
covering symbol reference counting, symbols__shrink() retention of active
symbols, dsos__shrink() two-pass LRU clock behavior, and on-demand reload
preserving live symbol identity.
Ian Rogers (7):
perf symbol: Add accessor functions for struct symbol fields
perf symbol: Remove symbol_conf.priv_size and negative-offset
allocations
perf symbol: Switch backing storage from rbtree to struct symbols
array
perf symbol: Add reference counting and DECLARE_RC_STRUCT(symbol)
perf symbol: Add LRU memory shrinking for symbols, DSOs, and machines
perf session: Periodically shrink symbols and DSOs during event
processing
perf test symbols: Add tests for symbol and DSO LRU shrinking
.../arch/powerpc/util/skip-callchain-idx.c | 2 +-
tools/perf/arch/powerpc/util/sym-handling.c | 40 +-
tools/perf/builtin-annotate.c | 15 +-
tools/perf/builtin-c2c.c | 14 -
tools/perf/builtin-diff.c | 5 +-
tools/perf/builtin-kallsyms.c | 10 +-
tools/perf/builtin-kmem.c | 66 +-
tools/perf/builtin-kwork.c | 4 +-
tools/perf/builtin-lock.c | 27 +-
tools/perf/builtin-mem.c | 2 +-
tools/perf/builtin-report.c | 14 -
tools/perf/builtin-sched.c | 6 +-
tools/perf/builtin-script.c | 18 +-
tools/perf/builtin-timechart.c | 2 +-
tools/perf/builtin-top.c | 29 +-
tools/perf/builtin-trace.c | 12 +-
tools/perf/tests/builtin-test.c | 1 -
tools/perf/tests/dlfilter-test.c | 12 +-
tools/perf/tests/dwarf-unwind.c | 2 +-
tools/perf/tests/hists_common.c | 4 +-
tools/perf/tests/hists_cumulate.c | 8 +-
tools/perf/tests/hists_filter.c | 10 +-
tools/perf/tests/hists_link.c | 16 +-
tools/perf/tests/hists_output.c | 9 +-
tools/perf/tests/kallsyms-split.c | 5 +-
tools/perf/tests/pe-file-parsing.c | 1 +
tools/perf/tests/symbols.c | 289 +++++-
tools/perf/tests/vmlinux-kallsyms.c | 191 ++--
tools/perf/ui/browsers/annotate.c | 11 +-
tools/perf/ui/browsers/hists.c | 17 +-
tools/perf/ui/browsers/map.c | 87 +-
tools/perf/ui/gtk/annotate.c | 7 +-
tools/perf/ui/stdio/hist.c | 6 +-
tools/perf/util/addr_location.c | 4 +
.../perf/util/annotate-arch/annotate-alpha.c | 2 +-
.../util/annotate-arch/annotate-loongarch.c | 8 +-
tools/perf/util/annotate-arch/annotate-s390.c | 2 +-
tools/perf/util/annotate-arch/annotate-x86.c | 14 +-
tools/perf/util/annotate-data.c | 14 +-
tools/perf/util/annotate.c | 211 ++++-
tools/perf/util/annotate.h | 6 +-
tools/perf/util/auxtrace.c | 111 ++-
tools/perf/util/block-info.c | 13 +-
tools/perf/util/bpf_lock_contention.c | 39 +-
tools/perf/util/c2c-function.c | 25 +-
tools/perf/util/call-path.c | 15 +-
tools/perf/util/callchain.c | 19 +-
tools/perf/util/capstone.c | 21 +-
tools/perf/util/data-convert-json.c | 4 +-
tools/perf/util/db-export.c | 76 +-
tools/perf/util/db-export.h | 6 +
tools/perf/util/debug.c | 3 +-
tools/perf/util/disasm.c | 57 +-
tools/perf/util/dlfilter.c | 12 +-
tools/perf/util/dso.c | 236 +++--
tools/perf/util/dso.h | 85 +-
tools/perf/util/dsos.c | 100 +++
tools/perf/util/dsos.h | 12 +-
tools/perf/util/event.c | 12 +-
tools/perf/util/evsel_fprintf.c | 2 +-
tools/perf/util/hist.c | 30 +-
tools/perf/util/intel-pt.c | 74 +-
tools/perf/util/libbfd.c | 5 +-
tools/perf/util/libdw.c | 5 +-
tools/perf/util/llvm.c | 6 +-
tools/perf/util/lock-contention.c | 8 +-
tools/perf/util/machine.c | 143 ++-
tools/perf/util/machine.h | 2 +
tools/perf/util/map.c | 53 +-
tools/perf/util/map.h | 18 +-
tools/perf/util/map_symbol.c | 4 +-
tools/perf/util/maps.c | 3 +-
tools/perf/util/probe-event.c | 135 +--
tools/perf/util/python.c | 20 +-
.../util/scripting-engines/trace-event-perl.c | 8 +-
.../scripting-engines/trace-event-python.c | 38 +-
tools/perf/util/session.c | 31 +
tools/perf/util/session.h | 13 +
tools/perf/util/sort.c | 44 +-
tools/perf/util/srcline.c | 19 +-
tools/perf/util/symbol-elf.c | 22 +-
tools/perf/util/symbol.c | 845 ++++++++++++------
tools/perf/util/symbol.h | 203 ++++-
tools/perf/util/symbol_conf.h | 1 -
tools/perf/util/symbol_fprintf.c | 14 +-
tools/perf/util/thread-stack.c | 18 +-
tools/perf/util/threads.c | 17 +-
tools/perf/util/unwind-libdw.c | 4 +-
tools/perf/util/unwind-libunwind.c | 2 +-
89 files changed, 2644 insertions(+), 1192 deletions(-)
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 1/7] perf symbol: Add accessor functions for struct symbol fields
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
@ 2026-09-28 7:52 ` Ian Rogers
2026-09-28 7:52 ` [PATCH v1 2/7] perf symbol: Remove symbol_conf.priv_size and negative-offset allocations Ian Rogers
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Rogers @ 2026-09-28 7:52 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter, James Clark,
linux-perf-users, linux-kernel, Alireza Haghdoost
To prepare for adding reference count checking (DECLARE_RC_STRUCT) to
struct symbol, add inline accessor functions for struct symbol fields
(symbol__start, symbol__set_start, symbol__end, symbol__set_end,
symbol__name, symbol__namelen, symbol__arch_sym, symbol__set_arch_sym)
and convert direct member accesses across tools/perf.
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
.../arch/powerpc/util/skip-callchain-idx.c | 2 +-
tools/perf/arch/powerpc/util/sym-handling.c | 8 +-
tools/perf/builtin-annotate.c | 4 +-
tools/perf/builtin-diff.c | 5 +-
tools/perf/builtin-kallsyms.c | 8 +-
tools/perf/builtin-kmem.c | 25 ++--
tools/perf/builtin-kwork.c | 4 +-
tools/perf/builtin-lock.c | 12 +-
tools/perf/builtin-mem.c | 2 +-
tools/perf/builtin-sched.c | 6 +-
tools/perf/builtin-script.c | 14 +--
tools/perf/builtin-timechart.c | 2 +-
tools/perf/builtin-top.c | 25 ++--
tools/perf/builtin-trace.c | 11 +-
tools/perf/tests/dlfilter-test.c | 4 +-
tools/perf/tests/dwarf-unwind.c | 2 +-
tools/perf/tests/hists_common.c | 4 +-
tools/perf/tests/hists_cumulate.c | 4 +-
tools/perf/tests/hists_output.c | 2 +-
tools/perf/tests/symbols.c | 4 +-
tools/perf/tests/vmlinux-kallsyms.c | 34 +++---
tools/perf/ui/browsers/annotate.c | 11 +-
tools/perf/ui/browsers/hists.c | 10 +-
tools/perf/ui/browsers/map.c | 9 +-
tools/perf/ui/gtk/annotate.c | 7 +-
tools/perf/ui/stdio/hist.c | 3 +-
.../util/annotate-arch/annotate-loongarch.c | 4 +-
tools/perf/util/annotate-arch/annotate-x86.c | 14 +--
tools/perf/util/annotate-data.c | 14 ++-
tools/perf/util/annotate.c | 73 +++++++-----
tools/perf/util/auxtrace.c | 14 +--
tools/perf/util/block-info.c | 7 +-
tools/perf/util/bpf_lock_contention.c | 20 ++--
tools/perf/util/c2c-function.c | 12 +-
tools/perf/util/callchain.c | 15 ++-
tools/perf/util/capstone.c | 20 ++--
tools/perf/util/data-convert-json.c | 4 +-
tools/perf/util/db-export.c | 2 +-
tools/perf/util/debug.c | 3 +-
tools/perf/util/disasm.c | 45 ++++----
tools/perf/util/dlfilter.c | 12 +-
tools/perf/util/dso.c | 4 +-
tools/perf/util/event.c | 4 +-
tools/perf/util/evsel_fprintf.c | 2 +-
tools/perf/util/hist.c | 17 +--
tools/perf/util/intel-pt.c | 8 +-
tools/perf/util/libbfd.c | 5 +-
tools/perf/util/llvm.c | 6 +-
tools/perf/util/lock-contention.c | 2 +-
tools/perf/util/machine.c | 34 +++---
tools/perf/util/map.c | 6 +-
tools/perf/util/map.h | 2 +-
tools/perf/util/probe-event.c | 40 +++----
tools/perf/util/python.c | 8 +-
.../util/scripting-engines/trace-event-perl.c | 8 +-
.../scripting-engines/trace-event-python.c | 28 ++---
tools/perf/util/sort.c | 42 +++----
tools/perf/util/srcline.c | 13 ++-
tools/perf/util/symbol-elf.c | 11 +-
tools/perf/util/symbol.c | 107 ++++++++++--------
tools/perf/util/symbol.h | 42 ++++++-
tools/perf/util/symbol_fprintf.c | 14 +--
tools/perf/util/thread-stack.c | 8 +-
tools/perf/util/unwind-libdw.c | 2 +-
64 files changed, 504 insertions(+), 390 deletions(-)
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
index 472714cfad38..ee2dea01c4ea 100644
--- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c
+++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
@@ -239,7 +239,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain)
rc = check_return_addr(dso, map__map_ip(al.map, ip));
pr_debug("[DSO %s, sym %s, ip 0x%" PRIx64 "] rc %d\n",
- dso__long_name(dso), al.sym->name, ip, rc);
+ dso__long_name(dso), symbol__name(al.sym), ip, rc);
if (rc == 0) {
/*
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
index 947bfad7aa59..d73bfdcdbec1 100644
--- a/tools/perf/arch/powerpc/util/sym-handling.c
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -13,7 +13,7 @@
int arch__choose_best_symbol(struct symbol *syma,
struct symbol *symb __maybe_unused)
{
- char *sym = syma->name;
+ const char *sym = symbol__name(syma);
#if !defined(_CALL_ELF) || _CALL_ELF != 2
/* Skip over any initial dot */
@@ -69,7 +69,7 @@ const char *arch__normalize_symbol_name(const char *name)
#ifdef HAVE_LIBELF_SUPPORT
void arch__sym_update(struct symbol *s, GElf_Sym *sym)
{
- s->arch_sym = sym->st_other;
+ symbol__set_arch_sym(s, sym->st_other);
}
#endif
@@ -102,7 +102,7 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev,
return;
}
- lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym);
+ lep_offset = PPC64_LOCAL_ENTRY_OFFSET(symbol__arch_sym(sym));
if (map__dso(map)->symtab_type == DSO_BINARY_TYPE__KALLSYMS)
tev->point.offset += PPC64LE_LEP_OFFSET;
@@ -131,7 +131,7 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
for (i = 0; i < ntevs; i++) {
tev = &pev->tevs[i];
map__for_each_symbol(map, sym, tmp) {
- if (map__unmap_ip(map, sym->start) == tev->point.address) {
+ if (map__unmap_ip(map, symbol__start(sym)) == tev->point.address) {
arch__fix_tev_from_maps(pev, tev, map, sym);
break;
}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 8863f3a570f6..c93b67986334 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -252,7 +252,7 @@ static int add_sample(struct perf_sample *sample,
if ((!ann->has_br_stack || !has_annotation(ann)) &&
ann->sym_hist_filter != NULL &&
(al->sym == NULL ||
- strcmp(ann->sym_hist_filter, al->sym->name) != 0)) {
+ strcmp(ann->sym_hist_filter, symbol__name(al->sym)) != 0)) {
/* We're only interested in a symbol named sym_hist_filter */
/*
* FIXME: why isn't this done in the symbol_filter when loading
@@ -423,7 +423,7 @@ static void hists__find_annotations(struct hists *hists,
goto find_next;
if (ann->sym_hist_filter &&
- (strcmp(he->ms.sym->name, ann->sym_hist_filter) != 0))
+ (strcmp(symbol__name(he->ms.sym), ann->sym_hist_filter) != 0))
goto find_next;
if (ann->min_percent) {
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 9fa8e900637b..17decf1e19ff 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -1358,10 +1358,11 @@ static int cycles_printf(struct hist_entry *he, struct hist_entry *pair,
bi = block_he->block_info;
- start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
+ start_line = map__srcline(he->ms.map,
+ symbol__start(bi->sym) + bi->start,
he->ms.sym);
- end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
+ end_line = map__srcline(he->ms.map, symbol__start(bi->sym) + bi->end,
he->ms.sym);
if (start_line != SRCLINE_UNKNOWN &&
diff --git a/tools/perf/builtin-kallsyms.c b/tools/perf/builtin-kallsyms.c
index 3c4339982b16..eb62bb4ea602 100644
--- a/tools/perf/builtin-kallsyms.c
+++ b/tools/perf/builtin-kallsyms.c
@@ -48,9 +48,11 @@ static int __cmd_kallsyms(int argc, const char **argv)
dso = map__dso(map);
printf("%s: %s %s %#" PRIx64 "-%#" PRIx64 " (%#" PRIx64 "-%#" PRIx64")\n",
- symbol->name, dso__short_name(dso), dso__long_name(dso),
- map__unmap_ip(map, symbol->start), map__unmap_ip(map, symbol->end),
- symbol->start, symbol->end);
+ symbol__name(symbol), dso__short_name(dso),
+ dso__long_name(dso),
+ map__unmap_ip(map, symbol__start(symbol)),
+ map__unmap_ip(map, symbol__end(symbol)),
+ symbol__start(symbol), symbol__end(symbol));
}
out:
machine__delete(machine);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 8693c6b135ca..d1883086ed58 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -310,7 +310,7 @@ static struct rb_root page_caller_sorted;
struct alloc_func {
u64 start;
u64 end;
- char *name;
+ const char *name;
};
static int nr_alloc_funcs;
@@ -368,7 +368,7 @@ static int build_alloc_func_list(void)
}
map__for_each_symbol(kernel_map, sym, node) {
- if (regexec(&alloc_func_regex, sym->name, 0, NULL, 0))
+ if (regexec(&alloc_func_regex, symbol__name(sym), 0, NULL, 0))
continue;
func = realloc(alloc_func_list,
@@ -376,10 +376,10 @@ static int build_alloc_func_list(void)
if (func == NULL)
return -ENOMEM;
- pr_debug("alloc func: %s\n", sym->name);
- func[nr_alloc_funcs].start = sym->start;
- func[nr_alloc_funcs].end = sym->end;
- func[nr_alloc_funcs].name = sym->name;
+ pr_debug("alloc func: %s\n", symbol__name(sym));
+ func[nr_alloc_funcs].start = symbol__start(sym);
+ func[nr_alloc_funcs].end = symbol__end(sym);
+ func[nr_alloc_funcs].name = symbol__name(sym);
alloc_func_list = func;
nr_alloc_funcs++;
@@ -1049,8 +1049,9 @@ static void __print_slab_result(struct rb_root *root,
addr = data->ptr;
if (sym != NULL)
- snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name,
- addr - map__unmap_ip(map, sym->start));
+ snprintf(buf, sizeof(buf), "%s+%" PRIx64 "",
+ symbol__name(sym),
+ addr - map__unmap_ip(map, symbol__start(sym)));
else
snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr);
printf(" %-34s |", buf);
@@ -1105,12 +1106,12 @@ static void __print_page_alloc_result(struct perf_session *session, int n_lines)
struct symbol *sym;
struct map *map;
char buf[32];
- char *caller = buf;
+ const char *caller = buf;
data = rb_entry(next, struct page_stat, node);
sym = machine__find_kernel_symbol(machine, data->callsite, &map);
if (sym)
- caller = sym->name;
+ caller = symbol__name(sym);
else
scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite);
@@ -1147,12 +1148,12 @@ static void __print_page_caller_result(struct perf_session *session, int n_lines
struct symbol *sym;
struct map *map;
char buf[32];
- char *caller = buf;
+ const char *caller = buf;
data = rb_entry(next, struct page_stat, node);
sym = machine__find_kernel_symbol(machine, data->callsite, &map);
if (sym)
- caller = sym->name;
+ caller = symbol__name(sym);
else
scnprintf(buf, sizeof(buf), "%"PRIx64, data->callsite);
diff --git a/tools/perf/builtin-kwork.c b/tools/perf/builtin-kwork.c
index fce588441e49..98714f1ed949 100644
--- a/tools/perf/builtin-kwork.c
+++ b/tools/perf/builtin-kwork.c
@@ -768,8 +768,8 @@ static void timehist_save_callchain(struct perf_kwork *kwork,
sym = node->ms.sym;
if (sym) {
- if (!strcmp(sym->name, "__softirqentry_text_start") ||
- !strcmp(sym->name, "__do_softirq"))
+ if (!strcmp(symbol__name(sym), "__softirqentry_text_start") ||
+ !strcmp(symbol__name(sym), "__do_softirq"))
symbol__set_ignore(sym, true);
}
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index d5c0d55cb82d..cd060c984068 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -826,12 +826,13 @@ static int get_symbol_name_offset(struct map *map, struct symbol *sym, u64 ip,
return 0;
}
- offset = map__map_ip(map, ip) - sym->start;
+ offset = map__map_ip(map, ip) - symbol__start(sym);
if (offset)
- return scnprintf(buf, size, "%s+%#lx", sym->name, offset);
+ return scnprintf(buf, size, "%s+%#lx", symbol__name(sym),
+ offset);
else
- return strlcpy(buf, sym->name, size);
+ return strlcpy(buf, symbol__name(sym), size);
}
static int lock_contention_caller(struct perf_sample *sample,
char *buf, int size)
@@ -1005,7 +1006,8 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
return -ENOMEM;
}
- addrs[filters.nr_addrs++] = map__unmap_ip(kmap, sym->start);
+ addrs[filters.nr_addrs++] = map__unmap_ip(kmap,
+ symbol__start(sym));
filters.addrs = addrs;
}
}
@@ -1019,7 +1021,7 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
case LOCK_AGGR_ADDR:
sym = machine__find_kernel_symbol(machine, key, &kmap);
if (sym)
- name = sym->name;
+ name = symbol__name(sym);
break;
case LOCK_AGGR_CALLER:
name = buf;
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index ade53688ebcd..5a19be73348d 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -249,7 +249,7 @@ dump_raw_samples(const struct perf_tool *tool,
sample->data_src,
symbol_conf.field_sep,
dso ? dso__long_name(dso) : "???",
- al.sym ? al.sym->name : "???");
+ al.sym ? symbol__name(al.sym) : "???");
out_put:
addr_location__exit(&al);
return 0;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 6e8bf619c86c..e53098b532b4 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -2629,9 +2629,9 @@ static void save_task_callchain(struct perf_sched *sched,
sym = node->ms.sym;
if (sym) {
- if (!strcmp(sym->name, "schedule") ||
- !strcmp(sym->name, "__schedule") ||
- !strcmp(sym->name, "preempt_schedule"))
+ if (!strcmp(symbol__name(sym), "schedule") ||
+ !strcmp(symbol__name(sym), "__schedule") ||
+ !strcmp(symbol__name(sym), "preempt_schedule"))
symbol__set_ignore(sym, true);
}
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 565ee8d55f80..f1257a78d975 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1404,7 +1404,7 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
addr_location__init(&al);
thread__find_map(thread, cpumode, addr, &al);
- if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end)
+ if ((*lastsym) && al.addr >= symbol__start((*lastsym)) && al.addr < symbol__end((*lastsym)))
goto out;
al.cpu = cpu;
@@ -1415,11 +1415,11 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
if (!al.sym)
goto out;
- if (al.addr < al.sym->end)
- off = al.addr - al.sym->start;
+ if (al.addr < symbol__end(al.sym))
+ off = al.addr - symbol__start(al.sym);
else
- off = al.addr - map__start(al.map) - al.sym->start;
- printed += fprintf(fp, "\t%s", al.sym->name);
+ off = al.addr - map__start(al.map) - symbol__start(al.sym);
+ printed += fprintf(fp, "\t%s", symbol__name(al.sym));
if (off)
printed += fprintf(fp, "%+d", off);
printed += fprintf(fp, ":");
@@ -1638,7 +1638,7 @@ static const char *resolve_branch_sym(struct perf_sample *sample,
if (!addr_al->thread)
thread__resolve(thread, addr_al, sample);
if (addr_al->sym)
- name = addr_al->sym->name;
+ name = symbol__name(addr_al->sym);
else
*ip = sample->addr;
} else {
@@ -1646,7 +1646,7 @@ static const char *resolve_branch_sym(struct perf_sample *sample,
}
} else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) {
if (al->sym)
- name = al->sym->name;
+ name = symbol__name(al->sym);
else
*ip = sample->ip;
}
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 3f9153d5ecfb..046bd185318d 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -565,7 +565,7 @@ static char *cat_backtrace(struct perf_sample *sample,
addr_location__init(&tal);
tal.filtered = 0;
if (thread__find_symbol(al.thread, cpumode, ip, &tal))
- fprintf(f, "..... %016" PRIx64 " %s\n", ip, tal.sym->name);
+ fprintf(f, "..... %016" PRIx64 " %s\n", ip, symbol__name(tal.sym));
else
fprintf(f, "..... %016" PRIx64 "\n", ip);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index a3442d2d6edf..19a21348823c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -133,8 +133,8 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
* We can't annotate with just /proc/kallsyms
*/
if (dso__symtab_type(dso) == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(dso)) {
- pr_err("Can't annotate %s: No vmlinux file was found in the "
- "path\n", sym->name);
+ pr_err("Can't annotate %s: No vmlinux file was found in the path\n",
+ symbol__name(sym));
sleep(1);
return -1;
}
@@ -145,7 +145,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
if (!symbol__hists(sym, evlist__nr_entries(top->evlist))) {
annotation__unlock(notes);
pr_err("Not enough memory for annotating '%s' symbol!\n",
- sym->name);
+ symbol__name(sym));
sleep(1);
return err;
}
@@ -156,7 +156,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
} else {
char msg[BUFSIZ];
symbol__strerror_disassemble(&he->ms, err, msg, sizeof(msg));
- pr_err("Couldn't annotate %s: %s\n", sym->name, msg);
+ pr_err("Couldn't annotate %s: %s\n", symbol__name(sym), msg);
}
annotation__unlock(notes);
@@ -186,9 +186,11 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip)
"Not all samples will be on the annotation output.\n\n"
"Please report to linux-kernel@vger.kernel.org\n",
ip, dso__long_name(dso), dso__symtab_origin(dso),
- map__start(map), map__end(map), sym->start, sym->end,
+ map__start(map), map__end(map), symbol__start(sym),
+ symbol__end(sym),
symbol__binding(sym) == STB_GLOBAL ? 'g' :
- symbol__binding(sym) == STB_LOCAL ? 'l' : 'w', sym->name,
+ symbol__binding(sym) == STB_LOCAL ? 'l' : 'w',
+ symbol__name(sym),
err ? "[unknown]" : uts.machine,
err ? "[unknown]" : uts.release, perf_version_string);
if (use_browser <= 0)
@@ -232,7 +234,7 @@ static void perf_top__record_precise_ip(struct perf_top *top,
ui__warn_map_erange(he->ms.map, sym, ip);
else if (err == -ENOMEM) {
pr_err("Not enough memory for annotating '%s' symbol!\n",
- sym->name);
+ symbol__name(sym));
sleep(1);
}
@@ -263,7 +265,8 @@ static void perf_top__show_details(struct perf_top *top)
if (notes->src == NULL)
goto out_unlock;
- printf("Showing %s for %s\n", evsel__name(top->sym_evsel), symbol->name);
+ printf("Showing %s for %s\n", evsel__name(top->sym_evsel),
+ symbol__name(symbol));
printf(" Events Pcnt (>=%d%%)\n", annotate_opts.min_pcnt);
more = hist_entry__annotate_printf(he, top->sym_evsel);
@@ -418,7 +421,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
next = rb_first_cached(&hists->entries);
while (next) {
n = rb_entry(next, struct hist_entry, rb_node);
- if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
+ if (n->ms.sym && !strcmp(buf, symbol__name(n->ms.sym))) {
found = n;
break;
}
@@ -437,11 +440,11 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
static void perf_top__print_mapped_keys(struct perf_top *top)
{
- char *name = NULL;
+ const char *name = NULL;
if (top->sym_filter_entry) {
struct symbol *sym = top->sym_filter_entry->ms.sym;
- name = sym->name;
+ name = symbol__name(sym);
}
fprintf(stdout, "\nMapped keys:\n");
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index d327603ae454..aaa090912409 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -768,15 +768,16 @@ size_t syscall_arg__scnprintf_ksym(char *bf, size_t size, struct syscall_arg *ar
arg->val, &map);
if (sym) {
- u64 start = map__unmap_ip(map, sym->start);
+ u64 start = map__unmap_ip(map, symbol__start(sym));
u64 offset = arg->val - start;
size_t printed;
if (offset == 0)
- printed = scnprintf(bf, size, "%s", sym->name);
+ printed = scnprintf(bf, size, "%s",
+ symbol__name(sym));
else
printed = scnprintf(bf, size, "%s+0x%" PRIx64,
- sym->name, offset);
+ symbol__name(sym), offset);
map__put(map);
return printed;
}
@@ -3652,8 +3653,8 @@ static void print_location(FILE *f, struct perf_sample *sample,
fprintf(f, "%s@", dso__long_name(map__dso(al->map)));
if ((verbose > 0 || print_sym) && al->sym)
- fprintf(f, "%s+0x%" PRIx64, al->sym->name,
- al->addr - al->sym->start);
+ fprintf(f, "%s+0x%" PRIx64, symbol__name(al->sym),
+ al->addr - symbol__start(al->sym));
else if (al->map)
fprintf(f, "0x%" PRIx64, al->addr);
else
diff --git a/tools/perf/tests/dlfilter-test.c b/tools/perf/tests/dlfilter-test.c
index 204663571943..b4649c79c309 100644
--- a/tools/perf/tests/dlfilter-test.c
+++ b/tools/perf/tests/dlfilter-test.c
@@ -274,11 +274,11 @@ static int get_ip_addr(struct test_data *td)
sym = map__find_symbol_by_name(map, "foo");
if (sym)
- td->foo = sym->start;
+ td->foo = symbol__start(sym);
sym = map__find_symbol_by_name(map, "bar");
if (sym)
- td->bar = sym->start;
+ td->bar = symbol__start(sym);
map__put(map);
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 9ed78d00fb87..b8b0c430a6b3 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -56,7 +56,7 @@ int test__dwarf_unwind(struct test_suite *test, int subtest);
static int unwind_entry(struct unwind_entry *entry, void *arg)
{
unsigned long *cnt = (unsigned long *) arg;
- char *symbol = entry->ms.sym ? entry->ms.sym->name : NULL;
+ const char *symbol = entry->ms.sym ? symbol__name(entry->ms.sym) : NULL;
static const char *funcs[MAX_STACK] = {
"test__arch_unwind_sample",
"test_dwarf_unwind__thread",
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index 187f12f5bc21..0db3ea9cf62e 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -184,7 +184,7 @@ void print_hists_in(struct hists *hists)
pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
i, thread__comm_str(he->thread),
dso__short_name(dso),
- he->ms.sym->name, he->stat.period);
+ symbol__name(he->ms.sym), he->stat.period);
}
i++;
@@ -213,7 +213,7 @@ void print_hists_out(struct hists *hists)
pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"/%"PRIu64"\n",
i, thread__comm_str(he->thread), thread__tid(he->thread),
dso__short_name(dso),
- he->ms.sym->name, he->stat.period,
+ symbol__name(he->ms.sym), he->stat.period,
he->stat_acc ? he->stat_acc->period : 0);
}
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index c4a11a3255bc..95b9a629e59e 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -164,11 +164,11 @@ typedef int (*test_fn_t)(struct evsel *, struct machine *);
#define COMM(he) (thread__comm_str(he->thread))
#define DSO(he) (dso__short_name(map__dso(he->ms.map)))
-#define SYM(he) (he->ms.sym->name)
+#define SYM(he) (symbol__name(he->ms.sym))
#define CPU(he) (he->cpu)
#define DEPTH(he) (he->callchain->max_depth)
#define CDSO(cl) (dso__short_name(map__dso(cl->ms.map)))
-#define CSYM(cl) (cl->ms.sym->name)
+#define CSYM(cl) (symbol__name(cl->ms.sym))
struct result {
u64 children;
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index 35d230a83e43..77fb3a187139 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -129,7 +129,7 @@ typedef int (*test_fn_t)(struct evsel *, struct machine *);
#define COMM(he) (thread__comm_str(he->thread))
#define DSO(he) (dso__short_name(map__dso(he->ms.map)))
-#define SYM(he) (he->ms.sym->name)
+#define SYM(he) (symbol__name(he->ms.sym))
#define CPU(he) (he->cpu)
#define PID(he) (thread__tid(he->thread))
diff --git a/tools/perf/tests/symbols.c b/tools/perf/tests/symbols.c
index c09e04f36035..d9796851335e 100644
--- a/tools/perf/tests/symbols.c
+++ b/tools/perf/tests/symbols.c
@@ -129,14 +129,14 @@ static int test_dso(struct dso *dso)
continue;
/* Check for overlapping function symbols */
- if (last_sym && sym->start < last_sym->end) {
+ if (last_sym && symbol__start(sym) < symbol__end(last_sym)) {
pr_debug("Overlapping symbols:\n");
symbol__fprintf(last_sym, stderr);
symbol__fprintf(sym, stderr);
ret = TEST_FAIL;
}
/* Check for zero-length function symbol */
- if (sym->start == sym->end) {
+ if (symbol__start(sym) == symbol__end(sym)) {
pr_debug("Zero-length symbol:\n");
symbol__fprintf(sym, stderr);
ret = TEST_FAIL;
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 9396c8a77c86..97950f86ed5f 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -292,18 +292,20 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused
sym = rb_entry(nd, struct symbol, rb_node);
- if (sym->start == sym->end)
+ if (symbol__start(sym) == symbol__end(sym))
continue;
- mem_start = map__unmap_ip(args.vmlinux_map, sym->start);
- mem_end = map__unmap_ip(args.vmlinux_map, sym->end);
+ mem_start = map__unmap_ip(args.vmlinux_map,
+ symbol__start(sym));
+ mem_end = map__unmap_ip(args.vmlinux_map, symbol__end(sym));
first_pair = machine__find_kernel_symbol(&args.kallsyms, mem_start, NULL);
pair = first_pair;
- if (pair && UM(pair->start) == mem_start) {
+ if (pair && UM(symbol__start(pair)) == mem_start) {
next_pair:
- if (arch__compare_symbol_names(sym->name, pair->name) == 0) {
+ if (arch__compare_symbol_names(symbol__name(sym),
+ symbol__name(pair)) == 0) {
/*
* kallsyms don't have the symbol end, so we
* set that by using the next symbol start - 1,
@@ -313,11 +315,12 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused
* off the real size. More than that and we
* _really_ have a problem.
*/
- s64 skew = mem_end - UM(pair->end);
+ s64 skew = mem_end - UM(symbol__end(pair));
if (llabs(skew) >= page_size)
pr_debug("WARN: %#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
- mem_start, sym->name, mem_end,
- UM(pair->end));
+ mem_start, symbol__name(sym),
+ mem_end,
+ UM(symbol__end(pair)));
/*
* Do not count this as a failure, because we
@@ -328,16 +331,19 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused
continue;
} else {
pair = machine__find_kernel_symbol_by_name(&args.kallsyms,
- sym->name, NULL);
+ symbol__name(sym),
+ NULL);
if (pair) {
- if (UM(pair->start) == mem_start)
+ if (UM(symbol__start(pair)) == mem_start)
goto next_pair;
pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
- mem_start, sym->name, pair->name);
+ mem_start, symbol__name(sym),
+ symbol__name(pair));
} else {
pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
- mem_start, sym->name, first_pair->name);
+ mem_start, symbol__name(sym),
+ symbol__name(first_pair));
}
continue;
@@ -348,14 +354,14 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused
* such as __indirect_thunk_end.
*/
continue;
- } else if (is_ignored_symbol(sym->name, symbol__type(sym))) {
+ } else if (is_ignored_symbol(symbol__name(sym), symbol__type(sym))) {
/*
* Ignore hidden symbols, see scripts/kallsyms.c for the details
*/
continue;
} else {
pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n",
- mem_start, sym->name);
+ mem_start, symbol__name(sym));
}
err = -1;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index cf36b5347f72..5ef9a59ebdc1 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -196,7 +196,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
int diff = 0;
/* PLT symbols contain external offsets */
- if (strstr(sym->name, "@plt"))
+ if (strstr(symbol__name(sym), "@plt"))
return;
if (!disasm_line__is_valid_local_jump(cursor, sym))
@@ -554,7 +554,8 @@ static void ui_browser__init_asm_mode(struct ui_browser *browser)
static int sym_title(struct symbol *sym, struct map *map, char *title,
size_t sz, int percent_type)
{
- return snprintf(title, sz, "%s %s [Percent: %s] %s", sym->name,
+ return snprintf(title, sz, "%s %s [Percent: %s] %s",
+ symbol__name(sym),
dso__long_name(map__dso(map)),
percent_type_str(percent_type),
annotate_opts.code_with_type ? "[Type]" : "");
@@ -602,7 +603,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
if (!symbol__hists(dl->ops.target.sym, evlist__nr_entries(evsel->evlist))) {
annotation__unlock(notes);
ui__warning("Not enough memory for annotating '%s' symbol!\n",
- dl->ops.target.sym->name);
+ symbol__name(dl->ops.target.sym));
return true;
}
@@ -876,7 +877,7 @@ static void annotate_browser__symbol_annotate_error(struct annotate_browser *bro
dso__set_annotate_warned(dso);
symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
- ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
+ ui__error("Couldn't annotate %s:\n%s", symbol__name(sym), msg);
}
static int annotate_browser__run(struct annotate_browser *browser,
@@ -1255,7 +1256,7 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms,
*/
if (al_addr != NO_ADDR) {
struct annotation_line *al = annotated_source__get_line(notes->src,
- al_addr - sym->start);
+ al_addr - symbol__start(sym));
browser.selection = al;
}
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 593e1fd5759d..206657039223 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2548,7 +2548,7 @@ add_annotate_opt(struct popup_action *act, char **optstr,
if (ms->sym == NULL || symbol__annotation(ms->sym)->src == NULL)
return 0;
- if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0)
+ if (asprintf(optstr, "Annotate %s", symbol__name(ms->sym)) < 0)
return 0;
map_symbol__copy(&act->ms, ms);
@@ -2748,7 +2748,7 @@ do_run_script(struct hist_browser *browser,
if (act->ms.thread)
len += strlen(thread__comm_str(act->ms.thread));
else if (act->ms.sym)
- len += strlen(act->ms.sym->name);
+ len += strlen(symbol__name(act->ms.sym));
script_opt = malloc(len);
if (!script_opt)
return -1;
@@ -2759,7 +2759,7 @@ do_run_script(struct hist_browser *browser,
thread__comm_str(act->ms.thread));
} else if (act->ms.sym) {
n = scnprintf(script_opt, len, " -S %s ",
- act->ms.sym->name);
+ symbol__name(act->ms.sym));
}
if (act->time) {
@@ -2804,7 +2804,7 @@ add_script_opt_2(struct popup_action *act, char **optstr,
return 0;
} else if (sym) {
if (asprintf(optstr, "Run scripts for samples of symbol [%s]%s",
- sym->name, tstr) < 0)
+ symbol__name(sym), tstr) < 0)
return 0;
} else {
if (asprintf(optstr, "Run scripts for all samples%s", tstr) < 0)
@@ -3208,7 +3208,7 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h
ui_browser__warning(&browser->b, delay_secs * 2,
"No samples for the \"%s\" symbol.\n\n"
"Probably appeared just in a callchain",
- browser->selection->sym->name);
+ symbol__name(browser->selection->sym));
continue;
}
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 075a575cdc5d..1f69d7a798e9 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -31,12 +31,13 @@ static void map_browser__write(struct ui_browser *browser, void *nd, int row)
ui_browser__set_percent_color(browser, 0, current_entry);
ui_browser__printf(browser, "%*" PRIx64 " %*" PRIx64 " %c ",
- mb->addrlen, sym->start, mb->addrlen, sym->end,
+ mb->addrlen, symbol__start(sym), mb->addrlen,
+ symbol__end(sym),
symbol__binding(sym) == STB_GLOBAL ? 'g' :
symbol__binding(sym) == STB_LOCAL ? 'l' : 'w');
width = browser->width - ((mb->addrlen * 2) + 4);
if (width > 0)
- ui_browser__write_nstring(browser, sym->name, width);
+ ui_browser__write_nstring(browser, symbol__name(sym), width);
}
/* FIXME uber-kludgy, see comment on cmd_report... */
@@ -122,8 +123,8 @@ int map__browse(struct map *map)
for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
- if (maxaddr < pos->end)
- maxaddr = pos->end;
+ if (maxaddr < symbol__end(pos))
+ maxaddr = symbol__end(pos);
if (verbose > 0) {
u32 *idx = symbol__browser_index(pos);
*idx = mb.b.nr_entries;
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
index 094dfa045b77..136957d475d0 100644
--- a/tools/perf/ui/gtk/annotate.c
+++ b/tools/perf/ui/gtk/annotate.c
@@ -67,7 +67,7 @@ static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
static int perf_gtk__get_offset(char *buf, size_t size, struct map_symbol *ms,
struct disasm_line *dl)
{
- u64 start = map__rip_2objdump(ms->map, ms->sym->start);
+ u64 start = map__rip_2objdump(ms->map, symbol__start(ms->sym));
strcpy(buf, "");
@@ -192,7 +192,8 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,
dso__set_annotate_warned(dso);
symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
- ui__error("Couldn't annotate %s: %s\n", sym->name, msg);
+ ui__error("Couldn't annotate %s: %s\n", symbol__name(sym),
+ msg);
return -1;
}
@@ -234,7 +235,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,
}
scrolled_window = gtk_scrolled_window_new();
- tab_label = gtk_label_new(sym->name);
+ tab_label = gtk_label_new(symbol__name(sym));
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
GTK_POLICY_AUTOMATIC,
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 8c4c8925df2c..f80cc73909ed 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -100,13 +100,12 @@ static struct callchain_list rem_hits;
static void init_rem_hits(void)
{
- rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
+ rem_sq_bracket = symbol__new(0, 0, 0, 0, "[...]");
if (!rem_sq_bracket) {
fprintf(stderr, "Not enough memory to display remaining hits\n");
return;
}
- strcpy(rem_sq_bracket->name, "[...]");
rem_hits.ms.sym = rem_sq_bracket;
}
diff --git a/tools/perf/util/annotate-arch/annotate-loongarch.c b/tools/perf/util/annotate-arch/annotate-loongarch.c
index a949b4392dd4..d275730080b7 100644
--- a/tools/perf/util/annotate-arch/annotate-loongarch.c
+++ b/tools/perf/util/annotate-arch/annotate-loongarch.c
@@ -94,8 +94,8 @@ static int loongarch_jump__parse(const struct arch *arch, struct ins_operands *o
ops->target.addr = strtoull(ops->raw, NULL, 16);
target.addr = map__objdump_2mem(map, ops->target.addr);
- start = map__unmap_ip(map, sym->start);
- end = map__unmap_ip(map, sym->end);
+ start = map__unmap_ip(map, symbol__start(sym));
+ end = map__unmap_ip(map, symbol__end(sym));
ops->target.outside = target.addr < start || target.addr >= end;
diff --git a/tools/perf/util/annotate-arch/annotate-x86.c b/tools/perf/util/annotate-arch/annotate-x86.c
index 1acf31a2c759..07b2b9e8fd1d 100644
--- a/tools/perf/util/annotate-arch/annotate-x86.c
+++ b/tools/perf/util/annotate-arch/annotate-x86.c
@@ -239,7 +239,7 @@ static void update_insn_state_x86(struct type_state *state,
/* Try to resolve the call target name */
if (func)
- call_name = func->name;
+ call_name = symbol__name(func);
else
call_name = dl->ops.target.name;
@@ -254,7 +254,7 @@ static void update_insn_state_x86(struct type_state *state,
/* Invalidate caller-saved registers after call */
call_addr = map__rip_2objdump(dloc->ms->map,
- dloc->ms->sym->start + dl->al.offset);
+ symbol__start(dloc->ms->sym) + dl->al.offset);
for (unsigned i = 0; i < ARRAY_SIZE(state->regs); i++) {
struct type_state_reg *reg = &state->regs[i];
@@ -286,7 +286,7 @@ static void update_insn_state_x86(struct type_state *state,
int offset;
const char *var_name = NULL;
struct map_symbol *ms = dloc->ms;
- u64 ip = ms->sym->start + dl->al.offset;
+ u64 ip = symbol__start(ms->sym) + dl->al.offset;
if (!has_reg_type(state, dst->reg1))
return;
@@ -487,7 +487,7 @@ static void update_insn_state_x86(struct type_state *state,
return;
if (dloc->fb_cfa) {
- u64 ip = dloc->ms->sym->start + dl->al.offset;
+ u64 ip = symbol__start(dloc->ms->sym) + dl->al.offset;
u64 pc = map__rip_2objdump(dloc->ms->map, ip);
if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fboff) < 0)
@@ -504,7 +504,7 @@ static void update_insn_state_x86(struct type_state *state,
if (dso__kernel(map__dso(dloc->ms->map)) &&
src->segment == INSN_SEG_X86_GS && src->imm) {
- u64 ip = dloc->ms->sym->start + dl->al.offset;
+ u64 ip = symbol__start(dloc->ms->sym) + dl->al.offset;
u64 var_addr;
int offset;
@@ -653,7 +653,7 @@ static void update_insn_state_x86(struct type_state *state,
/* Or check if it's a global variable */
else if (sreg == DWARF_REG_PC) {
struct map_symbol *ms = dloc->ms;
- u64 ip = ms->sym->start + dl->al.offset;
+ u64 ip = symbol__start(ms->sym) + dl->al.offset;
u64 addr;
int offset;
@@ -678,7 +678,7 @@ static void update_insn_state_x86(struct type_state *state,
/* And check percpu access with base register */
else if (has_reg_type(state, sreg) &&
state->regs[sreg].kind == TSR_KIND_PERCPU_BASE) {
- u64 ip = dloc->ms->sym->start + dl->al.offset;
+ u64 ip = symbol__start(dloc->ms->sym) + dl->al.offset;
u64 var_addr = src->offset;
int offset;
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 19a6ecd67f28..0b2bd6702f25 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -851,9 +851,10 @@ bool get_global_var_info(struct data_loc_info *dloc, u64 addr,
sym = thread__find_symbol_fb(dloc->thread, dloc->cpumode,
mem_addr, &al);
if (sym) {
- *var_name = sym->name;
+ *var_name = symbol__name(sym);
/* Calculate type offset from the start of variable */
- *var_offset = mem_addr - map__unmap_ip(al.map, sym->start);
+ *var_offset = mem_addr - map__unmap_ip(al.map,
+ symbol__start(sym));
} else {
*var_name = NULL;
}
@@ -1503,7 +1504,7 @@ static enum type_match_result find_data_type_insn(struct data_loc_info *dloc,
bb->begin->al.offset, bb->end->al.offset);
list_for_each_entry_from(dl, ¬es->src->source, al.node) {
- u64 this_ip = sym->start + dl->al.offset;
+ u64 this_ip = symbol__start(sym) + dl->al.offset;
u64 addr = map__rip_2objdump(dloc->ms->map, this_ip);
/* Skip comment or debug info lines */
@@ -1582,8 +1583,8 @@ static enum type_match_result find_data_type_block(struct data_loc_info *dloc,
}
pr_debug_dtp("cannot find a basic block from %"PRIx64" to %"PRIx64"\n",
- src_ip - dloc->ms->sym->start,
- dst_ip - dloc->ms->sym->start);
+ src_ip - symbol__start(dloc->ms->sym),
+ dst_ip - symbol__start(dloc->ms->sym));
continue;
}
prepend_basic_blocks(&this_blocks, &basic_blocks);
@@ -1662,7 +1663,8 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die)
pr_debug_dtp("-----------------------------------------------------------\n");
pr_debug_dtp("find data type for %s%#x(%s) at %s+%#"PRIx64"\n",
offset_sign, offset, buf,
- dloc->ms->sym->name, dloc->ip - dloc->ms->sym->start);
+ symbol__name(dloc->ms->sym),
+ dloc->ip - symbol__start(dloc->ms->sym));
/*
* IP is a relative instruction address from the start of the map, as
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 86a4beec6528..a1090a4e2e9d 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -237,18 +237,20 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms,
pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map__unmap_ip(ms->map, addr));
- if ((addr < sym->start || addr >= sym->end) &&
- (addr != sym->end || sym->start != sym->end)) {
+ if ((addr < symbol__start(sym) || addr >= symbol__end(sym)) &&
+ (addr != symbol__end(sym) || symbol__start(sym) != symbol__end(sym))) {
pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n",
- __func__, __LINE__, sym->name, sym->start, addr, sym->end);
+ __func__, __LINE__, symbol__name(sym),
+ symbol__start(sym), addr, symbol__end(sym));
return -ERANGE;
}
- offset = addr - sym->start;
+ offset = addr - symbol__start(sym);
h = annotated_source__histogram(src, evsel);
if (h == NULL) {
pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n",
- __func__, __LINE__, sym->name, sym->start, addr, sym->end,
+ __func__, __LINE__, symbol__name(sym),
+ symbol__start(sym), addr, symbol__end(sym),
symbol__type(sym) == STT_FUNC);
return -ENOMEM;
}
@@ -288,7 +290,8 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms,
pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64
" weight %" PRIu64 "\n",
- sym->start, sym->name, addr, addr - sym->start, evsel->core.idx,
+ symbol__start(sym), symbol__name(sym), addr,
+ addr - symbol__start(sym), evsel->core.idx,
entry->nr_samples, entry->period, weight);
return 0;
}
@@ -402,18 +405,18 @@ static int symbol__account_cycles(u64 addr, u64 start, struct symbol *sym,
branch = symbol__find_branch_hist(sym, evlist__nr_br_cntr(evsel->evlist));
if (!branch)
return -ENOMEM;
- if (addr < sym->start || addr >= sym->end)
+ if (addr < symbol__start(sym) || addr >= symbol__end(sym))
return -ERANGE;
if (start) {
- if (start < sym->start || start >= sym->end)
+ if (start < symbol__start(sym) || start >= symbol__end(sym))
return -ERANGE;
if (start >= addr)
start = 0;
}
- offset = addr - sym->start;
+ offset = addr - symbol__start(sym);
ret = __symbol__account_cycles(branch->cycles_hist,
- start ? start - sym->start : 0,
+ start ? start - symbol__start(sym) : 0,
offset, cycles,
!!start);
@@ -445,13 +448,13 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
if (start &&
(start->ms.sym == ams->ms.sym ||
(ams->ms.sym &&
- start->addr == ams->ms.sym->start + map__start(ams->ms.map))))
+ start->addr == symbol__start(ams->ms.sym) + map__start(ams->ms.map))))
saddr = start->al_addr;
if (saddr == 0)
pr_debug2("BB with bad start: addr %"PRIx64" start %"PRIx64" sym %"PRIx64" saddr %"PRIx64"\n",
ams->addr,
start ? start->addr : 0,
- ams->ms.sym ? ams->ms.sym->start + map__start(ams->ms.map) : 0,
+ ams->ms.sym ? symbol__start(ams->ms.sym) + map__start(ams->ms.map) : 0,
saddr);
err = symbol__account_cycles(ams->al_addr, saddr, ams->ms.sym, cycles, evsel, br_cntr);
if (err)
@@ -1165,9 +1168,11 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
notes->src->nr_events = nr ? nr : 1;
if (annotate_opts.full_addr)
- notes->src->start = map__objdump_2mem(ms->map, ms->sym->start);
+ notes->src->start = map__objdump_2mem(ms->map,
+ symbol__start(ms->sym));
else
- notes->src->start = map__rip_2objdump(ms->map, ms->sym->start);
+ notes->src->start = map__rip_2objdump(ms->map,
+ symbol__start(ms->sym));
return symbol__disassemble(sym, &args);
}
@@ -1309,7 +1314,7 @@ static void symbol__annotate_hits(struct symbol *sym, struct evsel *evsel)
entry = annotated_source__hist_entry(notes->src, evsel, offset);
if (entry && entry->nr_samples != 0)
printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
- sym->start + offset, entry->nr_samples);
+ symbol__start(sym) + offset, entry->nr_samples);
}
printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples);
}
@@ -1521,7 +1526,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel,
.evsel = evsel,
};
- if (asprintf(&filename, "%s.annotation", ms->sym->name) < 0)
+ if (asprintf(&filename, "%s.annotation", symbol__name(ms->sym)) < 0)
return -1;
fp = fopen(filename, "w");
@@ -1534,7 +1539,8 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel,
}
fprintf(fp, "%s() %s\nEvent: %s\n\n",
- ms->sym->name, dso__long_name(map__dso(ms->map)), ev_name);
+ symbol__name(ms->sym), dso__long_name(map__dso(ms->map)),
+ ev_name);
symbol__annotate_fprintf2(ms->sym, fp, &apd);
fclose(fp);
@@ -1629,7 +1635,7 @@ annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym)
struct annotation_line *al;
/* PLT symbols contain external offsets */
- if (strstr(sym->name, "@plt"))
+ if (strstr(symbol__name(sym), "@plt"))
return;
list_for_each_entry(al, ¬es->src->source, node) {
@@ -1708,7 +1714,7 @@ annotation__init_column_widths(struct annotation *notes, struct symbol *sym)
{
notes->src->widths.addr = notes->src->widths.target =
notes->src->widths.min_addr = hex_width(symbol__size(sym));
- notes->src->widths.max_addr = hex_width(sym->end);
+ notes->src->widths.max_addr = hex_width(symbol__end(sym));
notes->src->widths.jumps = width_jumps(notes->src->max_jump_sources);
notes->src->widths.max_ins_name = annotation__max_ins_name(notes);
}
@@ -1733,9 +1739,11 @@ void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *m
annotate_opts.full_addr = !annotate_opts.full_addr;
if (annotate_opts.full_addr)
- notes->src->start = map__objdump_2mem(ms->map, ms->sym->start);
+ notes->src->start = map__objdump_2mem(ms->map,
+ symbol__start(ms->sym));
else
- notes->src->start = map__rip_2objdump(ms->map, ms->sym->start);
+ notes->src->start = map__rip_2objdump(ms->map,
+ symbol__start(ms->sym));
annotation__update_column_widths(notes);
}
@@ -1764,9 +1772,10 @@ static void annotation__calc_lines(struct annotation *notes, struct map_symbol *
if (percent_max <= 0.5)
continue;
- addr = map__rip_2objdump(ms->map, ms->sym->start);
+ addr = map__rip_2objdump(ms->map, symbol__start(ms->sym));
al->path = get_srcline(map__dso(ms->map), addr + al->offset, NULL,
- false, true, ms->sym->start + al->offset);
+ false, true,
+ symbol__start(ms->sym) + al->offset);
insert_source_line(&tmp_root, al);
}
@@ -1800,7 +1809,7 @@ int hist_entry__tty_annotate2(struct hist_entry *he, struct evsel *evsel)
dso__set_annotate_warned(dso);
symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
- ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
+ ui__error("Couldn't annotate %s:\n%s", symbol__name(sym), msg);
return -1;
}
@@ -1812,7 +1821,8 @@ int hist_entry__tty_annotate2(struct hist_entry *he, struct evsel *evsel)
hists__scnprintf_title(hists, buf, sizeof(buf));
fprintf(stdout, "%s, [percent: %s]\n%s() %s\n",
- buf, percent_type_str(annotate_opts.percent_type), sym->name, dso__long_name(dso));
+ buf, percent_type_str(annotate_opts.percent_type),
+ symbol__name(sym), dso__long_name(dso));
symbol__annotate_fprintf2(sym, stdout, &apd);
annotated_source__purge(symbol__annotation(sym)->src);
@@ -1834,7 +1844,7 @@ int hist_entry__tty_annotate(struct hist_entry *he, struct evsel *evsel)
dso__set_annotate_warned(dso);
symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
- ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
+ ui__error("Couldn't annotate %s:\n%s", symbol__name(sym), msg);
return -1;
}
@@ -2682,7 +2692,7 @@ static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip,
if (dl->al.offset == -1)
continue;
- if (sym->start + dl->al.offset == ip) {
+ if (symbol__start(sym) + dl->al.offset == ip) {
/*
* llvm-objdump places "lock" in a separate line and
* in that case, we want to get the next line.
@@ -2818,7 +2828,7 @@ u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset,
*/
next = annotation__next_asm_line(notes, dl);
if (next == NULL)
- addr = ms->sym->end + offset;
+ addr = symbol__end(ms->sym) + offset;
else
addr = ip + (next->al.offset - dl->al.offset) + offset;
@@ -2880,7 +2890,7 @@ __hist_entry__get_data_type(struct hist_entry *he, const struct arch *arch,
.arch = arch,
.thread = he->thread,
.ms = ms,
- .ip = ms->sym->start + dl->al.offset,
+ .ip = symbol__start(ms->sym) + dl->al.offset,
.cpumode = he->cpumode,
.op = op_loc,
.di = dbg,
@@ -3134,7 +3144,7 @@ static bool process_basic_block(struct basic_block_data *bb_data,
if (dl->al.offset == -1)
continue;
/* Found the target instruction */
- if (sym->start + dl->al.offset == target) {
+ if (symbol__start(sym) + dl->al.offset == target) {
found = true;
break;
}
@@ -3151,7 +3161,8 @@ static bool process_basic_block(struct basic_block_data *bb_data,
if (dl->ops.target.outside)
break;
/* jump instruction creates new basic block(s) */
- next_dl = find_disasm_line(sym, sym->start + dl->ops.target.offset,
+ next_dl = find_disasm_line(sym,
+ symbol__start(sym) + dl->ops.target.offset,
/*allow_update=*/false);
if (next_dl)
add_basic_block(bb_data, link, next_dl);
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index ed2113190785..f4aee90b43a3 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -2707,7 +2707,7 @@ static bool dso_sym_match(struct symbol *sym, const char *name, int *cnt,
int idx)
{
/* Same name, and global or the n'th found or any */
- return !arch__compare_symbol_names(name, sym->name) &&
+ return !arch__compare_symbol_names(name, symbol__name(sym)) &&
((!idx && symbol__binding(sym) == STB_GLOBAL) ||
(idx > 0 && ++*cnt == idx) ||
idx < 0);
@@ -2725,14 +2725,14 @@ static void print_duplicate_syms(struct dso *dso, const char *sym_name)
while (sym) {
if (dso_sym_match(sym, sym_name, &cnt, -1)) {
pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n",
- ++cnt, sym->start,
+ ++cnt, symbol__start(sym),
symbol__binding(sym) == STB_GLOBAL ? 'g' :
symbol__binding(sym) == STB_LOCAL ? 'l' : 'w',
- sym->name);
+ symbol__name(sym));
near = true;
} else if (near) {
near = false;
- pr_err("\t\twhich is near\t\t%s\n", sym->name);
+ pr_err("\t\twhich is near\t\t%s\n", symbol__name(sym));
}
sym = dso__next_symbol(sym);
}
@@ -2755,7 +2755,7 @@ static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start,
while (sym) {
if (*start) {
if (!*size)
- *size = sym->start - *start;
+ *size = symbol__start(sym) - *start;
if (idx > 0) {
if (*size)
return 0;
@@ -2764,8 +2764,8 @@ static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start,
return -EINVAL;
}
} else if (dso_sym_match(sym, sym_name, &cnt, idx)) {
- *start = sym->start;
- *size = sym->end - sym->start;
+ *start = symbol__start(sym);
+ *size = symbol__end(sym) - symbol__start(sym);
}
sym = dso__next_symbol(sym);
}
diff --git a/tools/perf/util/block-info.c b/tools/perf/util/block-info.c
index 1135e54f4c7f..5dec6c9dc1a7 100644
--- a/tools/perf/util/block-info.c
+++ b/tools/perf/util/block-info.c
@@ -84,7 +84,7 @@ int64_t __block_info__cmp(struct hist_entry *left, struct hist_entry *right)
return 1;
}
- cmp = strcmp(bi_l->sym->name, bi_r->sym->name);
+ cmp = strcmp(symbol__name(bi_l->sym), symbol__name(bi_r->sym));
if (cmp)
return cmp;
@@ -305,10 +305,11 @@ static int block_range_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
symbol_conf.addr2line_disable_warn = true;
- start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
+ start_line = map__srcline(he->ms.map,
+ symbol__start(bi->sym) + bi->start,
he->ms.sym);
- end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
+ end_line = map__srcline(he->ms.map, symbol__start(bi->sym) + bi->end,
he->ms.sym);
if (start_line != SRCLINE_UNKNOWN &&
diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
index c20bd075664e..9832c45857d1 100644
--- a/tools/perf/util/bpf_lock_contention.c
+++ b/tools/perf/util/bpf_lock_contention.c
@@ -143,7 +143,8 @@ static void init_numa_data(struct lock_contention *con)
"contig_page_data",
&kmap);
if (sym) {
- skel->rodata->contig_page_data_addr = map__unmap_ip(kmap, sym->start);
+ skel->rodata->contig_page_data_addr = map__unmap_ip(kmap,
+ symbol__start(sym));
map__put(kmap);
return;
}
@@ -159,7 +160,7 @@ static void init_numa_data(struct lock_contention *con)
if (sym == NULL)
return;
- skel->rodata->node_data_addr = map__unmap_ip(kmap, sym->start);
+ skel->rodata->node_data_addr = map__unmap_ip(kmap, symbol__start(sym));
map__put(kmap);
/* get the number of online nodes using the last node number + 1 */
@@ -266,7 +267,8 @@ int lock_contention_prepare(struct lock_contention *con)
continue;
}
- addrs[con->filters->nr_addrs++] = map__unmap_ip(kmap, sym->start);
+ addrs[con->filters->nr_addrs++] = map__unmap_ip(kmap,
+ symbol__start(sym));
con->filters->addrs = addrs;
}
naddrs = con->filters->nr_addrs ?: has_mmap_lock;
@@ -288,7 +290,8 @@ int lock_contention_prepare(struct lock_contention *con)
continue;
}
- con->delays[i].addr = map__unmap_ip(kmap, sym->start);
+ con->delays[i].addr = map__unmap_ip(kmap,
+ symbol__start(sym));
}
skel->rodata->lock_delay = 1;
bpf_map__set_max_entries(skel->maps.lock_delays, con->nr_delays);
@@ -608,7 +611,7 @@ static const char *lock_contention_get_name(struct lock_contention *con,
/* global locks with symbols */
sym = machine__find_kernel_symbol(machine, key->lock_addr_or_cgroup, &kmap);
if (sym)
- return sym->name;
+ return symbol__name(sym);
/* try semi-global locks collected separately */
if (!bpf_map_lookup_elem(lock_fd, &key->lock_addr_or_cgroup, &flags)) {
@@ -652,12 +655,13 @@ static const char *lock_contention_get_name(struct lock_contention *con,
if (sym) {
unsigned long offset;
- offset = map__map_ip(kmap, addr) - sym->start;
+ offset = map__map_ip(kmap, addr) - symbol__start(sym);
if (offset == 0)
- return sym->name;
+ return symbol__name(sym);
- snprintf(name_buf, sizeof(name_buf), "%s+%#lx", sym->name, offset);
+ snprintf(name_buf, sizeof(name_buf), "%s+%#lx",
+ symbol__name(sym), offset);
} else {
snprintf(name_buf, sizeof(name_buf), "%#lx", (unsigned long)addr);
}
diff --git a/tools/perf/util/c2c-function.c b/tools/perf/util/c2c-function.c
index d410196d0429..0c50d816653f 100644
--- a/tools/perf/util/c2c-function.c
+++ b/tools/perf/util/c2c-function.c
@@ -966,7 +966,7 @@ c2c_function_hists__level1_entry(struct symbol *sym,
* true "function view" rather than a per-code-address view.
*/
u64 sym_start = (sym && detail_he->ms.map) ?
- map__unmap_ip(detail_he->ms.map, sym->start) : detail_he->ip;
+ map__unmap_ip(detail_he->ms.map, symbol__start(sym)) : detail_he->ip;
mi = mem_info__new();
if (!mi)
@@ -1058,8 +1058,8 @@ c2c_function_hists__level2_entry(struct c2c_hist_entry *level1_c2c,
/* Key by the function symbol start so all code addresses collapse. */
level2_c2c = c2c_child_entry__alloc(level1_he, detail_he, 1,
(sym && detail_he->ms.map) ?
- map__unmap_ip(detail_he->ms.map, sym->start) :
- hist_entry__iaddr(detail_he));
+ map__unmap_ip(detail_he->ms.map, symbol__start(sym)) :
+ hist_entry__iaddr(detail_he));
if (!level2_c2c)
return NULL;
@@ -1181,8 +1181,8 @@ static void c2c_he__resort_by_stores(struct hist_entry *parent_he)
if (a != b)
cmp = a < b ? -1 : 1;
else if (he->ms.sym && iter->ms.sym)
- cmp = strcmp(he->ms.sym->name,
- iter->ms.sym->name);
+ cmp = strcmp(symbol__name(he->ms.sym),
+ symbol__name(iter->ms.sym));
else
cmp = (iter->ms.sym ? 1 : 0) - (he->ms.sym ? 1 : 0);
@@ -1407,7 +1407,7 @@ static int c2c_function__ident_len(struct hist_entry *he)
* Match symbol_view_entry(): sort_sym adds the cpumode prefix and, in
* verbose mode, the address and DSO origin before the symbol name.
*/
- size = strlen(he->ms.sym->name) + 64;
+ size = strlen(symbol__name(he->ms.sym)) + 64;
symbuf = malloc(size);
if (!symbuf)
return size - 1;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 31c675cbab63..993b7c744a89 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -802,13 +802,15 @@ static enum match_result match_chain(struct callchain_cursor_node *node,
* on the symbol start address.
*/
if (symbol__inlined(cnode->ms.sym) || symbol__inlined(node->ms.sym)) {
- match = match_chain_strings(cnode->ms.sym->name,
- node->ms.sym->name);
+ match = match_chain_strings(symbol__name(cnode->ms.sym),
+ symbol__name(node->ms.sym));
if (match != MATCH_ERROR)
break;
} else {
- match = match_chain_dso_addresses(cnode->ms.map, cnode->ms.sym->start,
- node->ms.map, node->ms.sym->start);
+ match = match_chain_dso_addresses(cnode->ms.map,
+ symbol__start(cnode->ms.sym),
+ node->ms.map,
+ symbol__start(node->ms.sym));
break;
}
}
@@ -1249,11 +1251,12 @@ char *callchain_list__sym_name(struct callchain_list *cl,
if (show_srcline && cl->srcline)
printed = scnprintf(bf, bfsize, "%s %s%s",
- cl->ms.sym->name, cl->srcline,
+ symbol__name(cl->ms.sym),
+ cl->srcline,
inlined);
else
printed = scnprintf(bf, bfsize, "%s%s",
- cl->ms.sym->name, inlined);
+ symbol__name(cl->ms.sym), inlined);
} else
printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c
index 95881f15324a..422a48385b78 100644
--- a/tools/perf/util/capstone.c
+++ b/tools/perf/util/capstone.c
@@ -333,7 +333,7 @@ static struct symbol *find_symbol_from_addr(struct map *map, u64 addr,
return NULL;
}
- *sym_offset = al_addr - sym->start;
+ *sym_offset = al_addr - symbol__start(sym);
return sym;
}
@@ -368,10 +368,10 @@ static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len,
if (sym_offset == 0) {
scnprintf(buf, len, "\t# %"PRIx64" <%s>",
- orig_addr, sym->name);
+ orig_addr, symbol__name(sym));
} else {
scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">",
- orig_addr, sym->name, sym_offset);
+ orig_addr, symbol__name(sym), sym_offset);
}
map__put(found_map);
break;
@@ -454,10 +454,10 @@ static void format_capstone_insn_arm64(struct cs_insn *insn, char *buf,
len = len - (last_imm - buf);
if (sym_offset == 0) {
scnprintf(last_imm, len, "%"PRIx64" <%s>",
- addr, sym->name);
+ addr, symbol__name(sym));
} else {
scnprintf(last_imm, len, "%"PRIx64" <%s+%#"PRIx64">",
- addr, sym->name, sym_offset);
+ addr, symbol__name(sym), sym_offset);
}
map__put(found_map);
}
@@ -498,7 +498,7 @@ int symbol__disassemble_capstone(const char *filename, struct symbol *sym,
struct annotation *notes = symbol__annotation(sym);
struct map *map = args->ms->map;
struct dso *dso = map__dso(map);
- u64 start = map__rip_2objdump(map, sym->start);
+ u64 start = map__rip_2objdump(map, symbol__start(sym));
u64 offset;
int i, count, free_count;
bool is_64bit = false;
@@ -526,7 +526,7 @@ int symbol__disassemble_capstone(const char *filename, struct symbol *sym,
/* add the function address and name */
scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
- start, sym->name);
+ start, symbol__name(sym));
args->offset = -1;
args->line = disasm_buf;
@@ -631,8 +631,8 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
struct map *map = args->ms->map;
struct dso *dso = map__dso(map);
struct nscookie nsc;
- u64 start = map__rip_2objdump(map, sym->start);
- u64 end = map__rip_2objdump(map, sym->end);
+ u64 start = map__rip_2objdump(map, symbol__start(sym));
+ u64 end = map__rip_2objdump(map, symbol__end(sym));
u64 len = end - start;
u64 offset;
int i, fd, count;
@@ -703,7 +703,7 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
/* add the function address and name */
scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
- start, sym->name);
+ start, symbol__name(sym));
args->offset = -1;
args->line = disasm_buf;
diff --git a/tools/perf/util/data-convert-json.c b/tools/perf/util/data-convert-json.c
index 40888b7c4467..c09bd77f5665 100644
--- a/tools/perf/util/data-convert-json.c
+++ b/tools/perf/util/data-convert-json.c
@@ -138,11 +138,11 @@ static void output_sample_callchain_entry(const struct perf_tool *tool,
output_json_format(out, false, 4, "{");
output_json_key_format(out, false, 5, "ip", "\"0x%" PRIx64 "\"", ip);
- if (al && al->sym && al->sym->namelen) {
+ if (al && al->sym && symbol__namelen(al->sym)) {
struct dso *dso = al->map ? map__dso(al->map) : NULL;
fputc(',', out);
- output_json_key_string(out, false, 5, "symbol", al->sym->name);
+ output_json_key_string(out, false, 5, "symbol", symbol__name(al->sym));
if (dso) {
const char *dso_name = dso__short_name(dso);
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index ba54b1119ee6..732369fe0046 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -198,7 +198,7 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
if (err)
return err;
*sym_db_id = *db_id;
- *offset = al->addr - al->sym->start;
+ *offset = al->addr - symbol__start(al->sym);
}
}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 6b5ffe81f141..e43bfb741dd1 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -342,7 +342,8 @@ void __dump_stack(FILE *file, void **stackdump, size_t stackdump_size)
if (thread && thread__find_map(thread, PERF_RECORD_MISC_USER, addr, &al)) {
al.sym = map__find_symbol(al.map, al.addr);
if (al.sym) {
- fprintf(file, " #%zd %p in %s ", i, stackdump[i], al.sym->name);
+ fprintf(file, " #%zd %p in %s ", i, stackdump[i],
+ symbol__name(al.sym));
printed = true;
}
}
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 5478c134e7e3..78b8811dcaa4 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -312,7 +312,8 @@ int call__scnprintf(const struct ins *ins, char *bf, size_t size,
struct ins_operands *ops, int max_ins_name)
{
if (ops->target.sym)
- return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name);
+ return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name,
+ symbol__name(ops->target.sym));
if (ops->target.addr == 0)
return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
@@ -399,8 +400,8 @@ static int jump__parse(const struct arch *arch, struct ins_operands *ops, struct
}
target.addr = map__objdump_2mem(map, ops->target.addr);
- start = map__unmap_ip(map, sym->start);
- end = map__unmap_ip(map, sym->end);
+ start = map__unmap_ip(map, symbol__start(sym));
+ end = map__unmap_ip(map, symbol__end(sym));
ops->target.outside = target.addr < start || target.addr >= end;
@@ -445,7 +446,8 @@ int jump__scnprintf(const struct ins *ins, char *bf, size_t size,
return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
if (ops->target.outside && ops->target.sym != NULL)
- return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name);
+ return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name,
+ symbol__name(ops->target.sym));
c = strchr(ops->raw, ',');
c = validate_comma(c, ops);
@@ -1050,8 +1052,8 @@ static int symbol__parse_objdump_line(struct symbol *sym,
/* Process hex address followed by ':'. */
line_ip = strtoull(parsed_line, &tmp, 16);
if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') {
- u64 start = map__rip_2objdump(map, sym->start),
- end = map__rip_2objdump(map, sym->end);
+ u64 start = map__rip_2objdump(map, symbol__start(sym)),
+ end = map__rip_2objdump(map, symbol__end(sym));
offset = line_ip - start;
if ((u64)line_ip < start || (u64)line_ip >= end)
@@ -1074,7 +1076,8 @@ static int symbol__parse_objdump_line(struct symbol *sym,
if (!disasm_line__has_local_offset(dl)) {
dl->ops.target.offset = dl->ops.target.addr -
- map__rip_2objdump(map, sym->start);
+ map__rip_2objdump(map,
+ symbol__start(sym));
dl->ops.target.offset_avail = true;
}
@@ -1086,7 +1089,7 @@ static int symbol__parse_objdump_line(struct symbol *sym,
};
if (!maps__find_ams(thread__maps(args->ms->thread), &target) &&
- target.ms.sym->start == target.al_addr)
+ symbol__start(target.ms.sym) == target.al_addr)
dl->ops.target.sym = target.ms.sym;
addr_map_symbol__exit(&target);
@@ -1260,8 +1263,8 @@ static int symbol__disassemble_raw(char *filename, struct symbol *sym,
struct annotation *notes = symbol__annotation(sym);
struct map *map = args->ms->map;
struct dso *dso = map__dso(map);
- u64 start = map__rip_2objdump(map, sym->start);
- u64 end = map__rip_2objdump(map, sym->end);
+ u64 start = map__rip_2objdump(map, symbol__start(sym));
+ u64 end = map__rip_2objdump(map, symbol__end(sym));
u64 len = end - start;
u64 offset;
int i, count;
@@ -1280,7 +1283,7 @@ static int symbol__disassemble_raw(char *filename, struct symbol *sym,
if (buf == NULL)
goto err;
- count = dso__data_read_offset(dso, NULL, sym->start, buf, len);
+ count = dso__data_read_offset(dso, NULL, symbol__start(sym), buf, len);
line = (u32 *)buf;
@@ -1289,7 +1292,7 @@ static int symbol__disassemble_raw(char *filename, struct symbol *sym,
/* add the function address and name */
scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
- start, sym->name);
+ start, symbol__name(sym));
args->offset = -1;
args->line = disasm_buf;
@@ -1454,8 +1457,8 @@ static int symbol__disassemble_objdump(const char *filename, struct symbol *sym,
opts->objdump_path ?: "objdump",
opts->disassembler_style ? "-M " : "",
opts->disassembler_style ?: "",
- map__rip_2objdump(map, sym->start),
- map__rip_2objdump(map, sym->end),
+ map__rip_2objdump(map, symbol__start(sym)),
+ map__rip_2objdump(map, symbol__end(sym)),
opts->show_linenr ? "-l" : "",
opts->show_asm_raw ? "" : "--no-show-raw-insn",
opts->annotate_src ? "-S" : "",
@@ -1576,18 +1579,20 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
return err;
pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
- symfs_filename, sym->name, map__unmap_ip(map, sym->start),
- map__unmap_ip(map, sym->end));
+ symfs_filename, symbol__name(sym),
+ map__unmap_ip(map, symbol__start(sym)),
+ map__unmap_ip(map, symbol__end(sym)));
- pr_debug("annotating [%p] %30s : [%p] %30s\n", dso, dso__long_name(dso), sym, sym->name);
+ pr_debug("annotating [%p] %30s : [%p] %30s\n", dso, dso__long_name(dso), sym,
+ symbol__name(sym));
if (dso__binary_type(dso) == DSO_BINARY_TYPE__NOT_FOUND) {
return SYMBOL_ANNOTATE_ERRNO__COULDNT_DETERMINE_FILE_TYPE;
} else if (dso__is_kcore(dso)) {
- kce.addr = map__rip_2objdump(map, sym->start);
+ kce.addr = map__rip_2objdump(map, symbol__start(sym));
kce.kcore_filename = symfs_filename;
- kce.len = sym->end - sym->start;
- kce.offs = sym->start;
+ kce.len = symbol__end(sym) - symbol__start(sym);
+ kce.offs = symbol__start(sym);
if (!kcore_extract__create(&kce)) {
delete_extract = true;
diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c
index e11e144af62b..3b72cb7b412e 100644
--- a/tools/perf/util/dlfilter.c
+++ b/tools/perf/util/dlfilter.c
@@ -47,13 +47,13 @@ static void al_to_d_al(struct addr_location *al, struct perf_dlfilter_al *d_al)
d_al->buildid = NULL;
}
if (sym) {
- d_al->sym = sym->name;
- d_al->sym_start = sym->start;
- d_al->sym_end = sym->end;
- if (al->addr < sym->end)
- d_al->symoff = al->addr - sym->start;
+ d_al->sym = symbol__name(sym);
+ d_al->sym_start = symbol__start(sym);
+ d_al->sym_end = symbol__end(sym);
+ if (al->addr < symbol__end(sym))
+ d_al->symoff = al->addr - symbol__start(sym);
else if (al->map)
- d_al->symoff = al->addr - map__start(al->map) - sym->start;
+ d_al->symoff = al->addr - map__start(al->map) - symbol__start(sym);
else
d_al->symoff = 0;
d_al->sym_binding = symbol__binding(sym);
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 11db461f2032..39cb82693596 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -2027,8 +2027,8 @@ const u8 *dso__read_symbol(struct dso *dso, const char *symfs_filename,
const struct map *map, const struct symbol *sym,
u8 **out_buf, u64 *out_buf_len, bool *is_64bit)
{
- u64 start = map__rip_2objdump(map, sym->start);
- u64 end = map__rip_2objdump(map, sym->end);
+ u64 start = map__rip_2objdump(map, symbol__start(sym));
+ u64 end = map__rip_2objdump(map, symbol__end(sym));
size_t len = end - start;
*out_buf = NULL;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index ea75816d126a..939307796a88 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -884,11 +884,11 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
if (al->sym) {
ret = strlist__has_entry(symbol_conf.sym_list,
- al->sym->name);
+ symbol__name(al->sym));
}
if (!ret && al->sym) {
snprintf(al_addr_str, sz, "0x%"PRIx64,
- map__unmap_ip(al->map, al->sym->start));
+ map__unmap_ip(al->map, symbol__start(al->sym)));
ret = strlist__has_entry(symbol_conf.sym_list,
al_addr_str);
}
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
index 0f7a25500a44..76a0c69e6f45 100644
--- a/tools/perf/util/evsel_fprintf.c
+++ b/tools/perf/util/evsel_fprintf.c
@@ -200,7 +200,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
/* Add srccode here too? */
if (bt_stop_list && sym &&
- strlist__has_entry(bt_stop_list, sym->name)) {
+ strlist__has_entry(bt_stop_list, symbol__name(sym))) {
break;
}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 443694926f1a..dd388169c25b 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -97,7 +97,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
* +3 accounts for ' y ' symtab origin info
*/
if (h->ms.sym) {
- symlen = h->ms.sym->namelen + 4;
+ symlen = symbol__namelen(h->ms.sym) + 4;
if (verbose > 0)
symlen += BITS_PER_LONG / 4 + 2 + 3;
hists__new_col_len(hists, HISTC_SYMBOL, symlen);
@@ -120,11 +120,12 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
}
if (h->parent)
- hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
+ hists__new_col_len(hists, HISTC_PARENT,
+ symbol__namelen(h->parent));
if (h->branch_info) {
if (h->branch_info->from.ms.sym) {
- symlen = (int)h->branch_info->from.ms.sym->namelen + 4;
+ symlen = (int) symbol__namelen(h->branch_info->from.ms.sym) + 4;
if (verbose > 0)
symlen += BITS_PER_LONG / 4 + 2 + 3;
hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
@@ -139,7 +140,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
}
if (h->branch_info->to.ms.sym) {
- symlen = (int)h->branch_info->to.ms.sym->namelen + 4;
+ symlen = (int) symbol__namelen(h->branch_info->to.ms.sym) + 4;
if (verbose > 0)
symlen += BITS_PER_LONG / 4 + 2 + 3;
hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
@@ -163,7 +164,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
if (h->mem_info) {
if (mem_info__daddr(h->mem_info)->ms.sym) {
- symlen = (int)mem_info__daddr(h->mem_info)->ms.sym->namelen + 4
+ symlen = (int) symbol__namelen(mem_info__daddr(h->mem_info)->ms.sym) + 4
+ unresolved_col_width + 2;
hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
symlen);
@@ -178,7 +179,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
}
if (mem_info__iaddr(h->mem_info)->ms.sym) {
- symlen = (int)mem_info__iaddr(h->mem_info)->ms.sym->namelen + 4
+ symlen = (int) symbol__namelen(mem_info__iaddr(h->mem_info)->ms.sym) + 4
+ unresolved_col_width + 2;
hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
symlen);
@@ -725,7 +726,7 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
*/
if (hists__has(hists, sym) && he->ms.map != entry->ms.map) {
if (he->ms.sym) {
- u64 addr = he->ms.sym->start;
+ u64 addr = symbol__start(he->ms.sym);
he->ms.sym = map__find_symbol(entry->ms.map, addr);
}
@@ -2298,7 +2299,7 @@ static bool hists__filter_entry_by_symbol(struct hists *hists,
struct hist_entry *he)
{
if (hists->symbol_filter_str != NULL &&
- (!he->ms.sym || strstr(he->ms.sym->name,
+ (!he->ms.sym || strstr(symbol__name(he->ms.sym),
hists->symbol_filter_str) == NULL)) {
he->filtered |= (1 << HIST_FILTER__SYMBOL);
return true;
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index 8c21c9f52d57..a9f43ac8d152 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -3003,8 +3003,8 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
for (sym = start; sym; sym = dso__next_symbol(sym)) {
if (symbol__binding(sym) == STB_GLOBAL &&
- !strcmp(sym->name, "__switch_to")) {
- ip = map__unmap_ip(map, sym->start);
+ !strcmp(symbol__name(sym), "__switch_to")) {
+ ip = map__unmap_ip(map, symbol__start(sym));
if (ip >= map__start(map) && ip < map__end(map)) {
switch_ip = ip;
break;
@@ -3021,8 +3021,8 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
ptss = "__perf_event_task_sched_out";
for (sym = start; sym; sym = dso__next_symbol(sym)) {
- if (!strcmp(sym->name, ptss)) {
- ip = map__unmap_ip(map, sym->start);
+ if (!strcmp(symbol__name(sym), ptss)) {
+ ip = map__unmap_ip(map, symbol__start(sym));
if (ip >= map__start(map) && ip < map__end(map)) {
*ptss_ip = ip;
break;
diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c
index a907d7c1ac94..d4b496bb9426 100644
--- a/tools/perf/util/libbfd.c
+++ b/tools/perf/util/libbfd.c
@@ -552,7 +552,7 @@ int symbol__disassemble_bpf_libbfd(struct symbol *sym __maybe_unused,
struct annotation *notes = symbol__annotation(sym);
struct bpf_prog_linfo *prog_linfo = NULL;
struct bpf_prog_info_node *info_node;
- int len = sym->end - sym->start;
+ int len = symbol__end(sym) - symbol__start(sym);
disassembler_ftype disassemble;
struct map *map = args->ms->map;
struct perf_bpil *info_linear;
@@ -572,7 +572,8 @@ int symbol__disassemble_bpf_libbfd(struct symbol *sym __maybe_unused,
return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE;
pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__,
- sym->name, sym->start, sym->end - sym->start);
+ symbol__name(sym), symbol__start(sym),
+ symbol__end(sym) - symbol__start(sym));
memset(tpath, 0, sizeof(tpath));
perf_exe(tpath, sizeof(tpath));
diff --git a/tools/perf/util/llvm.c b/tools/perf/util/llvm.c
index 722e71aab100..e90b0d55070e 100644
--- a/tools/perf/util/llvm.c
+++ b/tools/perf/util/llvm.c
@@ -132,7 +132,7 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
struct annotation *notes = symbol__annotation(sym);
struct map *map = args->ms->map;
struct dso *dso = map__dso(map);
- u64 start = map__rip_2objdump(map, sym->start);
+ u64 start = map__rip_2objdump(map, symbol__start(sym));
/* Malloc-ed buffer containing instructions read from disk. */
u8 *code_buf = NULL;
/* Pointer to code to be disassembled. */
@@ -196,7 +196,7 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
/* add the function address and name */
scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
- start, sym->name);
+ start, symbol__name(sym));
args->offset = -1;
args->line = disasm_buf;
@@ -317,7 +317,7 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
return ret;
#else // HAVE_LIBLLVM_SUPPORT
pr_debug("The LLVM disassembler isn't linked in for %s in %s\n",
- sym->name, filename);
+ symbol__name(sym), filename);
return -1;
#endif
}
diff --git a/tools/perf/util/lock-contention.c b/tools/perf/util/lock-contention.c
index 119a7206f3cd..8ee1b19a8292 100644
--- a/tools/perf/util/lock-contention.c
+++ b/tools/perf/util/lock-contention.c
@@ -135,7 +135,7 @@ bool match_callstack_filter(struct machine *machine, u64 *callstack, int max_sta
continue;
list_for_each_entry(filter, &callstack_filters, list) {
- if (strstr(sym->name, filter->name))
+ if (strstr(symbol__name(sym), filter->name))
return true;
}
}
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 1d9d3bf57720..fa2bd8e0e1f1 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1110,8 +1110,8 @@ static u64 find_entry_trampoline(struct dso *dso)
if (symbol__binding(sym) != STB_GLOBAL)
continue;
for (i = 0; i < ARRAY_SIZE(syms); i++) {
- if (!strcmp(sym->name, syms[i]))
- return sym->start;
+ if (!strcmp(symbol__name(sym), syms[i]))
+ return symbol__start(sym);
}
}
@@ -2056,7 +2056,7 @@ int machine__process_event(struct machine *machine, union perf_event *event,
static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
{
- return regexec(regex, sym->name, 0, NULL, 0) == 0;
+ return regexec(regex, symbol__name(sym), 0, NULL, 0) == 0;
}
static void ip__resolve_ams(struct thread *thread,
@@ -3283,8 +3283,8 @@ char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, ch
return NULL;
*modp = __map__is_kmodule(map) ? (char *)dso__short_name(map__dso(map)) : NULL;
- *addrp = map__unmap_ip(map, sym->start);
- return sym->name;
+ *addrp = map__unmap_ip(map, symbol__start(sym));
+ return (char *)symbol__name(sym);
}
struct machine__for_each_dso_cb_args {
@@ -3330,27 +3330,35 @@ bool machine__is_lock_function(struct machine *machine, u64 addr)
return false;
}
- machine->sched.text_start = map__unmap_ip(kmap, sym->start);
+ machine->sched.text_start = map__unmap_ip(kmap,
+ symbol__start(sym));
/* should not fail from here */
sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_end", &kmap);
- machine->sched.text_end = map__unmap_ip(kmap, sym->start);
+ machine->sched.text_end = map__unmap_ip(kmap,
+ symbol__start(sym));
sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_start", &kmap);
- machine->lock.text_start = map__unmap_ip(kmap, sym->start);
+ machine->lock.text_start = map__unmap_ip(kmap,
+ symbol__start(sym));
sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_end", &kmap);
- machine->lock.text_end = map__unmap_ip(kmap, sym->start);
+ machine->lock.text_end = map__unmap_ip(kmap,
+ symbol__start(sym));
sym = machine__find_kernel_symbol_by_name(machine, "__traceiter_contention_begin", &kmap);
if (sym) {
- machine->traceiter.text_start = map__unmap_ip(kmap, sym->start);
- machine->traceiter.text_end = map__unmap_ip(kmap, sym->end);
+ machine->traceiter.text_start = map__unmap_ip(kmap,
+ symbol__start(sym));
+ machine->traceiter.text_end = map__unmap_ip(kmap,
+ symbol__end(sym));
}
sym = machine__find_kernel_symbol_by_name(machine, "trace_contention_begin", &kmap);
if (sym) {
- machine->trace.text_start = map__unmap_ip(kmap, sym->start);
- machine->trace.text_end = map__unmap_ip(kmap, sym->end);
+ machine->trace.text_start = map__unmap_ip(kmap,
+ symbol__start(sym));
+ machine->trace.text_end = map__unmap_ip(kmap,
+ symbol__end(sym));
}
}
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 41cdddc987ee..85216fa71f1a 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -321,7 +321,7 @@ void map__fixup_start(struct map *map)
if (nd != NULL) {
struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
- map__set_start(map, sym->start);
+ map__set_start(map, symbol__start(sym));
}
}
@@ -333,7 +333,7 @@ void map__fixup_end(struct map *map)
if (nd != NULL) {
struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
- map__set_end(map, sym->end);
+ map__set_end(map, symbol__end(sym));
}
}
@@ -606,7 +606,7 @@ u64 map__objdump_2rip(const struct map *map, u64 ip)
bool map__contains_symbol(const struct map *map, const struct symbol *sym)
{
- u64 ip = map__unmap_ip(map, sym->start);
+ u64 ip = map__unmap_ip(map, symbol__start(sym));
return ip >= map__start(map) && ip < map__end(map);
}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index fb0279810ae9..f49b4aaacf2f 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -164,7 +164,7 @@ struct thread;
#define __map__for_each_symbol_by_name(map, sym_name, pos, idx) \
for (pos = map__find_symbol_by_name_idx(map, sym_name, &idx); \
pos && \
- !symbol__match_symbol_name(pos->name, sym_name, \
+ !symbol__match_symbol_name(symbol__name(pos), sym_name, \
SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); \
pos = dso__next_symbol_by_name(map__dso(map), &idx))
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 11ae4a09412c..128076a4b92d 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -149,7 +149,7 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr,
sym = machine__find_kernel_symbol_by_name(host_machine, name, &map);
if (!sym)
return -ENOENT;
- *addr = map__unmap_ip(map, sym->start) -
+ *addr = map__unmap_ip(map, symbol__start(sym)) -
((reloc) ? 0 : map__reloc(map)) -
((reladdr) ? map__start(map) : 0);
}
@@ -415,13 +415,13 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
/* Find the address of given function */
map__for_each_symbol_by_name(map, pp->function, sym, idx) {
if (uprobes) {
- address = sym->start;
+ address = symbol__start(sym);
if (symbol__type(sym) == STT_GNU_IFUNC)
pr_warning("Warning: The probe function (%s) is a GNU indirect function.\n"
"Consider identifying the final function used at run time and set the probe directly on that.\n",
pp->function);
} else
- address = map__unmap_ip(map, sym->start) - map__reloc(map);
+ address = map__unmap_ip(map, symbol__start(sym)) - map__reloc(map);
break;
}
if (!address) {
@@ -721,17 +721,17 @@ static int post_process_probe_trace_point(struct probe_trace_point *tp,
return (symbol_conf.ignore_vmlinux_buildid) ? 0 : -ENOENT;
}
- if (strcmp(sym->name, tp->symbol)) {
+ if (strcmp(symbol__name(sym), tp->symbol)) {
/* If we have no realname, use symbol for it */
if (!tp->realname)
tp->realname = tp->symbol;
else
free(tp->symbol);
- tp->symbol = strdup(sym->name);
+ tp->symbol = strdup(symbol__name(sym));
if (!tp->symbol)
return -ENOMEM;
}
- tp->offset = addr - sym->start;
+ tp->offset = addr - symbol__start(sym);
tp->address -= offs;
return 0;
@@ -2309,8 +2309,8 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
goto out;
pp->retprobe = tp->retprobe;
- pp->offset = addr - map__unmap_ip(map, sym->start);
- pp->function = strdup(sym->name);
+ pp->offset = addr - map__unmap_ip(map, symbol__start(sym));
+ pp->function = strdup(symbol__name(sym));
ret = pp->function ? 0 : -ENOMEM;
out:
@@ -3065,7 +3065,7 @@ static int find_probe_functions(struct map *map, char *name,
cut_version = false;
map__for_each_symbol(map, sym, tmp) {
- norm = arch__normalize_symbol_name(sym->name);
+ norm = arch__normalize_symbol_name(symbol__name(sym));
if (!norm)
continue;
@@ -3194,9 +3194,10 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
/* There can be duplicated symbols in the map */
for (i = 0; i < j; i++)
- if (sym->start == syms[i]->start) {
+ if (symbol__start(sym) == symbol__start(syms[i])) {
pr_debug("Found duplicated symbol %s @ %" PRIx64 "\n",
- sym->name, sym->start);
+ symbol__name(sym),
+ symbol__start(sym));
break;
}
if (i != j)
@@ -3210,28 +3211,29 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
}
ret++;
- if (pp->offset > sym->end - sym->start) {
+ if (pp->offset > symbol__end(sym) - symbol__start(sym)) {
pr_warning("Offset %ld is bigger than the size of %s\n",
- pp->offset, sym->name);
+ pp->offset, symbol__name(sym));
ret = -ENOENT;
goto err_out;
}
/* Add one probe point */
- tp->address = map__unmap_ip(map, sym->start) + pp->offset;
+ tp->address = map__unmap_ip(map, symbol__start(sym)) + pp->offset;
/* Check the kprobe (not in module) is within .text */
if (!pev->uprobes && !pev->target &&
- kprobe_warn_out_range(sym->name, tp->address)) {
+ kprobe_warn_out_range(symbol__name(sym), tp->address)) {
tp->symbol = NULL; /* Skip it */
skipped++;
} else if (reloc_sym) {
tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
tp->offset = tp->address - reloc_sym->addr;
} else {
- tp->symbol = strdup_or_goto(sym->name, nomem_out);
+ tp->symbol = strdup_or_goto(symbol__name(sym),
+ nomem_out);
tp->offset = pp->offset;
}
- tp->realname = strdup_or_goto(sym->name, nomem_out);
+ tp->realname = strdup_or_goto(symbol__name(sym), nomem_out);
tp->retprobe = pp->retprobe;
if (pev->target) {
@@ -3813,8 +3815,8 @@ int show_available_funcs(const char *target, struct nsinfo *nsi,
for (size_t i = 0; i < dso__symbol_names_len(dso); i++) {
struct symbol *pos = dso__symbol_names(dso)[i];
- if (strfilter__compare(_filter, pos->name))
- printf("%s\n", pos->name);
+ if (strfilter__compare(_filter, symbol__name(pos)))
+ printf("%s\n", symbol__name(pos));
}
end:
map__put(map);
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index d8a842621cda..d47f6865021e 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -759,7 +759,7 @@ static PyObject *pyrf_sample_event__get_symbol(struct pyrf_event *pevent,
if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.sym)
Py_RETURN_NONE;
- return PyUnicode_FromString(pevent->al.sym->name);
+ return PyUnicode_FromString(symbol__name(pevent->al.sym));
}
static PyObject *pyrf_sample_event__get_sym_start(struct pyrf_event *pevent,
@@ -768,7 +768,7 @@ static PyObject *pyrf_sample_event__get_sym_start(struct pyrf_event *pevent,
if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.sym)
Py_RETURN_NONE;
- return PyLong_FromUnsignedLongLong(pevent->al.sym->start);
+ return PyLong_FromUnsignedLongLong(symbol__start(pevent->al.sym));
}
static PyObject *pyrf_sample_event__get_sym_end(struct pyrf_event *pevent,
@@ -777,7 +777,7 @@ static PyObject *pyrf_sample_event__get_sym_end(struct pyrf_event *pevent,
if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.sym)
Py_RETURN_NONE;
- return PyLong_FromUnsignedLongLong(pevent->al.sym->end);
+ return PyLong_FromUnsignedLongLong(symbol__end(pevent->al.sym));
}
static PyObject *pyrf_sample_event__get_raw_buf(struct pyrf_event *pevent,
@@ -890,7 +890,7 @@ static PyObject *pyrf_callchain_node__get_symbol(struct pyrf_callchain_node *pno
void *closure __maybe_unused)
{
if (pnode->sym)
- return PyUnicode_FromString(pnode->sym->name);
+ return PyUnicode_FromString(symbol__name(pnode->sym));
return PyUnicode_FromString("[unknown]");
}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 410dc4cd0600..bcb4f0f6a173 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -301,11 +301,11 @@ static SV *perl_process_callchain(struct perf_sample *sample,
hv_undef(elem);
goto exit;
}
- if (!hv_stores(sym, "start", newSVuv(node->ms.sym->start)) ||
- !hv_stores(sym, "end", newSVuv(node->ms.sym->end)) ||
+ if (!hv_stores(sym, "start", newSVuv(symbol__start(node->ms.sym))) ||
+ !hv_stores(sym, "end", newSVuv(symbol__end(node->ms.sym))) ||
!hv_stores(sym, "binding", newSVuv(symbol__binding(node->ms.sym))) ||
- !hv_stores(sym, "name", newSVpvn(node->ms.sym->name,
- node->ms.sym->namelen)) ||
+ !hv_stores(sym, "name", newSVpvn(symbol__name(node->ms.sym),
+ symbol__namelen(node->ms.sym))) ||
!hv_stores(elem, "sym", newRV_noinc((SV*)sym))) {
hv_undef(sym);
hv_undef(elem);
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 038c4268a429..408b5645b33d 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -382,10 +382,10 @@ static unsigned long get_offset(struct symbol *sym, struct addr_location *al)
{
unsigned long offset;
- if (al->addr < sym->end)
- offset = al->addr - sym->start;
+ if (al->addr < symbol__end(sym))
+ offset = al->addr - symbol__start(sym);
else
- offset = al->addr - map__start(al->map) - sym->start;
+ offset = al->addr - map__start(al->map) - symbol__start(sym);
return offset;
}
@@ -433,14 +433,14 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
if (!pysym)
Py_FatalError("couldn't create Python dictionary");
pydict_set_item_string_decref(pysym, "start",
- PyLong_FromUnsignedLongLong(node->ms.sym->start));
+ PyLong_FromUnsignedLongLong(symbol__start(node->ms.sym)));
pydict_set_item_string_decref(pysym, "end",
- PyLong_FromUnsignedLongLong(node->ms.sym->end));
+ PyLong_FromUnsignedLongLong(symbol__end(node->ms.sym)));
pydict_set_item_string_decref(pysym, "binding",
_PyLong_FromLong(symbol__binding(node->ms.sym)));
pydict_set_item_string_decref(pysym, "name",
- _PyUnicode_FromStringAndSize(node->ms.sym->name,
- node->ms.sym->namelen));
+ _PyUnicode_FromStringAndSize(symbol__name(node->ms.sym),
+ symbol__namelen(node->ms.sym)));
pydict_set_item_string_decref(pyelem, "sym", pysym);
if (node->ms.map) {
@@ -547,15 +547,15 @@ static int get_symoff(struct symbol *sym, struct addr_location *al,
{
unsigned long offset;
- if (!sym || !sym->name[0])
+ if (!sym || !symbol__name(sym)[0])
return scnprintf(bf, size, "%s", "[unknown]");
if (!print_off)
- return scnprintf(bf, size, "%s", sym->name);
+ return scnprintf(bf, size, "%s", symbol__name(sym));
offset = get_offset(sym, al);
- return scnprintf(bf, size, "%s+0x%x", sym->name, offset);
+ return scnprintf(bf, size, "%s+0x%x", symbol__name(sym), offset);
}
static int get_br_mspred(struct branch_flags *flags, char *bf, int size)
@@ -908,7 +908,7 @@ static void set_sym_in_dict(PyObject *dict, struct addr_location *al,
}
if (al->sym) {
pydict_set_item_string_decref(dict, sym_field,
- _PyUnicode_FromString(al->sym->name));
+ _PyUnicode_FromString(symbol__name(al->sym)));
pydict_set_item_string_decref(dict, symoff_field,
PyLong_FromUnsignedLong(get_offset(al->sym, al)));
}
@@ -1379,10 +1379,10 @@ static int python_export_symbol(struct db_export *dbe, struct symbol *sym,
tuple_set_d64(t, 0, *sym_db_id);
tuple_set_d64(t, 1, dso__db_id(dso));
- tuple_set_d64(t, 2, sym->start);
- tuple_set_d64(t, 3, sym->end);
+ tuple_set_d64(t, 2, symbol__start(sym));
+ tuple_set_d64(t, 3, symbol__end(sym));
tuple_set_s32(t, 4, symbol__binding(sym));
- tuple_set_string(t, 5, sym->name);
+ tuple_set_string(t, 5, symbol__name(sym));
call_object(tables->symbol_handler, t, "symbol_table");
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 58638ec9ae0e..89e833f35fd2 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -470,18 +470,19 @@ int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
return 0;
if (symbol__inlined(sym_l) || symbol__inlined(sym_r)) {
- int ret = strcmp(sym_l->name, sym_r->name);
+ int ret = strcmp(symbol__name(sym_l), symbol__name(sym_r));
if (ret)
return ret;
- if ((sym_l->start <= sym_r->end) && (sym_l->end >= sym_r->start))
+ if ((symbol__start(sym_l) <= symbol__end(sym_r)) &&
+ (symbol__end(sym_l) >= symbol__start(sym_r)))
return 0;
}
- if (sym_l->start != sym_r->start)
- return (int64_t)(sym_r->start - sym_l->start);
+ if (symbol__start(sym_l) != symbol__start(sym_r))
+ return (int64_t)(symbol__start(sym_r) - symbol__start(sym_l));
- return (int64_t)(sym_r->end - sym_l->end);
+ return (int64_t)(symbol__end(sym_r) - symbol__end(sym_l));
}
static int64_t
@@ -511,7 +512,7 @@ sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
if (!left->ms.sym || !right->ms.sym)
return cmp_null(left->ms.sym, right->ms.sym);
- return strcmp(right->ms.sym->name, left->ms.sym->name);
+ return strcmp(symbol__name(right->ms.sym), symbol__name(left->ms.sym));
}
static int _hist_entry__sym_snprintf(struct map_symbol *ms,
@@ -537,13 +538,14 @@ static int _hist_entry__sym_snprintf(struct map_symbol *ms,
ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
if (sym && map) {
if (symbol__type(sym) == STT_OBJECT) {
- ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
+ ret += repsep_snprintf(bf + ret, size - ret, "%s",
+ symbol__name(sym));
ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
- ip - map__unmap_ip(map, sym->start));
+ ip - map__unmap_ip(map, symbol__start(sym)));
} else {
ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
width - ret,
- sym->name);
+ symbol__name(sym));
if (symbol__inlined(sym))
ret += repsep_snprintf(bf + ret, size - ret,
" (inlined)");
@@ -570,7 +572,7 @@ static int hist_entry__sym_filter(struct hist_entry *he, int type, const void *a
if (type != HIST_FILTER__SYMBOL)
return -1;
- return sym && (!he->ms.sym || !strstr(he->ms.sym->name, sym));
+ return sym && (!he->ms.sym || !strstr(symbol__name(he->ms.sym), sym));
}
struct sort_entry sort_sym = {
@@ -616,7 +618,8 @@ hist_entry__symoff_snprintf(struct hist_entry *he, char *bf, size_t size, unsign
if (sym == NULL)
return repsep_snprintf(bf, size, "[%c] %-#.*llx", he->level, width - 4, he->ip);
- return repsep_snprintf(bf, size, "[%c] %s+0x%llx", he->level, sym->name, he->ip - sym->start);
+ return repsep_snprintf(bf, size, "[%c] %s+0x%llx", he->level,
+ symbol__name(sym), he->ip - symbol__start(sym));
}
static struct sort_entry sort_sym_offset = {
@@ -1016,14 +1019,14 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
if (!sym_l || !sym_r)
return cmp_null(sym_l, sym_r);
- return strcmp(sym_r->name, sym_l->name);
+ return strcmp(symbol__name(sym_r), symbol__name(sym_l));
}
static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*.*s", width, width,
- he->parent ? he->parent->name : "[other]");
+ he->parent ? symbol__name(he->parent) : "[other]");
}
struct sort_entry sort_parent = {
@@ -1426,7 +1429,7 @@ static int hist_entry__sym_from_filter(struct hist_entry *he, int type,
return -1;
return sym && !(he->branch_info && he->branch_info->from.ms.sym &&
- strstr(he->branch_info->from.ms.sym->name, sym));
+ strstr(symbol__name(he->branch_info->from.ms.sym), sym));
}
static int hist_entry__sym_to_filter(struct hist_entry *he, int type,
@@ -1438,7 +1441,7 @@ static int hist_entry__sym_to_filter(struct hist_entry *he, int type,
return -1;
return sym && !(he->branch_info && he->branch_info->to.ms.sym &&
- strstr(he->branch_info->to.ms.sym->name, sym));
+ strstr(symbol__name(he->branch_info->to.ms.sym), sym));
}
struct sort_entry sort_dso_from = {
@@ -1484,14 +1487,15 @@ static int _hist_entry__addr_snprintf(struct map_symbol *ms,
ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
if (sym && map) {
if (symbol__type(sym) == STT_OBJECT) {
- ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
+ ret += repsep_snprintf(bf + ret, size - ret, "%s",
+ symbol__name(sym));
ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
- ip - map__unmap_ip(map, sym->start));
+ ip - map__unmap_ip(map, symbol__start(sym)));
} else {
ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
width - ret,
- sym->name);
- offs = ip - sym->start;
+ symbol__name(sym));
+ offs = ip - symbol__start(sym);
if (offs)
ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", offs);
}
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index a8d16106f619..53976de3105c 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -116,7 +116,7 @@ struct symbol *new_inline_sym(struct dso *dso,
funcname = demangled;
}
- if (base_sym && strcmp(funcname, base_sym->name) == 0) {
+ if (base_sym && strcmp(funcname, symbol__name(base_sym)) == 0) {
/* reuse the real, existing symbol */
inline_sym = base_sym;
/* ensure that we don't alias an inlined symbol, which could
@@ -125,8 +125,9 @@ struct symbol *new_inline_sym(struct dso *dso,
assert(!symbol__inlined(base_sym));
} else {
/* create a fake symbol for the inline frame */
- inline_sym = symbol__new(base_sym ? base_sym->start : 0,
- base_sym ? (base_sym->end - base_sym->start) : 0,
+ inline_sym = symbol__new(base_sym ? symbol__start(base_sym) : 0,
+ base_sym ?
+ (symbol__end(base_sym) - symbol__start(base_sym)) : 0,
base_sym ? symbol__binding(base_sym) : 0,
base_sym ? symbol__type(base_sym) : 0,
funcname);
@@ -307,11 +308,11 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
out:
if (!show_addr)
return (show_sym && sym) ?
- strndup(sym->name, sym->namelen) : SRCLINE_UNKNOWN;
+ strndup(symbol__name(sym), symbol__namelen(sym)) : SRCLINE_UNKNOWN;
if (sym) {
- if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
- ip - sym->start) < 0)
+ if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? symbol__name(sym) : "",
+ ip - symbol__start(sym)) < 0)
return SRCLINE_UNKNOWN;
} else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso__short_name(dso), addr) < 0)
return SRCLINE_UNKNOWN;
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index e955c3feddcd..73885413073b 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -350,11 +350,11 @@ static bool get_ifunc_name(Elf *elf, struct dso *dso, GElf_Ehdr *ehdr,
sym = dso__find_symbol_nocache(dso, addr);
/* Expecting the address to be an IFUNC or IFUNC alias */
- if (!sym || sym->start != addr ||
+ if (!sym || symbol__start(sym) != addr ||
(symbol__type(sym) != STT_GNU_IFUNC && !symbol__ifunc_alias(sym)))
return false;
- snprintf(buf, buf_sz, "%s@plt", sym->name);
+ snprintf(buf, buf_sz, "%s@plt", symbol__name(sym));
return true;
}
@@ -629,8 +629,8 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss)
* a symbol for .plt header.
*/
f = dso__find_symbol_nocache(dso, shdr_plt.sh_offset);
- if (f && f->start < shdr_plt.sh_offset && f->end > shdr_plt.sh_offset)
- f->end = shdr_plt.sh_offset;
+ if (f && symbol__start(f) < shdr_plt.sh_offset && symbol__end(f) > shdr_plt.sh_offset)
+ symbol__set_end(f, shdr_plt.sh_offset);
if (!get_plt_sizes(dso, &ehdr, &shdr_plt, &plt_header_size, &plt_entry_size))
return 0;
@@ -652,7 +652,8 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss)
if (!get_plt_sizes(dso, &ehdr, &plt_sec_shdr, &plt_header_size, &plt_entry_size))
return 0;
/* Extend .plt symbol to entire .plt */
- plt_sym->end = plt_sym->start + shdr_plt.sh_size;
+ symbol__set_end(plt_sym,
+ symbol__start(plt_sym) + shdr_plt.sh_size);
/* Use .plt.sec offset */
plt_offset = plt_sec_shdr.sh_offset;
lazy_plt = false;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 163652f071c6..8e264d38b981 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -149,9 +149,9 @@ int __weak arch__choose_best_symbol(struct symbol *syma,
struct symbol *symb __maybe_unused)
{
/* Avoid "SyS" kernel syscall aliases */
- if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3))
+ if (strlen(symbol__name(syma)) >= 3 && !strncmp(symbol__name(syma), "SyS", 3))
return SYMBOL_B;
- if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10))
+ if (strlen(symbol__name(syma)) >= 10 && !strncmp(symbol__name(syma), "compat_SyS", 10))
return SYMBOL_B;
return SYMBOL_A;
@@ -164,8 +164,8 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
size_t na, nb;
/* Prefer a symbol with non zero length */
- a = syma->end - syma->start;
- b = symb->end - symb->start;
+ a = symbol__end(syma) - symbol__start(syma);
+ b = symbol__end(symb) - symbol__start(symb);
if ((b == 0) && (a > 0))
return SYMBOL_A;
else if ((a == 0) && (b > 0))
@@ -195,16 +195,16 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
return SYMBOL_B;
/* Prefer a symbol with less underscores */
- a = prefix_underscores_count(syma->name);
- b = prefix_underscores_count(symb->name);
+ a = prefix_underscores_count(symbol__name(syma));
+ b = prefix_underscores_count(symbol__name(symb));
if (b > a)
return SYMBOL_A;
else if (a > b)
return SYMBOL_B;
/* Choose the symbol with the longest name */
- na = strlen(syma->name);
- nb = strlen(symb->name);
+ na = strlen(symbol__name(syma));
+ nb = strlen(symbol__name(symb));
if (na > nb)
return SYMBOL_A;
else if (na < nb)
@@ -231,7 +231,7 @@ void symbols__fixup_duplicate(struct rb_root_cached *symbols)
break;
next = rb_entry(nd, struct symbol, rb_node);
- if (curr->start != next->start)
+ if (symbol__start(curr) != symbol__start(next))
continue;
if (choose_best_symbol(curr, next) == SYMBOL_A) {
@@ -281,35 +281,39 @@ void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms)
* like in:
* ffffffffc1937000 T hdmi_driver_init [snd_hda_codec_hdmi]
*/
- if (prev->end == prev->start) {
+ if (symbol__end(prev) == symbol__start(prev)) {
const char *prev_mod;
const char *curr_mod;
if (!is_kallsyms) {
- prev->end = curr->start;
+ symbol__set_end(prev, symbol__start(curr));
continue;
}
- prev_mod = strchr(prev->name, '[');
- curr_mod = strchr(curr->name, '[');
+ prev_mod = strchr(symbol__name(prev), '[');
+ curr_mod = strchr(symbol__name(curr), '[');
/* Last kernel/module symbol mapped to end of page */
if (!prev_mod != !curr_mod)
- prev->end = roundup(prev->end + 4096, 4096);
+ symbol__set_end(prev,
+ roundup(symbol__end(prev) + 4096, 4096));
/* Last symbol in the previous module */
else if (prev_mod && strcmp(prev_mod, curr_mod))
- prev->end = roundup(prev->end + 4096, 4096);
+ symbol__set_end(prev,
+ roundup(symbol__end(prev) + 4096, 4096));
else
- prev->end = curr->start;
+ symbol__set_end(prev, symbol__start(curr));
pr_debug4("%s sym:%s end:%#" PRIx64 "\n",
- __func__, prev->name, prev->end);
+ __func__, symbol__name(prev),
+ symbol__end(prev));
}
}
/* Last entry */
- if (curr->end == curr->start)
- curr->end = roundup(curr->start, 4096) + 4096;
+ if (symbol__end(curr) == symbol__start(curr))
+ symbol__set_end(curr,
+ roundup(symbol__start(curr), 4096) + 4096);
}
struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name)
@@ -413,14 +417,14 @@ void __symbols__insert(struct rb_root_cached *symbols, struct symbol *sym)
{
struct rb_node **p = &symbols->rb_root.rb_node;
struct rb_node *parent = NULL;
- const u64 ip = sym->start;
+ const u64 ip = symbol__start(sym);
struct symbol *s;
bool leftmost = true;
while (*p != NULL) {
parent = *p;
s = rb_entry(parent, struct symbol, rb_node);
- if (ip < s->start)
+ if (ip < symbol__start(s))
p = &(*p)->rb_left;
else {
p = &(*p)->rb_right;
@@ -448,9 +452,9 @@ static struct symbol *symbols__find(struct rb_root_cached *symbols, u64 ip)
while (n) {
struct symbol *s = rb_entry(n, struct symbol, rb_node);
- if (ip < s->start)
+ if (ip < symbol__start(s))
n = n->rb_left;
- else if (ip > s->end || (ip == s->end && ip != s->start))
+ else if (ip > symbol__end(s) || (ip == symbol__end(s) && ip != symbol__start(s)))
n = n->rb_right;
else
return s;
@@ -494,7 +498,7 @@ static int symbols__sort_name_cmp(const void *vlhs, const void *vrhs)
const struct symbol *lhs = *((const struct symbol **)vlhs);
const struct symbol *rhs = *((const struct symbol **)vrhs);
- return strcmp(lhs->name, rhs->name);
+ return strcmp(symbol__name(lhs), symbol__name(rhs));
}
static struct symbol **symbols__sort_by_name(struct rb_root_cached *source, size_t *len)
@@ -556,7 +560,8 @@ static struct symbol *symbols__find_by_name(struct symbol *symbols[],
int cmp;
i = (lower + upper) / 2;
- cmp = symbol__match_symbol_name(symbols[i]->name, name, includes);
+ cmp = symbol__match_symbol_name(symbol__name(symbols[i]),
+ name, includes);
if (cmp > 0)
upper = i;
@@ -574,7 +579,7 @@ static struct symbol *symbols__find_by_name(struct symbol *symbols[],
for (; i > 0; i--) {
struct symbol *tmp = symbols[i - 1];
- if (!arch__compare_symbol_names(tmp->name, s->name)) {
+ if (!arch__compare_symbol_names(symbol__name(tmp), symbol__name(s))) {
if (found_idx)
*found_idx = i - 1;
s = tmp;
@@ -597,9 +602,9 @@ void dso__insert_symbol(struct dso *dso, struct symbol *sym)
__symbols__insert(dso__symbols(dso), sym);
/* update the symbol cache if necessary */
- if (dso__last_find_result_addr(dso) >= sym->start &&
- (dso__last_find_result_addr(dso) < sym->end ||
- sym->start == sym->end)) {
+ if (dso__last_find_result_addr(dso) >= symbol__start(sym) &&
+ (dso__last_find_result_addr(dso) < symbol__end(sym) ||
+ symbol__start(sym) == symbol__end(sym))) {
dso__set_last_find_result_symbol(dso, sym);
}
}
@@ -796,7 +801,7 @@ bool symbol__is_idle(struct symbol *sym, const struct dso *dso, struct perf_env
"poll_idle",
"pseries_dedicated_idle_sleep",
};
- const char *name = sym->name;
+ const char *name = symbol__name(sym);
uint16_t e_machine;
{
@@ -936,22 +941,25 @@ static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso)
rb_erase_cached(&pos->rb_node, &old_root);
RB_CLEAR_NODE(&pos->rb_node);
- module = strchr(pos->name, '\t');
+ module = strchr((char *)symbol__name(pos), '\t');
if (module)
*module = '\0';
- curr_map = maps__find(kmaps, pos->start);
+ curr_map = maps__find(kmaps, symbol__start(pos));
if (!curr_map) {
symbol__delete(pos);
continue;
}
curr_map_dso = map__dso(curr_map);
- pos->start -= map__start(curr_map) - map__pgoff(curr_map);
- if (pos->end > map__end(curr_map))
- pos->end = map__end(curr_map);
- if (pos->end)
- pos->end -= map__start(curr_map) - map__pgoff(curr_map);
+ symbol__set_start(pos, symbol__start(pos) -
+ (map__start(curr_map) - map__pgoff(curr_map)));
+ if (symbol__end(pos) > map__end(curr_map))
+ symbol__set_end(pos, map__end(curr_map));
+ if (symbol__end(pos)) {
+ symbol__set_end(pos, symbol__end(pos) -
+ (map__start(curr_map) - map__pgoff(curr_map)));
+ }
symbols__insert(dso__symbols(curr_map_dso), pos);
++count;
map__put(curr_map);
@@ -1009,7 +1017,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
pos = rb_entry(next, struct symbol, rb_node);
next = rb_next(&pos->rb_node);
- module = strchr(pos->name, '\t');
+ module = strchr((char *)symbol__name(pos), '\t');
if (module) {
struct dso *curr_map_dso;
@@ -1051,9 +1059,11 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
* So that we look just like we get from .ko files,
* i.e. not prelinked, relative to initial_map->start.
*/
- pos->start = map__map_ip(curr_map, pos->start);
- pos->end = map__map_ip(curr_map, pos->end);
- } else if (e_machine == EM_X86_64 && is_entry_trampoline(pos->name)) {
+ symbol__set_start(pos,
+ map__map_ip(curr_map, symbol__start(pos)));
+ symbol__set_end(pos,
+ map__map_ip(curr_map, symbol__end(pos)));
+ } else if (e_machine == EM_X86_64 && is_entry_trampoline(symbol__name(pos))) {
/*
* These symbols are not needed anymore since the
* trampoline maps refer to the text section and it's
@@ -1069,12 +1079,13 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
if (delta) {
/* Kernel was relocated at boot time */
- pos->start -= delta;
- pos->end -= delta;
+ symbol__set_start(pos,
+ symbol__start(pos) - delta);
+ symbol__set_end(pos, symbol__end(pos) - delta);
}
- if (map__start(initial_map) <= (pos->start + delta) &&
- (pos->start + delta) < map__end(initial_map)) {
+ if (map__start(initial_map) <= (symbol__start(pos) + delta) &&
+ (symbol__start(pos) + delta) < map__end(initial_map)) {
map__zput(curr_map);
curr_map = map__get(initial_map);
goto add_symbol;
@@ -1097,7 +1108,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
dso__set_kernel(ndso, dso__kernel(dso));
dso__set_loaded(ndso);
- curr_map = map__new2(pos->start, ndso);
+ curr_map = map__new2(symbol__start(pos), ndso);
if (curr_map == NULL) {
dso__put(ndso);
return -1;
@@ -1113,8 +1124,8 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
++kernel_range;
} else if (delta) {
/* Kernel was relocated at boot time */
- pos->start -= delta;
- pos->end -= delta;
+ symbol__set_start(pos, symbol__start(pos) - delta);
+ symbol__set_end(pos, symbol__end(pos) - delta);
}
add_symbol:
if (!RC_CHK_EQUAL(curr_map, initial_map)) {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index d0bac824c79c..4fb7f6fa8441 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -109,6 +109,46 @@ struct symbol {
void symbol__delete(struct symbol *sym);
void symbols__delete(struct rb_root_cached *symbols);
+static inline u64 symbol__start(const struct symbol *sym)
+{
+ return sym->start;
+}
+
+static inline void symbol__set_start(struct symbol *sym, u64 start)
+{
+ sym->start = start;
+}
+
+static inline u64 symbol__end(const struct symbol *sym)
+{
+ return sym->end;
+}
+
+static inline void symbol__set_end(struct symbol *sym, u64 end)
+{
+ sym->end = end;
+}
+
+static inline const char *symbol__name(const struct symbol *sym)
+{
+ return sym->name;
+}
+
+static inline u16 symbol__namelen(const struct symbol *sym)
+{
+ return sym->namelen;
+}
+
+static inline u8 symbol__arch_sym(const struct symbol *sym)
+{
+ return sym->arch_sym;
+}
+
+static inline void symbol__set_arch_sym(struct symbol *sym, u8 arch_sym)
+{
+ sym->arch_sym = arch_sym;
+}
+
static inline u8 symbol__type(const struct symbol *sym)
{
return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
@@ -165,7 +205,7 @@ void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias);
static inline size_t symbol__size(const struct symbol *sym)
{
- return sym->end - sym->start;
+ return symbol__end(sym) - symbol__start(sym);
}
struct strlist;
diff --git a/tools/perf/util/symbol_fprintf.c b/tools/perf/util/symbol_fprintf.c
index 4dc8d5761f52..8c131325e989 100644
--- a/tools/perf/util/symbol_fprintf.c
+++ b/tools/perf/util/symbol_fprintf.c
@@ -10,10 +10,10 @@
size_t symbol__fprintf(struct symbol *sym, FILE *fp)
{
return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
- sym->start, sym->end,
+ symbol__start(sym), symbol__end(sym),
symbol__binding(sym) == STB_GLOBAL ? 'g' :
symbol__binding(sym) == STB_LOCAL ? 'l' : 'w',
- sym->name);
+ symbol__name(sym));
}
size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
@@ -25,12 +25,12 @@ size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
size_t length;
if (sym) {
- length = fprintf(fp, "%s", sym->name);
+ length = fprintf(fp, "%s", symbol__name(sym));
if (al && print_offsets) {
- if (al->addr < sym->end)
- offset = al->addr - sym->start;
+ if (al->addr < symbol__end(sym))
+ offset = al->addr - symbol__start(sym);
else
- offset = al->addr - map__start(al->map) - sym->start;
+ offset = al->addr - map__start(al->map) - symbol__start(sym);
length += fprintf(fp, "+0x%lx", offset);
}
return length;
@@ -67,7 +67,7 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
for (size_t i = 0; i < dso__symbol_names_len(dso); i++) {
struct symbol *pos = dso__symbol_names(dso)[i];
- ret += fprintf(fp, "%s\n", pos->name);
+ ret += fprintf(fp, "%s\n", symbol__name(pos));
}
return ret;
}
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
index 1360f44421ef..76867ba83365 100644
--- a/tools/perf/util/thread-stack.c
+++ b/tools/perf/util/thread-stack.c
@@ -1056,7 +1056,7 @@ static int thread_stack__x86_retpoline(struct thread_stack *ts,
struct symbol *tsym = to_al->sym;
struct call_path *cp;
- if (sym && is_x86_retpoline(sym->name)) {
+ if (sym && is_x86_retpoline(symbol__name(sym))) {
/*
* This is a x86 retpoline fn. It pollutes the call graph by
* showing up everywhere there is an indirect branch, but does
@@ -1069,7 +1069,7 @@ static int thread_stack__x86_retpoline(struct thread_stack *ts,
*/
ts->cnt -= 1;
sym = ts->stack[ts->cnt - 2].cp->sym;
- if (sym && sym == tsym && to_al->addr != tsym->start) {
+ if (sym && sym == tsym && to_al->addr != symbol__start(tsym)) {
/*
* Target is back to the middle of the symbol we came
* from so assume it is an indirect jmp and forget it
@@ -1170,7 +1170,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
*/
if (!err && rstate == X86_RETPOLINE_POSSIBLE && to_al->sym &&
from_al->sym == to_al->sym &&
- to_al->addr != to_al->sym->start)
+ to_al->addr != symbol__start(to_al->sym))
ts->rstate = X86_RETPOLINE_DETECTED;
} else if (sample->flags & PERF_IP_FLAG_RETURN) {
@@ -1207,7 +1207,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
err = thread_stack__trace_end(ts, sample, ref);
} else if (sample->flags & PERF_IP_FLAG_BRANCH &&
from_al->sym != to_al->sym && to_al->sym &&
- to_al->addr == to_al->sym->start) {
+ to_al->addr == symbol__start(to_al->sym)) {
struct call_path_root *cpr = ts->crp->cpr;
struct call_path *cp;
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index d49901b1571e..87ade098b5c6 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -172,7 +172,7 @@ static int entry(u64 ip, struct unwind_info *ui)
e->ms.sym = al.sym;
pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
- al.sym ? al.sym->name : "''",
+ al.sym ? symbol__name(al.sym) : "''",
ip,
al.map ? map__map_ip(al.map, ip) : (u64) 0);
addr_location__exit(&al);
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 2/7] perf symbol: Remove symbol_conf.priv_size and negative-offset allocations
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
2026-09-28 7:52 ` [PATCH v1 1/7] perf symbol: Add accessor functions for struct symbol fields Ian Rogers
@ 2026-09-28 7:52 ` Ian Rogers
2026-09-28 7:52 ` [PATCH v1 3/7] perf symbol: Switch backing storage from rbtree to struct symbols array Ian Rogers
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Rogers @ 2026-09-28 7:52 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter, James Clark,
linux-perf-users, linux-kernel, Alireza Haghdoost
Previously struct symbol allocations could be preceded by
symbol_conf.priv_size bytes (used by annotation, the TUI map browser
index, and db-export symbol IDs). This coupled symbol allocation size to
global configuration, allocated unused space ahead of every symbol in
the system, and complicated symbol lifetime management.
Without adding extra seldom-used fields to struct symbol:
- Move struct annotation storage to an on-demand hashmap in
util/annotate.c keyed by struct symbol pointer, guarded by
annotations_lock and tracked via a new SYMBOL_FLAG_ANNOTATED flag in
sym->flags so unannotated symbols pay zero lookup or teardown
overhead. If allocation fails in symbol__annotation(), return a static
empty_annotation fallback so callers that do not check for NULL remain
safe while mutating callers check for &empty_annotation.
- Remove symbol__browser_index() in ui/browsers/map.c and compute the
TUI map browser index on demand in map_browser__search() by walking
the map browser's symbol entries when the user searches with '/'.
Previously, '/' search in the TUI map browser was gated behind
'verbose > 0' (-v) in builtin-c2c.c, builtin-report.c, builtin-top.c,
and ui/browsers/map.c solely to avoid adding sizeof(u32) to
symbol_conf.priv_size for every struct symbol in normal runs. With on-
demand index computation there is no per-symbol memory overhead, so
remove the verbose > 0 restriction and allow '/' search in the map
browser unconditionally.
- Store exported symbol database IDs in an on-demand sym_db_ids hashmap
in struct db_export instead of symbol__priv().
- Remove symbol_conf.priv_size and symbol__priv().
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-c2c.c | 14 --
tools/perf/builtin-report.c | 14 --
tools/perf/tests/builtin-test.c | 1 -
tools/perf/ui/browsers/map.c | 35 +++--
tools/perf/util/annotate.c | 128 +++++++++++++++++-
tools/perf/util/annotate.h | 6 +-
tools/perf/util/db-export.c | 49 ++++++-
tools/perf/util/db-export.h | 6 +
.../scripting-engines/trace-event-python.c | 10 +-
tools/perf/util/symbol.c | 34 ++---
tools/perf/util/symbol.h | 16 ++-
tools/perf/util/symbol_conf.h | 1 -
12 files changed, 219 insertions(+), 95 deletions(-)
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index 4222ac784fab..ba2f6cb7b371 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -3404,20 +3404,6 @@ static int perf_c2c__report(int argc, const char **argv)
if (ret < 0)
goto out_mem2node;
- /*
- * For searching by name on the "Browse map details".
- * providing it only in verbose mode not to bloat too
- * much struct symbol.
- */
- if (verbose > 0) {
- /*
- * XXX: Need to provide a less kludgy way to ask for
- * more space per symbol, the u32 is for the index on
- * the ui browser.
- * See symbol__browser_index.
- */
- symbol_conf.priv_size += sizeof(u32);
- }
annotation_config__init();
}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 57225bc87731..b42bf23e5545 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -1876,20 +1876,6 @@ int cmd_report(int argc, const char **argv)
ret = symbol__annotation_init();
if (ret < 0)
goto error;
- /*
- * For searching by name on the "Browse map details".
- * providing it only in verbose mode not to bloat too
- * much struct symbol.
- */
- if (verbose > 0) {
- /*
- * XXX: Need to provide a less kludgy way to ask for
- * more space per symbol, the u32 is for the index on
- * the ui browser.
- * See symbol__browser_index.
- */
- symbol_conf.priv_size += sizeof(u32);
- }
annotation_config__init();
}
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index d2f594921e25..66bfd0841f95 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -1827,7 +1827,6 @@ int cmd_test(int argc, const char **argv)
if (dont_fork)
sequential = true;
- symbol_conf.priv_size = sizeof(int);
symbol_conf.try_vmlinux_path = true;
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 1f69d7a798e9..38e123d45a1f 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -40,12 +40,6 @@ static void map_browser__write(struct ui_browser *browser, void *nd, int row)
ui_browser__write_nstring(browser, symbol__name(sym), width);
}
-/* FIXME uber-kludgy, see comment on cmd_report... */
-static u32 *symbol__browser_index(struct symbol *browser)
-{
- return ((void *)browser) - sizeof(struct rb_node) - sizeof(u32);
-}
-
static int map_browser__search(struct map_browser *browser)
{
char target[512];
@@ -63,10 +57,21 @@ static int map_browser__search(struct map_browser *browser)
sym = map__find_symbol_by_name(browser->map, target);
if (sym != NULL) {
- u32 *idx = symbol__browser_index(sym);
-
- browser->b.top = &sym->rb_node;
- browser->b.index = browser->b.top_idx = *idx;
+ struct rb_node *nd;
+ u32 idx = 0;
+
+ /*
+ * Walk the map browser's symbol entries to find the matching
+ * symbol node and its display row index, then position the
+ * browser cursor at that entry.
+ */
+ for (nd = rb_first(browser->b.entries); nd; nd = rb_next(nd), ++idx) {
+ if (&sym->rb_node == nd) {
+ browser->b.top = nd;
+ browser->b.index = browser->b.top_idx = idx;
+ break;
+ }
+ }
} else
ui_helpline__fpush("%s not found!", target);
@@ -78,8 +83,7 @@ static int map_browser__run(struct map_browser *browser)
int key;
if (ui_browser__show(&browser->b, dso__long_name(map__dso(browser->map)),
- "Press ESC to exit, %s / to search",
- verbose > 0 ? "" : "restart with -v to use") < 0)
+ "Press ESC to exit, / to search") < 0)
return -1;
while (1) {
@@ -87,8 +91,7 @@ static int map_browser__run(struct map_browser *browser)
switch (key) {
case '/':
- if (verbose > 0)
- map_browser__search(browser);
+ map_browser__search(browser);
/* fall thru */
default:
ui_browser__warn_unhandled_hotkey(&browser->b, key, 0, NULL);
@@ -125,10 +128,6 @@ int map__browse(struct map *map)
if (maxaddr < symbol__end(pos))
maxaddr = symbol__end(pos);
- if (verbose > 0) {
- u32 *idx = symbol__browser_index(pos);
- *idx = mb.b.nr_entries;
- }
++mb.b.nr_entries;
}
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index a1090a4e2e9d..9bb7e0ee1b8e 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -35,6 +35,7 @@
#include "string2.h"
#include "dwarf-regs.h"
#include "util/event.h"
+#include "util/rwsem.h"
#include "util/sharded_mutex.h"
#include "arch/common.h"
#include "namespaces.h"
@@ -156,9 +157,126 @@ annotated_source__hist_entry(struct annotated_source *src, const struct evsel *e
return entry;
}
+/*
+ * Map from struct symbol pointer to struct annotation. Allocated on demand so
+ * unannotated symbols do not pay the memory cost of struct annotation.
+ * empty_annotation is returned as a fallback on allocation failure so callers
+ * that do not check for NULL do not dereference NULL, while mutating callers
+ * check for &empty_annotation and return an error.
+ */
+static struct rw_semaphore _annotations_lock;
+static struct hashmap *annotations GUARDED_BY(_annotations_lock);
+static struct annotation empty_annotation;
+
+static void annotations_lock_init(void)
+{
+ init_rwsem(&_annotations_lock);
+}
+
+static struct rw_semaphore *annotations_lock(void) LOCK_RETURNED(_annotations_lock)
+{
+ static pthread_once_t annotations_lock_once = PTHREAD_ONCE_INIT;
+
+ pthread_once(&annotations_lock_once, annotations_lock_init);
+ return &_annotations_lock;
+}
+
+static size_t sym_ptr_hash(long key, void *ctx __maybe_unused)
+{
+ return hash_bits((size_t)key, 16);
+}
+
+static bool sym_ptr_equal(long key1, long key2, void *ctx __maybe_unused)
+{
+ return key1 == key2;
+}
+
+struct annotation *symbol__annotation(struct symbol *sym)
+{
+ struct annotation *notes = NULL;
+ long val = 0;
+
+ if (!sym)
+ return NULL;
+
+ /* Fast path: look up existing annotation under read lock if flagged. */
+ if (symbol__annotated(sym)) {
+ down_read(annotations_lock());
+ if (annotations && hashmap__find(annotations, (long)sym, &val))
+ notes = (struct annotation *)val;
+ up_read(annotations_lock());
+ if (notes)
+ return notes;
+ }
+
+ down_write(annotations_lock());
+ if (!annotations) {
+ annotations = hashmap__new(sym_ptr_hash, sym_ptr_equal, NULL);
+ if (IS_ERR(annotations)) {
+ annotations = NULL;
+ up_write(annotations_lock());
+ return &empty_annotation;
+ }
+ } else if (hashmap__find(annotations, (long)sym, &val)) {
+ notes = (struct annotation *)val;
+ up_write(annotations_lock());
+ return notes;
+ }
+
+ notes = zalloc(sizeof(*notes));
+ if (!notes) {
+ up_write(annotations_lock());
+ return &empty_annotation;
+ }
+ annotation__init(notes);
+ if (hashmap__add(annotations, (long)sym, notes) < 0) {
+ free(notes);
+ if (hashmap__size(annotations) == 0) {
+ hashmap__free(annotations);
+ annotations = NULL;
+ }
+ up_write(annotations_lock());
+ return &empty_annotation;
+ }
+ symbol__set_annotated(sym, true);
+ up_write(annotations_lock());
+ return notes;
+}
+
+void symbol__annotation_delete(struct symbol *sym)
+{
+ struct annotation *notes = NULL;
+ long val = 0;
+
+ /* Unannotated symbols avoid taking annotations_lock on teardown. */
+ if (!sym || !symbol__annotated(sym))
+ return;
+
+ down_write(annotations_lock());
+ if (annotations && hashmap__delete(annotations, (long)sym, NULL, &val)) {
+ notes = (struct annotation *)val;
+ if (hashmap__size(annotations) == 0) {
+ hashmap__free(annotations);
+ annotations = NULL;
+ }
+ }
+ symbol__set_annotated(sym, false);
+ up_write(annotations_lock());
+
+ if (notes) {
+ annotation__exit(notes);
+ free(notes);
+ }
+}
+
void symbol__annotate_zero_histograms(struct symbol *sym)
{
- struct annotation *notes = symbol__annotation(sym);
+ struct annotation *notes;
+
+ if (!symbol__annotated(sym))
+ return;
+
+ notes = symbol__annotation(sym);
annotation__lock(notes);
if (notes->src != NULL) {
@@ -298,7 +416,7 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms,
struct annotated_branch *annotation__get_branch(struct annotation *notes)
{
- if (notes == NULL)
+ if (notes == NULL || notes == &empty_annotation)
return NULL;
if (notes->branch == NULL)
@@ -337,6 +455,9 @@ struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists)
{
struct annotation *notes = symbol__annotation(sym);
+ if (!notes || notes == &empty_annotation)
+ return NULL;
+
if (notes->src == NULL) {
notes->src = annotated_source__new();
if (notes->src == NULL)
@@ -1142,6 +1263,9 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
if (parch)
*parch = arch;
+ if (!notes || notes == &empty_annotation)
+ return -ENOMEM;
+
if (notes->src && !list_empty(¬es->src->source))
return 0;
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 1b47c1156b9a..d87de0f11a60 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -449,10 +449,8 @@ static inline struct sym_hist *annotation__histogram(struct annotation *notes,
struct sym_hist_entry *
annotated_source__hist_entry(struct annotated_source *src, const struct evsel *evsel, u64 offset);
-static inline struct annotation *symbol__annotation(struct symbol *sym)
-{
- return (void *)sym - symbol_conf.priv_size;
-}
+struct annotation *symbol__annotation(struct symbol *sym);
+void symbol__annotation_delete(struct symbol *sym);
int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample);
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index 732369fe0046..897cda3fadd2 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -17,8 +17,20 @@
#include "event.h"
#include "thread-stack.h"
#include "callchain.h"
+#include <linux/err.h>
#include "call-path.h"
#include "db-export.h"
+#include "hashmap.h"
+
+static size_t sym_ptr_hash(long key, void *ctx __maybe_unused)
+{
+ return hash_bits((size_t)key, 16);
+}
+
+static bool sym_ptr_equal(long key1, long key2, void *ctx __maybe_unused)
+{
+ return key1 == key2;
+}
int db_export__init(struct db_export *dbe)
{
@@ -28,6 +40,8 @@ int db_export__init(struct db_export *dbe)
void db_export__exit(struct db_export *dbe)
{
+ hashmap__free(dbe->sym_db_ids);
+ dbe->sym_db_ids = NULL;
call_return_processor__free(dbe->crp);
dbe->crp = NULL;
}
@@ -156,15 +170,40 @@ int db_export__dso(struct db_export *dbe, struct dso *dso,
return 0;
}
+/*
+ * Return the database export ID assigned to @sym in @dbe->sym_db_ids, or 0
+ * if @sym has not been exported yet.
+ */
+u64 db_export__symbol_db_id(struct db_export *dbe, struct symbol *sym)
+{
+ long db_id = 0;
+
+ if (sym && dbe->sym_db_ids)
+ hashmap__find(dbe->sym_db_ids, (long)sym, &db_id);
+ return (u64)db_id;
+}
+
int db_export__symbol(struct db_export *dbe, struct symbol *sym,
struct dso *dso)
{
- u64 *sym_db_id = symbol__priv(sym);
+ long db_id;
- if (*sym_db_id)
+ if (db_export__symbol_db_id(dbe, sym))
return 0;
- *sym_db_id = ++dbe->symbol_last_db_id;
+ if (!dbe->sym_db_ids) {
+ dbe->sym_db_ids = hashmap__new(sym_ptr_hash, sym_ptr_equal, NULL);
+ if (IS_ERR(dbe->sym_db_ids)) {
+ int err = PTR_ERR(dbe->sym_db_ids);
+
+ dbe->sym_db_ids = NULL;
+ return err;
+ }
+ }
+
+ db_id = ++dbe->symbol_last_db_id;
+ if (hashmap__set(dbe->sym_db_ids, (long)sym, db_id, NULL, NULL))
+ return -ENOMEM;
if (dbe->export_symbol)
return dbe->export_symbol(dbe, sym, dso);
@@ -192,12 +231,10 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
}
if (al->sym) {
- u64 *db_id = symbol__priv(al->sym);
-
err = db_export__symbol(dbe, al->sym, dso);
if (err)
return err;
- *sym_db_id = *db_id;
+ *sym_db_id = db_export__symbol_db_id(dbe, al->sym);
*offset = al->addr - symbol__start(al->sym);
}
}
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
index 1abbfd398e3a..b5c22095e914 100644
--- a/tools/perf/util/db-export.h
+++ b/tools/perf/util/db-export.h
@@ -63,6 +63,11 @@ struct db_export {
u64 th_in_id, u64 comm_in_id, int flags);
struct call_return_processor *crp;
struct call_path_root *cpr;
+ /**
+ * @sym_db_ids: Hashmap mapping struct symbol pointers to their
+ * exported 64-bit database IDs.
+ */
+ struct hashmap *sym_db_ids;
u64 evsel_last_db_id;
u64 machine_last_db_id;
u64 thread_last_db_id;
@@ -90,6 +95,7 @@ int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
struct thread *thread);
int db_export__dso(struct db_export *dbe, struct dso *dso,
struct machine *machine);
+u64 db_export__symbol_db_id(struct db_export *dbe, struct symbol *sym);
int db_export__symbol(struct db_export *dbe, struct symbol *sym,
struct dso *dso);
int db_export__branch_type(struct db_export *dbe, u32 branch_type,
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 408b5645b33d..91885381d8b7 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -1372,12 +1372,12 @@ static int python_export_symbol(struct db_export *dbe, struct symbol *sym,
struct dso *dso)
{
struct tables *tables = container_of(dbe, struct tables, dbe);
- u64 *sym_db_id = symbol__priv(sym);
+ u64 sym_db_id = db_export__symbol_db_id(dbe, sym);
PyObject *t;
t = tuple_new(6);
- tuple_set_d64(t, 0, *sym_db_id);
+ tuple_set_d64(t, 0, sym_db_id);
tuple_set_d64(t, 1, dso__db_id(dso));
tuple_set_d64(t, 2, symbol__start(sym));
tuple_set_d64(t, 3, symbol__end(sym));
@@ -1487,7 +1487,7 @@ static int python_export_call_path(struct db_export *dbe, struct call_path *cp)
u64 parent_db_id, sym_db_id;
parent_db_id = cp->parent ? cp->parent->db_id : 0;
- sym_db_id = cp->sym ? *(u64 *)symbol__priv(cp->sym) : 0;
+ sym_db_id = db_export__symbol_db_id(dbe, cp->sym);
t = tuple_new(4);
@@ -1993,10 +1993,6 @@ static void set_table_handlers(struct tables *tables)
}
tables->db_export_mode = true;
- /*
- * Reserve per symbol space for symbol->db_id via symbol__priv()
- */
- symbol_conf.priv_size = sizeof(u64);
SET_TABLE_HANDLER(evsel);
SET_TABLE_HANDLER(machine);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8e264d38b981..2ec650a7834d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -319,19 +319,11 @@ void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms)
struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name)
{
size_t namelen = strlen(name) + 1;
- struct symbol *sym = calloc(1, (symbol_conf.priv_size +
- sizeof(*sym) + namelen));
+ struct symbol *sym = calloc(1, sizeof(*sym) + namelen);
+
if (sym == NULL)
return NULL;
- if (symbol_conf.priv_size) {
- if (symbol_conf.init_annotation) {
- struct annotation *notes = (void *)sym;
- annotation__init(notes);
- }
- sym = ((void *)sym) + symbol_conf.priv_size;
- }
-
sym->start = start;
sym->end = len ? start + len : start;
atomic_init(&sym->flags, (type << SYMBOL_FLAG_TYPE_SHIFT) |
@@ -347,14 +339,9 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *
void symbol__delete(struct symbol *sym)
{
- if (symbol_conf.priv_size) {
- if (symbol_conf.init_annotation) {
- struct annotation *notes = symbol__annotation(sym);
-
- annotation__exit(notes);
- }
- }
- free(((void *)sym) - symbol_conf.priv_size);
+ if (symbol__annotated(sym))
+ symbol__annotation_delete(sym);
+ free(sym);
}
void symbol__set_ignore(struct symbol *sym, bool ignore)
@@ -389,6 +376,14 @@ void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias)
atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_IFUNC_ALIAS);
}
+void symbol__set_annotated(struct symbol *sym, bool annotated)
+{
+ if (annotated)
+ atomic_fetch_or(&sym->flags, SYMBOL_FLAG_ANNOTATED);
+ else
+ atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_ANNOTATED);
+}
+
static void symbol__set_idle(struct symbol *sym, bool idle)
{
uint16_t old_flags = atomic_load_explicit(&sym->flags, memory_order_relaxed);
@@ -2504,7 +2499,6 @@ int symbol__annotation_init(void)
return -1;
}
- symbol_conf.priv_size += sizeof(struct annotation);
symbol_conf.init_annotation = true;
return 0;
}
@@ -2547,8 +2541,6 @@ int symbol__init(struct perf_env *env)
if (symbol_conf.initialized)
return 0;
- symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
-
symbol__elf_init();
if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 4fb7f6fa8441..100a7da07834 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -88,9 +88,9 @@ enum symbol_idle_kind {
#define SYMBOL_FLAG_INLINED (1 << 11)
#define SYMBOL_FLAG_ANNOTATE2 (1 << 12)
#define SYMBOL_FLAG_IFUNC_ALIAS (1 << 13)
+#define SYMBOL_FLAG_ANNOTATED (1 << 14)
/**
- * A symtab entry. When allocated this may be preceded by an annotation (see
- * symbol__annotation) and/or a browser_index (see symbol__browser_index).
+ * A symtab entry.
*/
struct symbol {
struct rb_node rb_node;
@@ -185,12 +185,19 @@ static inline bool symbol__ifunc_alias(const struct symbol *sym)
SYMBOL_FLAG_IFUNC_ALIAS) != 0;
}
+static inline bool symbol__annotated(const struct symbol *sym)
+{
+ return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ SYMBOL_FLAG_ANNOTATED) != 0;
+}
+
bool symbol__is_idle(struct symbol *sym, const struct dso *dso, struct perf_env *env);
void symbol__set_ignore(struct symbol *sym, bool ignore);
void symbol__set_annotate2(struct symbol *sym, bool annotate2);
void symbol__set_inlined(struct symbol *sym, bool inlined);
void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias);
+void symbol__set_annotated(struct symbol *sym, bool annotated);
/* symbols__for_each_entry - iterate over symbols (rb_root)
*
@@ -224,11 +231,6 @@ static inline int __symbol__join_symfs(char *bf, size_t size, const char *path)
extern int vmlinux_path__nr_entries;
extern char **vmlinux_path;
-static inline void *symbol__priv(struct symbol *sym)
-{
- return ((void *)sym) - symbol_conf.priv_size;
-}
-
struct ref_reloc_sym {
const char *name;
u64 addr;
diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
index 37d35f42dcc1..aaa7148c3ac1 100644
--- a/tools/perf/util/symbol_conf.h
+++ b/tools/perf/util/symbol_conf.h
@@ -42,7 +42,6 @@ struct symbol_conf {
/* Was hybrid_merge given on the command line rather than in a config file? */
bool hybrid_merge_set;
bool nanosecs;
- unsigned short priv_size;
bool try_vmlinux_path,
init_annotation,
force,
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 3/7] perf symbol: Switch backing storage from rbtree to struct symbols array
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
2026-09-28 7:52 ` [PATCH v1 1/7] perf symbol: Add accessor functions for struct symbol fields Ian Rogers
2026-09-28 7:52 ` [PATCH v1 2/7] perf symbol: Remove symbol_conf.priv_size and negative-offset allocations Ian Rogers
@ 2026-09-28 7:52 ` Ian Rogers
2026-09-28 7:52 ` [PATCH v1 4/7] perf symbol: Add reference counting and DECLARE_RC_STRUCT(symbol) Ian Rogers
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Rogers @ 2026-09-28 7:52 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter, James Clark,
linux-perf-users, linux-kernel, Alireza Haghdoost
Replace struct rb_node rb_node in struct symbol (which cost 24 bytes per
symbol on 64-bit) with a sorted array in struct symbols, matching the
design of struct dsos and struct maps:
- Introduce struct symbols containing a rw_semaphore lock, primary
address-sorted symbols array, secondary name-sorted symbols_by_name
array, counts, capacity, and sorted state flags.
- Lazily sort symbols by [start, end) using qsort (symbols__sort_locked)
and use binary search in symbols__find().
- Update symbols__fixup_duplicate(), symbols__fixup_end(),
maps__split_kallsyms_for_kcore(), and maps__split_kallsyms() to
operate on the sorted array and compact entries in place.
- Convert symbols__for_each_entry(), dso__for_each_symbol(), and
map__for_each_symbol() to callback-based iteration under
symbols->lock, matching dsos__for_each_dso() and maps__for_each_map().
- Remove the unsynchronized single-entry dso->last_find_result cache and
dso__reset_find_symbol_cache() since binary search over a contiguous
array is cache-friendly.
- Remove the direct rb_erase_cached() workaround in builtin-annotate.c's
add_sample().
- Update the TUI map browser (ui/browsers/map.c) to snapshot the sorted
symbol array into an entries array and use ui_browser__argv_refresh
and ui_browser__argv_seek instead of ui_browser__rb_tree_refresh.
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/arch/powerpc/util/sym-handling.c | 34 +-
tools/perf/builtin-annotate.c | 11 -
tools/perf/builtin-kmem.c | 51 ++-
tools/perf/tests/symbols.c | 61 ++-
tools/perf/tests/vmlinux-kallsyms.c | 189 ++++----
tools/perf/ui/browsers/map.c | 62 ++-
tools/perf/util/auxtrace.c | 109 +++--
tools/perf/util/dso.c | 50 +-
tools/perf/util/dso.h | 59 +--
tools/perf/util/intel-pt.c | 74 +--
tools/perf/util/machine.c | 28 +-
tools/perf/util/map.c | 25 +-
tools/perf/util/map.h | 8 +-
tools/perf/util/probe-event.c | 82 ++--
tools/perf/util/symbol.c | 478 ++++++++++++--------
tools/perf/util/symbol.h | 70 ++-
16 files changed, 801 insertions(+), 590 deletions(-)
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
index d73bfdcdbec1..0ec327930b0a 100644
--- a/tools/perf/arch/powerpc/util/sym-handling.c
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -115,13 +115,27 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev,
}
#ifdef HAVE_LIBELF_SUPPORT
+struct post_process_probe_trace_events_args {
+ struct perf_probe_event *pev;
+ struct probe_trace_event *tev;
+ struct map *map;
+};
+
+static int post_process_probe_trace_events_cb(struct symbol *sym, void *data)
+{
+ struct post_process_probe_trace_events_args *args = data;
+
+ if (map__unmap_ip(args->map, symbol__start(sym)) == args->tev->point.address) {
+ arch__fix_tev_from_maps(args->pev, args->tev, args->map, sym);
+ return 1;
+ }
+ return 0;
+}
+
void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
int ntevs)
{
- struct probe_trace_event *tev;
struct map *map;
- struct symbol *sym = NULL;
- struct rb_node *tmp;
int i = 0;
map = get_target_map(pev->target, pev->nsi, pev->uprobes);
@@ -129,13 +143,13 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
return;
for (i = 0; i < ntevs; i++) {
- tev = &pev->tevs[i];
- map__for_each_symbol(map, sym, tmp) {
- if (map__unmap_ip(map, symbol__start(sym)) == tev->point.address) {
- arch__fix_tev_from_maps(pev, tev, map, sym);
- break;
- }
- }
+ struct post_process_probe_trace_events_args args = {
+ .pev = pev,
+ .tev = &pev->tevs[i],
+ .map = map,
+ };
+
+ map__for_each_symbol(map, post_process_probe_trace_events_cb, &args);
}
}
#endif /* HAVE_LIBELF_SUPPORT */
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index c93b67986334..5ee02a25fb9c 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -254,17 +254,6 @@ static int add_sample(struct perf_sample *sample,
(al->sym == NULL ||
strcmp(ann->sym_hist_filter, symbol__name(al->sym)) != 0)) {
/* We're only interested in a symbol named sym_hist_filter */
- /*
- * FIXME: why isn't this done in the symbol_filter when loading
- * the DSO?
- */
- if (al->sym != NULL) {
- struct dso *dso = map__dso(al->map);
-
- rb_erase_cached(&al->sym->rb_node, dso__symbols(dso));
- symbol__delete(al->sym);
- dso__reset_find_symbol_cache(dso);
- }
return 0;
}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index d1883086ed58..dd8821d2d05e 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -341,13 +341,33 @@ static int callcmp(const void *a, const void *b)
return -1;
}
+static int build_alloc_func_list_cb(struct symbol *sym, void *data)
+{
+ regex_t *alloc_func_regex = data;
+ struct alloc_func *func;
+
+ if (regexec(alloc_func_regex, symbol__name(sym), 0, NULL, 0))
+ return 0;
+
+ func = realloc(alloc_func_list,
+ (nr_alloc_funcs + 1) * sizeof(*func));
+ if (func == NULL)
+ return -ENOMEM;
+
+ pr_debug("alloc func: %s\n", symbol__name(sym));
+ func[nr_alloc_funcs].start = symbol__start(sym);
+ func[nr_alloc_funcs].end = symbol__end(sym);
+ func[nr_alloc_funcs].name = symbol__name(sym);
+
+ alloc_func_list = func;
+ nr_alloc_funcs++;
+ return 0;
+}
+
static int build_alloc_func_list(void)
{
int ret;
struct map *kernel_map;
- struct symbol *sym;
- struct rb_node *node;
- struct alloc_func *func;
struct machine *machine = &kmem_session->machines.host;
regex_t alloc_func_regex;
static const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?";
@@ -364,30 +384,17 @@ static int build_alloc_func_list(void)
kernel_map = machine__kernel_map(machine);
if (map__load(kernel_map) < 0) {
pr_err("cannot load kernel map\n");
+ regfree(&alloc_func_regex);
return -ENOENT;
}
- map__for_each_symbol(kernel_map, sym, node) {
- if (regexec(&alloc_func_regex, symbol__name(sym), 0, NULL, 0))
- continue;
-
- func = realloc(alloc_func_list,
- (nr_alloc_funcs + 1) * sizeof(*func));
- if (func == NULL)
- return -ENOMEM;
-
- pr_debug("alloc func: %s\n", symbol__name(sym));
- func[nr_alloc_funcs].start = symbol__start(sym);
- func[nr_alloc_funcs].end = symbol__end(sym);
- func[nr_alloc_funcs].name = symbol__name(sym);
-
- alloc_func_list = func;
- nr_alloc_funcs++;
- }
+ ret = map__for_each_symbol(kernel_map, build_alloc_func_list_cb, &alloc_func_regex);
+ regfree(&alloc_func_regex);
+ if (ret)
+ return ret;
- qsort(alloc_func_list, nr_alloc_funcs, sizeof(*func), funcmp);
+ qsort(alloc_func_list, nr_alloc_funcs, sizeof(*alloc_func_list), funcmp);
- regfree(&alloc_func_regex);
return 0;
}
diff --git a/tools/perf/tests/symbols.c b/tools/perf/tests/symbols.c
index d9796851335e..440d800d9f4d 100644
--- a/tools/perf/tests/symbols.c
+++ b/tools/perf/tests/symbols.c
@@ -112,39 +112,50 @@ static int create_map(struct test_info *ti, char *filename, struct map **map_p)
return TEST_OK;
}
+struct test_dso_args {
+ struct symbol *last_sym;
+ int ret;
+};
+
+static int test_dso_cb(struct symbol *sym, void *data)
+{
+ struct test_dso_args *args = data;
+ struct symbol *last_sym = args->last_sym;
+
+ if (symbol__type(sym) != STT_FUNC && symbol__type(sym) != STT_GNU_IFUNC)
+ return 0;
+
+ /* Check for overlapping function symbols */
+ if (last_sym && symbol__start(sym) < symbol__end(last_sym)) {
+ pr_debug("Overlapping symbols:\n");
+ symbol__fprintf(last_sym, stderr);
+ symbol__fprintf(sym, stderr);
+ args->ret = TEST_FAIL;
+ }
+ /* Check for zero-length function symbol */
+ if (symbol__start(sym) == symbol__end(sym)) {
+ pr_debug("Zero-length symbol:\n");
+ symbol__fprintf(sym, stderr);
+ args->ret = TEST_FAIL;
+ }
+ args->last_sym = sym;
+ return 0;
+}
+
static int test_dso(struct dso *dso)
{
- struct symbol *last_sym = NULL;
- struct rb_node *nd;
- int ret = TEST_OK;
+ struct test_dso_args args = {
+ .last_sym = NULL,
+ .ret = TEST_OK,
+ };
/* dso__fprintf() prints all the symbols */
if (verbose > 1)
dso__fprintf(dso, stderr);
- for (nd = rb_first_cached(dso__symbols(dso)); nd; nd = rb_next(nd)) {
- struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+ dso__for_each_symbol(dso, test_dso_cb, &args);
- if (symbol__type(sym) != STT_FUNC && symbol__type(sym) != STT_GNU_IFUNC)
- continue;
-
- /* Check for overlapping function symbols */
- if (last_sym && symbol__start(sym) < symbol__end(last_sym)) {
- pr_debug("Overlapping symbols:\n");
- symbol__fprintf(last_sym, stderr);
- symbol__fprintf(sym, stderr);
- ret = TEST_FAIL;
- }
- /* Check for zero-length function symbol */
- if (symbol__start(sym) == symbol__end(sym)) {
- pr_debug("Zero-length symbol:\n");
- symbol__fprintf(sym, stderr);
- ret = TEST_FAIL;
- }
- last_sym = sym;
- }
-
- return ret;
+ return args.ret;
}
static int subdivided_dso_cb(struct dso *dso, struct machine *machine __maybe_unused, void *d)
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 97950f86ed5f..98c2a9437ba7 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -113,6 +113,7 @@ static bool is_ignored_symbol(const char *name, char type)
struct test__vmlinux_matches_kallsyms_cb_args {
struct machine kallsyms;
struct map *vmlinux_map;
+ int err;
bool header_printed;
};
@@ -185,16 +186,103 @@ static int test__vmlinux_matches_kallsyms_cb3(struct map *map, void *data)
return 0;
}
+static int test__vmlinux_matches_kallsyms_sym_cb(struct symbol *sym, void *data)
+{
+ struct test__vmlinux_matches_kallsyms_cb_args *args = data;
+ /*
+ * Step 4:
+ *
+ * kallsyms will be internally on demand sorted by name so that we can
+ * find the reference relocation * symbol, i.e. the symbol we will use
+ * to see if the running kernel was relocated by checking if it has the
+ * same value in the vmlinux file we load.
+ */
+ struct map *kallsyms_map = machine__kernel_map(&args->kallsyms);
+ struct symbol *pair, *first_pair;
+ u64 mem_start, mem_end;
+
+ if (symbol__start(sym) == symbol__end(sym))
+ return 0;
+
+ mem_start = map__unmap_ip(args->vmlinux_map, symbol__start(sym));
+ mem_end = map__unmap_ip(args->vmlinux_map, symbol__end(sym));
+
+ first_pair = machine__find_kernel_symbol(&args->kallsyms, mem_start, NULL);
+ pair = first_pair;
+
+ if (pair && UM(symbol__start(pair)) == mem_start) {
+next_pair:
+ if (arch__compare_symbol_names(symbol__name(sym),
+ symbol__name(pair)) == 0) {
+ /*
+ * kallsyms don't have the symbol end, so we
+ * set that by using the next symbol start - 1,
+ * in some cases we get this up to a page
+ * wrong, trace_kmalloc when I was developing
+ * this code was one such example, 2106 bytes
+ * off the real size. More than that and we
+ * _really_ have a problem.
+ */
+ s64 skew = mem_end - UM(symbol__end(pair));
+
+ if (llabs(skew) >= page_size)
+ pr_debug("WARN: %#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
+ mem_start, symbol__name(sym),
+ mem_end,
+ UM(symbol__end(pair)));
+
+ /*
+ * Do not count this as a failure, because we
+ * could really find a case where it's not
+ * possible to get proper function end from
+ * kallsyms.
+ */
+ return 0;
+ } else {
+ pair = machine__find_kernel_symbol_by_name(&args->kallsyms,
+ symbol__name(sym),
+ NULL);
+ if (pair) {
+ if (UM(symbol__start(pair)) == mem_start)
+ goto next_pair;
+
+ pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
+ mem_start, symbol__name(sym),
+ symbol__name(pair));
+ } else {
+ pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
+ mem_start, symbol__name(sym),
+ symbol__name(first_pair));
+ }
+
+ return 0;
+ }
+ } else if (mem_start == map__end(args->kallsyms.vmlinux_map)) {
+ /*
+ * Ignore aliases to _etext, i.e. to the end of the kernel text area,
+ * such as __indirect_thunk_end.
+ */
+ return 0;
+ } else if (is_ignored_symbol(symbol__name(sym), symbol__type(sym))) {
+ /*
+ * Ignore hidden symbols, see scripts/kallsyms.c for the details
+ */
+ return 0;
+ } else {
+ pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n",
+ mem_start, symbol__name(sym));
+ }
+
+ args->err = -1;
+ return 0;
+}
+
static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
int err = TEST_FAIL;
- struct rb_node *nd;
- struct symbol *sym;
- struct map *kallsyms_map;
struct machine vmlinux = { 0 };
struct maps *maps;
- u64 mem_start, mem_end;
struct test__vmlinux_matches_kallsyms_cb_args args;
/*
@@ -240,16 +328,6 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused
goto out;
}
- /*
- * Step 4:
- *
- * kallsyms will be internally on demand sorted by name so that we can
- * find the reference relocation * symbol, i.e. the symbol we will use
- * to see if the running kernel was relocated by checking if it has the
- * same value in the vmlinux file we load.
- */
- kallsyms_map = machine__kernel_map(&args.kallsyms);
-
/*
* Step 5:
*
@@ -279,7 +357,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused
goto out;
}
- err = 0;
+ args.err = 0;
/*
* Step 7:
*
@@ -287,85 +365,8 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused
* in the kallsyms dso. For the ones that are in both, check its names and
* end addresses too.
*/
- map__for_each_symbol(args.vmlinux_map, sym, nd) {
- struct symbol *pair, *first_pair;
-
- sym = rb_entry(nd, struct symbol, rb_node);
-
- if (symbol__start(sym) == symbol__end(sym))
- continue;
-
- mem_start = map__unmap_ip(args.vmlinux_map,
- symbol__start(sym));
- mem_end = map__unmap_ip(args.vmlinux_map, symbol__end(sym));
-
- first_pair = machine__find_kernel_symbol(&args.kallsyms, mem_start, NULL);
- pair = first_pair;
-
- if (pair && UM(symbol__start(pair)) == mem_start) {
-next_pair:
- if (arch__compare_symbol_names(symbol__name(sym),
- symbol__name(pair)) == 0) {
- /*
- * kallsyms don't have the symbol end, so we
- * set that by using the next symbol start - 1,
- * in some cases we get this up to a page
- * wrong, trace_kmalloc when I was developing
- * this code was one such example, 2106 bytes
- * off the real size. More than that and we
- * _really_ have a problem.
- */
- s64 skew = mem_end - UM(symbol__end(pair));
- if (llabs(skew) >= page_size)
- pr_debug("WARN: %#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
- mem_start, symbol__name(sym),
- mem_end,
- UM(symbol__end(pair)));
-
- /*
- * Do not count this as a failure, because we
- * could really find a case where it's not
- * possible to get proper function end from
- * kallsyms.
- */
- continue;
- } else {
- pair = machine__find_kernel_symbol_by_name(&args.kallsyms,
- symbol__name(sym),
- NULL);
- if (pair) {
- if (UM(symbol__start(pair)) == mem_start)
- goto next_pair;
-
- pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
- mem_start, symbol__name(sym),
- symbol__name(pair));
- } else {
- pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
- mem_start, symbol__name(sym),
- symbol__name(first_pair));
- }
-
- continue;
- }
- } else if (mem_start == map__end(args.kallsyms.vmlinux_map)) {
- /*
- * Ignore aliases to _etext, i.e. to the end of the kernel text area,
- * such as __indirect_thunk_end.
- */
- continue;
- } else if (is_ignored_symbol(symbol__name(sym), symbol__type(sym))) {
- /*
- * Ignore hidden symbols, see scripts/kallsyms.c for the details
- */
- continue;
- } else {
- pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n",
- mem_start, symbol__name(sym));
- }
-
- err = -1;
- }
+ map__for_each_symbol(args.vmlinux_map, test__vmlinux_matches_kallsyms_sym_cb, &args);
+ err = args.err;
if (verbose <= 0)
goto out;
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 38e123d45a1f..bb35d4965a3a 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -24,7 +24,7 @@ struct map_browser {
static void map_browser__write(struct ui_browser *browser, void *nd, int row)
{
- struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+ struct symbol *sym = *(struct symbol **)nd;
struct map_browser *mb = container_of(browser, struct map_browser, b);
bool current_entry = ui_browser__is_current_entry(browser, row);
int width;
@@ -57,17 +57,16 @@ static int map_browser__search(struct map_browser *browser)
sym = map__find_symbol_by_name(browser->map, target);
if (sym != NULL) {
- struct rb_node *nd;
- u32 idx = 0;
+ struct symbol **entries = browser->b.entries;
/*
- * Walk the map browser's symbol entries to find the matching
- * symbol node and its display row index, then position the
- * browser cursor at that entry.
+ * Scan the map browser's symbol entries to find the matching
+ * symbol and its display row index, then position the browser
+ * cursor at that entry.
*/
- for (nd = rb_first(browser->b.entries); nd; nd = rb_next(nd), ++idx) {
- if (&sym->rb_node == nd) {
- browser->b.top = nd;
+ for (u32 idx = 0; idx < browser->b.nr_entries; ++idx) {
+ if (entries[idx] == sym) {
+ browser->b.top = &entries[idx];
browser->b.index = browser->b.top_idx = idx;
break;
}
@@ -110,27 +109,48 @@ static int map_browser__run(struct map_browser *browser)
int map__browse(struct map *map)
{
+ struct symbols *symbols = dso__symbols(map__dso(map));
struct map_browser mb = {
.b = {
- .entries = dso__symbols(map__dso(map)),
- .refresh = ui_browser__rb_tree_refresh,
- .seek = ui_browser__rb_tree_seek,
+ .refresh = ui_browser__argv_refresh,
+ .seek = ui_browser__argv_seek,
.write = map_browser__write,
},
.map = map,
};
- struct rb_node *nd;
+ struct symbol **entries = NULL;
+ unsigned int nr_entries = 0;
char tmp[BITS_PER_LONG / 4];
u64 maxaddr = 0;
-
- for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
-
- if (maxaddr < symbol__end(pos))
- maxaddr = symbol__end(pos);
- ++mb.b.nr_entries;
+ int ret;
+
+ /*
+ * Snapshot the DSO's sorted symbol array under symbols->lock for use
+ * with ui_browser__argv_refresh and ui_browser__argv_seek.
+ */
+ symbols__sort_read_lock(symbols);
+ nr_entries = symbols->cnt;
+ if (nr_entries > 0) {
+ entries = malloc(nr_entries * sizeof(*entries));
+ if (entries) {
+ for (unsigned int idx = 0; idx < nr_entries; idx++) {
+ struct symbol *pos = symbols->symbols[idx];
+
+ entries[idx] = pos;
+ if (maxaddr < symbol__end(pos))
+ maxaddr = symbol__end(pos);
+ }
+ } else {
+ nr_entries = 0;
+ }
}
+ up_read(&symbols->lock);
+
+ mb.b.entries = entries;
+ mb.b.nr_entries = nr_entries;
mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
- return map_browser__run(&mb);
+ ret = map_browser__run(&mb);
+ free(entries);
+ return ret;
}
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index f4aee90b43a3..c7bca2acf938 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -2713,61 +2713,96 @@ static bool dso_sym_match(struct symbol *sym, const char *name, int *cnt,
idx < 0);
}
+struct print_duplicate_syms_args {
+ const char *sym_name;
+ bool near;
+ int cnt;
+};
+
+static int print_duplicate_syms_cb(struct symbol *sym, void *data)
+{
+ struct print_duplicate_syms_args *args = data;
+
+ if (dso_sym_match(sym, args->sym_name, &args->cnt, -1)) {
+ pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n",
+ ++args->cnt, symbol__start(sym),
+ symbol__binding(sym) == STB_GLOBAL ? 'g' :
+ symbol__binding(sym) == STB_LOCAL ? 'l' : 'w',
+ symbol__name(sym));
+ args->near = true;
+ } else if (args->near) {
+ args->near = false;
+ pr_err("\t\twhich is near\t\t%s\n", symbol__name(sym));
+ }
+ return 0;
+}
+
static void print_duplicate_syms(struct dso *dso, const char *sym_name)
{
- struct symbol *sym;
- bool near = false;
- int cnt = 0;
+ struct print_duplicate_syms_args args = {
+ .sym_name = sym_name,
+ .near = false,
+ .cnt = 0,
+ };
pr_err("Multiple symbols with name '%s'\n", sym_name);
- sym = dso__first_symbol(dso);
- while (sym) {
- if (dso_sym_match(sym, sym_name, &cnt, -1)) {
- pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n",
- ++cnt, symbol__start(sym),
- symbol__binding(sym) == STB_GLOBAL ? 'g' :
- symbol__binding(sym) == STB_LOCAL ? 'l' : 'w',
- symbol__name(sym));
- near = true;
- } else if (near) {
- near = false;
- pr_err("\t\twhich is near\t\t%s\n", symbol__name(sym));
- }
- sym = dso__next_symbol(sym);
- }
+ dso__for_each_symbol(dso, print_duplicate_syms_cb, &args);
pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n",
sym_name);
pr_err("Or select a global symbol by inserting #0 or #g or #G\n");
}
+struct find_dso_sym_args {
+ const char *sym_name;
+ u64 *start;
+ u64 *size;
+ int idx;
+ int cnt;
+ bool duplicate;
+};
+
+static int find_dso_sym_cb(struct symbol *sym, void *data)
+{
+ struct find_dso_sym_args *args = data;
+
+ if (*args->start) {
+ if (!*args->size)
+ *args->size = symbol__start(sym) - *args->start;
+ if (args->idx > 0) {
+ if (*args->size)
+ return 1;
+ } else if (dso_sym_match(sym, args->sym_name, &args->cnt, args->idx)) {
+ args->duplicate = true;
+ return 1;
+ }
+ } else if (dso_sym_match(sym, args->sym_name, &args->cnt, args->idx)) {
+ *args->start = symbol__start(sym);
+ *args->size = symbol__end(sym) - symbol__start(sym);
+ }
+ return 0;
+}
+
static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start,
u64 *size, int idx)
{
- struct symbol *sym;
- int cnt = 0;
+ struct find_dso_sym_args args = {
+ .sym_name = sym_name,
+ .start = start,
+ .size = size,
+ .idx = idx,
+ .cnt = 0,
+ .duplicate = false,
+ };
*start = 0;
*size = 0;
- sym = dso__first_symbol(dso);
- while (sym) {
- if (*start) {
- if (!*size)
- *size = symbol__start(sym) - *start;
- if (idx > 0) {
- if (*size)
- return 0;
- } else if (dso_sym_match(sym, sym_name, &cnt, idx)) {
- print_duplicate_syms(dso, sym_name);
- return -EINVAL;
- }
- } else if (dso_sym_match(sym, sym_name, &cnt, idx)) {
- *start = symbol__start(sym);
- *size = symbol__end(sym) - symbol__start(sym);
- }
- sym = dso__next_symbol(sym);
+ dso__for_each_symbol(dso, find_dso_sym_cb, &args);
+ if (args.duplicate) {
+ print_duplicate_syms(dso, sym_name);
+ return -EINVAL;
}
if (!*start)
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 39cb82693596..1b96853164be 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1687,12 +1687,7 @@ bool dso__loaded(const struct dso *dso)
bool dso__sorted_by_name(const struct dso *dso)
{
- return RC_CHK_ACCESS(dso)->sorted_by_name;
-}
-
-void dso__set_sorted_by_name(struct dso *dso)
-{
- RC_CHK_ACCESS(dso)->sorted_by_name = true;
+ return RC_CHK_ACCESS(dso)->symbols.sorted_by_name;
}
struct dso *dso__new_id(const char *name, const struct dso_id *id)
@@ -1710,9 +1705,7 @@ struct dso *dso__new_id(const char *name, const struct dso_id *id)
dso->id = *id;
dso__set_long_name_id(res, dso->name, false);
dso__set_short_name(res, dso->name, false);
- dso->symbols = RB_ROOT_CACHED;
- dso->symbol_names = NULL;
- dso->symbol_names_len = 0;
+ symbols__init(&dso->symbols);
dso->inlined_nodes = RB_ROOT_CACHED;
dso->srclines = RB_ROOT_CACHED;
dso->data_types = RB_ROOT;
@@ -1724,7 +1717,6 @@ struct dso *dso__new_id(const char *name, const struct dso_id *id)
dso->is_64_bit = (sizeof(void *) == 8);
dso->loaded = 0;
dso->rel = 0;
- dso->sorted_by_name = 0;
dso->has_srcline = 1;
dso->a2l_fails = 1;
dso->kernel = DSO_SPACE__USER;
@@ -1758,9 +1750,7 @@ void dso__delete(struct dso *dso)
/* free inlines first, as they reference symbols */
inlines__tree_delete(&RC_CHK_ACCESS(dso)->inlined_nodes);
srcline__tree_delete(&RC_CHK_ACCESS(dso)->srclines);
- symbols__delete(&RC_CHK_ACCESS(dso)->symbols);
- RC_CHK_ACCESS(dso)->symbol_names_len = 0;
- zfree(&RC_CHK_ACCESS(dso)->symbol_names);
+ symbols__exit(&RC_CHK_ACCESS(dso)->symbols);
annotated_data_type__tree_delete(dso__data_types(dso));
global_var_type__tree_delete(dso__global_vars(dso));
@@ -1883,22 +1873,34 @@ static size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
return fprintf(fp, "%s", sbuild_id);
}
+struct dso__fprintf_cb_args {
+ FILE *fp;
+ size_t ret;
+};
+
+static int dso__fprintf_cb(struct symbol *pos, void *data)
+{
+ struct dso__fprintf_cb_args *args = data;
+
+ args->ret += symbol__fprintf(pos, args->fp);
+ return 0;
+}
+
size_t dso__fprintf(struct dso *dso, FILE *fp)
{
- struct rb_node *nd;
- size_t ret = fprintf(fp, "dso: %s (", dso__short_name(dso));
+ struct dso__fprintf_cb_args args = {
+ .fp = fp,
+ .ret = fprintf(fp, "dso: %s (", dso__short_name(dso)),
+ };
if (dso__short_name(dso) != dso__long_name(dso))
- ret += fprintf(fp, "%s, ", dso__long_name(dso));
- ret += fprintf(fp, "%sloaded, ", dso__loaded(dso) ? "" : "NOT ");
- ret += dso__fprintf_buildid(dso, fp);
- ret += fprintf(fp, ")\n");
- for (nd = rb_first_cached(dso__symbols(dso)); nd; nd = rb_next(nd)) {
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
- ret += symbol__fprintf(pos, fp);
- }
+ args.ret += fprintf(fp, "%s, ", dso__long_name(dso));
+ args.ret += fprintf(fp, "%sloaded, ", dso__loaded(dso) ? "" : "NOT ");
+ args.ret += dso__fprintf_buildid(dso, fp);
+ args.ret += fprintf(fp, ")\n");
+ dso__for_each_symbol(dso, dso__fprintf_cb, &args);
- return ret;
+ return args.ret;
}
enum dso_type dso__type(struct dso *dso, struct machine *machine)
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index e7d5f4bbf894..1de446966f01 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -13,6 +13,7 @@
#include "build-id.h"
#include "debuginfo.h"
#include "mutex.h"
+#include "symbol.h"
#include <internal/rc_check.h>
struct machine;
@@ -287,18 +288,12 @@ struct auxtrace_cache;
DECLARE_RC_STRUCT(dso) {
struct mutex lock;
struct dsos *dsos;
- struct rb_root_cached symbols;
- struct symbol **symbol_names;
- size_t symbol_names_len;
+ struct symbols symbols;
struct rb_root_cached inlined_nodes;
struct rb_root_cached srclines;
struct rb_root data_types;
struct rb_root global_vars;
- struct {
- u64 addr;
- struct symbol *symbol;
- } last_find_result;
u64 text_offset;
u64 text_end;
const char *short_name;
@@ -343,7 +338,6 @@ DECLARE_RC_STRUCT(dso) {
u8 short_name_allocated:1;
u8 long_name_allocated:1;
u8 is_64_bit:1;
- bool sorted_by_name;
bool loaded;
u8 rel;
char name[];
@@ -357,11 +351,11 @@ int dso_id__cmp(const struct dso_id *a, const struct dso_id *b);
/* dso__for_each_symbol - iterate over the symbols of given type
*
* @dso: the 'struct dso *' in which symbols are iterated
- * @pos: the 'struct symbol *' to use as a loop cursor
- * @n: the 'struct rb_node *' to use as a temporary storage
+ * @cb: callback function invoked for each symbol
+ * @data: opaque data pointer passed to @cb
*/
-#define dso__for_each_symbol(dso, pos, n) \
- symbols__for_each_entry(dso__symbols(dso), pos, n)
+#define dso__for_each_symbol(dso, cb, data) \
+ symbols__for_each_entry(dso__symbols(dso), cb, data)
static inline void *dso__a2l(const struct dso *dso)
{
@@ -590,26 +584,6 @@ static inline void dso__set_kernel(struct dso *dso, enum dso_space_type kernel)
RC_CHK_ACCESS(dso)->kernel = kernel;
}
-static inline u64 dso__last_find_result_addr(const struct dso *dso)
-{
- return RC_CHK_ACCESS(dso)->last_find_result.addr;
-}
-
-static inline void dso__set_last_find_result_addr(struct dso *dso, u64 addr)
-{
- RC_CHK_ACCESS(dso)->last_find_result.addr = addr;
-}
-
-static inline struct symbol *dso__last_find_result_symbol(const struct dso *dso)
-{
- return RC_CHK_ACCESS(dso)->last_find_result.symbol;
-}
-
-static inline void dso__set_last_find_result_symbol(struct dso *dso, struct symbol *symbol)
-{
- RC_CHK_ACCESS(dso)->last_find_result.symbol = symbol;
-}
-
static inline enum dso_load_errno *dso__load_errno(struct dso *dso)
{
return &RC_CHK_ACCESS(dso)->load_errno;
@@ -722,29 +696,19 @@ static inline struct rb_root *dso__global_vars(struct dso *dso)
return &RC_CHK_ACCESS(dso)->global_vars;
}
-static inline struct rb_root_cached *dso__symbols(struct dso *dso)
+static inline struct symbols *dso__symbols(struct dso *dso)
{
return &RC_CHK_ACCESS(dso)->symbols;
}
static inline struct symbol **dso__symbol_names(struct dso *dso)
{
- return RC_CHK_ACCESS(dso)->symbol_names;
-}
-
-static inline void dso__set_symbol_names(struct dso *dso, struct symbol **names)
-{
- RC_CHK_ACCESS(dso)->symbol_names = names;
+ return RC_CHK_ACCESS(dso)->symbols.symbols_by_name;
}
static inline size_t dso__symbol_names_len(struct dso *dso)
{
- return RC_CHK_ACCESS(dso)->symbol_names_len;
-}
-
-static inline void dso__set_symbol_names_len(struct dso *dso, size_t len)
-{
- RC_CHK_ACCESS(dso)->symbol_names_len = len;
+ return RC_CHK_ACCESS(dso)->symbols.num_by_name;
}
static inline const char *dso__symsrc_filename(const struct dso *dso)
@@ -815,13 +779,12 @@ bool dso__loaded(const struct dso *dso);
static inline bool dso__has_symbols(const struct dso *dso)
{
- return !RB_EMPTY_ROOT(&RC_CHK_ACCESS(dso)->symbols.rb_root);
+ return RC_CHK_ACCESS(dso)->symbols.cnt > 0;
}
char *dso__filename_with_chroot(const struct dso *dso, const char *filename);
bool dso__sorted_by_name(const struct dso *dso);
-void dso__set_sorted_by_name(struct dso *dso);
void dso__sort_by_name(struct dso *dso);
int dso__swap_init(struct dso *dso, unsigned char eidata);
@@ -941,8 +904,6 @@ struct map *dso__new_map(const char *name);
struct dso *machine__findnew_kernel(struct machine *machine, const char *name,
const char *short_name, int dso_type);
-void dso__reset_find_symbol_cache(struct dso *dso);
-
size_t dso__fprintf_symbols_by_name(struct dso *dso, FILE *fp);
size_t dso__fprintf(struct dso *dso, FILE *fp);
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index a9f43ac8d152..2e64b3faabc9 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -2981,13 +2981,37 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
return 0;
}
+struct intel_pt_switch_ip_args {
+ struct map *map;
+ const char *name;
+ bool check_global;
+ u64 ip;
+};
+
+static int intel_pt_switch_ip_cb(struct symbol *sym, void *data)
+{
+ struct intel_pt_switch_ip_args *args = data;
+ u64 ip;
+
+ if (args->check_global && symbol__binding(sym) != STB_GLOBAL)
+ return 0;
+
+ if (!strcmp(symbol__name(sym), args->name)) {
+ ip = map__unmap_ip(args->map, symbol__start(sym));
+ if (ip >= map__start(args->map) && ip < map__end(args->map)) {
+ args->ip = ip;
+ return 1;
+ }
+ }
+ return 0;
+}
+
static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
{
struct machine *machine = pt->machine;
struct map *map;
- struct symbol *sym, *start;
- u64 ip, switch_ip = 0;
- const char *ptss;
+ struct intel_pt_switch_ip_args args;
+ u64 switch_ip = 0;
if (ptss_ip)
*ptss_ip = 0;
@@ -2999,36 +3023,28 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
if (map__load(map))
return 0;
- start = dso__first_symbol(map__dso(map));
-
- for (sym = start; sym; sym = dso__next_symbol(sym)) {
- if (symbol__binding(sym) == STB_GLOBAL &&
- !strcmp(symbol__name(sym), "__switch_to")) {
- ip = map__unmap_ip(map, symbol__start(sym));
- if (ip >= map__start(map) && ip < map__end(map)) {
- switch_ip = ip;
- break;
- }
- }
- }
+ args = (struct intel_pt_switch_ip_args) {
+ .map = map,
+ .name = "__switch_to",
+ .check_global = true,
+ .ip = 0,
+ };
+ map__for_each_symbol(map, intel_pt_switch_ip_cb, &args);
+ switch_ip = args.ip;
if (!switch_ip || !ptss_ip)
return 0;
- if (pt->have_sched_switch == 1)
- ptss = "perf_trace_sched_switch";
- else
- ptss = "__perf_event_task_sched_out";
-
- for (sym = start; sym; sym = dso__next_symbol(sym)) {
- if (!strcmp(symbol__name(sym), ptss)) {
- ip = map__unmap_ip(map, symbol__start(sym));
- if (ip >= map__start(map) && ip < map__end(map)) {
- *ptss_ip = ip;
- break;
- }
- }
- }
+ args = (struct intel_pt_switch_ip_args) {
+ .map = map,
+ .name = pt->have_sched_switch == 1 ?
+ "perf_trace_sched_switch" :
+ "__perf_event_task_sched_out",
+ .check_global = false,
+ .ip = 0,
+ };
+ map__for_each_symbol(map, intel_pt_switch_ip_cb, &args);
+ *ptss_ip = args.ip;
return switch_ip;
}
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index fa2bd8e0e1f1..cb30d858f62d 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1095,29 +1095,35 @@ int machine__create_extra_kernel_map(struct machine *machine,
return err;
}
-static u64 find_entry_trampoline(struct dso *dso)
+static int find_entry_trampoline_cb(struct symbol *sym, void *data)
{
/* Duplicates are removed so lookup all aliases */
- const char *syms[] = {
+ static const char * const syms[] = {
"_entry_trampoline",
"__entry_trampoline_start",
"entry_SYSCALL_64_trampoline",
};
- struct symbol *sym = dso__first_symbol(dso);
- unsigned int i;
+ u64 *addr = data;
- for (; sym; sym = dso__next_symbol(sym)) {
- if (symbol__binding(sym) != STB_GLOBAL)
- continue;
- for (i = 0; i < ARRAY_SIZE(syms); i++) {
- if (!strcmp(symbol__name(sym), syms[i]))
- return symbol__start(sym);
+ if (symbol__binding(sym) != STB_GLOBAL)
+ return 0;
+ for (unsigned int i = 0; i < ARRAY_SIZE(syms); i++) {
+ if (!strcmp(symbol__name(sym), syms[i])) {
+ *addr = symbol__start(sym);
+ return 1;
}
}
-
return 0;
}
+static u64 find_entry_trampoline(struct dso *dso)
+{
+ u64 addr = 0;
+
+ dso__for_each_symbol(dso, find_entry_trampoline_cb, &addr);
+ return addr;
+}
+
/*
* These values can be used for kernels that do not have symbols for the entry
* trampolines in kallsyms.
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 85216fa71f1a..19afe676adf2 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -314,27 +314,22 @@ void map__put(struct map *map)
void map__fixup_start(struct map *map)
{
- struct dso *dso = map__dso(map);
- struct rb_root_cached *symbols = dso__symbols(dso);
- struct rb_node *nd = rb_first_cached(symbols);
-
- if (nd != NULL) {
- struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+ struct symbols *symbols = dso__symbols(map__dso(map));
- map__set_start(map, symbol__start(sym));
- }
+ symbols__sort_read_lock(symbols);
+ if (symbols->cnt > 0)
+ map__set_start(map, symbol__start(symbols->symbols[0]));
+ up_read(&symbols->lock);
}
void map__fixup_end(struct map *map)
{
- struct dso *dso = map__dso(map);
- struct rb_root_cached *symbols = dso__symbols(dso);
- struct rb_node *nd = rb_last(&symbols->rb_root);
+ struct symbols *symbols = dso__symbols(map__dso(map));
- if (nd != NULL) {
- struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
- map__set_end(map, symbol__end(sym));
- }
+ symbols__sort_read_lock(symbols);
+ if (symbols->cnt > 0)
+ map__set_end(map, symbol__end(symbols->symbols[symbols->cnt - 1]));
+ up_read(&symbols->lock);
}
#define DSO__DELETED "(deleted)"
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index f49b4aaacf2f..3d8f72e70d49 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -146,12 +146,12 @@ struct thread;
/* map__for_each_symbol - iterate over the symbols in the given map
*
* @map: the 'struct map *' in which symbols are iterated
- * @pos: the 'struct symbol *' to use as a loop cursor
- * @n: the 'struct rb_node *' to use as a temporary storage
+ * @cb: callback function invoked for each symbol
+ * @data: opaque data pointer passed to @cb
* Note: caller must ensure map->dso is not NULL (map is loaded).
*/
-#define map__for_each_symbol(map, pos, n) \
- dso__for_each_symbol(map__dso(map), pos, n)
+#define map__for_each_symbol(map, cb, data) \
+ dso__for_each_symbol(map__dso(map), cb, data)
/* map__for_each_symbol_with_name - iterate over the symbols in the given map
* that have the given name
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 128076a4b92d..47dbe865c2f9 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -3047,49 +3047,63 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
return ret;
}
-static int find_probe_functions(struct map *map, char *name,
- struct symbol **syms)
+struct find_probe_functions_args {
+ const char *name;
+ struct symbol **syms;
+ int found;
+ bool cut_version;
+};
+
+static int find_probe_functions_cb(struct symbol *sym, void *data)
{
- int found = 0;
- struct symbol *sym;
- struct rb_node *tmp;
+ struct find_probe_functions_args *args = data;
const char *norm, *ver;
char *buf = NULL;
- bool cut_version = true;
-
- if (map__load(map) < 0)
- return -EACCES; /* Possible permission error to load symbols */
- /* If user gives a version, don't cut off the version from symbols */
- if (strchr(name, '@'))
- cut_version = false;
-
- map__for_each_symbol(map, sym, tmp) {
- norm = arch__normalize_symbol_name(symbol__name(sym));
- if (!norm)
- continue;
+ norm = arch__normalize_symbol_name(symbol__name(sym));
+ if (!norm)
+ return 0;
- if (cut_version) {
- /* We don't care about default symbol or not */
- ver = strchr(norm, '@');
- if (ver) {
- buf = strndup(norm, ver - norm);
- if (!buf)
- return -ENOMEM;
- norm = buf;
- }
+ if (args->cut_version) {
+ /* We don't care about default symbol or not */
+ ver = strchr(norm, '@');
+ if (ver) {
+ buf = strndup(norm, ver - norm);
+ if (!buf)
+ return -ENOMEM;
+ norm = buf;
}
+ }
- if (strglobmatch(norm, name)) {
- found++;
- if (syms && found < probe_conf.max_probes)
- syms[found - 1] = sym;
- }
- if (buf)
- zfree(&buf);
+ if (strglobmatch(norm, args->name)) {
+ args->found++;
+ if (args->syms && args->found < probe_conf.max_probes)
+ args->syms[args->found - 1] = sym;
}
+ free(buf);
+ return 0;
+}
+
+static int find_probe_functions(struct map *map, char *name,
+ struct symbol **syms)
+{
+ struct find_probe_functions_args args = {
+ .name = name,
+ .syms = syms,
+ /* If user gives a version, don't cut off the version from symbols */
+ .cut_version = strchr(name, '@') == NULL,
+ .found = 0,
+ };
+ int ret;
+
+ if (map__load(map) < 0)
+ return -EACCES; /* Possible permission error to load symbols */
+
+ ret = map__for_each_symbol(map, find_probe_functions_cb, &args);
+ if (ret < 0)
+ return ret;
- return found;
+ return args.found;
}
void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused,
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 2ec650a7834d..d25d8c96ee66 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -213,57 +213,157 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
return arch__choose_best_symbol(syma, symb);
}
-void symbols__fixup_duplicate(struct rb_root_cached *symbols)
+void symbols__init(struct symbols *symbols)
{
- struct rb_node *nd;
- struct symbol *curr, *next;
+ init_rwsem(&symbols->lock);
+ symbols->symbols = NULL;
+ symbols->symbols_by_name = NULL;
+ symbols->cnt = 0;
+ symbols->allocated = 0;
+ symbols->num_by_name = 0;
+ symbols->sorted = true;
+ symbols->sorted_by_name = false;
+}
+
+static void symbols__delete_locked(struct symbols *symbols)
+{
+ for (unsigned int i = 0; i < symbols->cnt; i++)
+ symbol__delete(symbols->symbols[i]);
+
+ zfree(&symbols->symbols);
+ zfree(&symbols->symbols_by_name);
+ symbols->cnt = 0;
+ symbols->allocated = 0;
+ symbols->num_by_name = 0;
+ symbols->sorted = true;
+ symbols->sorted_by_name = false;
+}
+
+void symbols__delete(struct symbols *symbols)
+{
+ down_write(&symbols->lock);
+ symbols__delete_locked(symbols);
+ up_write(&symbols->lock);
+}
+
+void symbols__exit(struct symbols *symbols)
+{
+ symbols__delete(symbols);
+ exit_rwsem(&symbols->lock);
+}
+
+static inline bool symbol__less_or_equal(const struct symbol *a, const struct symbol *b)
+{
+ if (symbol__start(a) != symbol__start(b))
+ return symbol__start(a) < symbol__start(b);
+ return symbol__end(a) <= symbol__end(b);
+}
+
+static int symbols__sort_cmp(const void *vlhs, const void *vrhs)
+{
+ const struct symbol *lhs = *((const struct symbol **)vlhs);
+ const struct symbol *rhs = *((const struct symbol **)vrhs);
+
+ if (symbol__start(lhs) != symbol__start(rhs))
+ return symbol__start(lhs) < symbol__start(rhs) ? -1 : 1;
+ if (symbol__end(lhs) != symbol__end(rhs))
+ return symbol__end(lhs) < symbol__end(rhs) ? -1 : 1;
+ return 0;
+}
+
+static void symbols__sort_locked(struct symbols *symbols)
+{
+ if (symbols->sorted)
+ return;
+
+ if (symbols->cnt > 1) {
+ qsort(symbols->symbols, symbols->cnt, sizeof(struct symbol *),
+ symbols__sort_cmp);
+ }
+ symbols->sorted = true;
+}
+
+/*
+ * Acquire @symbols->lock for reading after ensuring @symbols->symbols is
+ * sorted.
+ */
+void symbols__sort_read_lock(struct symbols *symbols)
+ NO_THREAD_SAFETY_ANALYSIS
+{
+ down_read(&symbols->lock);
+ while (!symbols->sorted) {
+ up_read(&symbols->lock);
+ down_write(&symbols->lock);
+ symbols__sort_locked(symbols);
+ up_write(&symbols->lock);
+ down_read(&symbols->lock);
+ }
+}
+
+/*
+ * Deduplicate symbols sharing the same start address by sorting @symbols and
+ * compacting the array in place, keeping the best symbol at each address as
+ * chosen by choose_best_symbol().
+ */
+void symbols__fixup_duplicate(struct symbols *symbols)
+{
+ unsigned int write_idx = 0;
if (symbol_conf.allow_aliases)
return;
- nd = rb_first_cached(symbols);
+ down_write(&symbols->lock);
+ symbols__sort_locked(symbols);
+ if (symbols->cnt <= 1) {
+ up_write(&symbols->lock);
+ return;
+ }
- while (nd) {
- curr = rb_entry(nd, struct symbol, rb_node);
-again:
- nd = rb_next(&curr->rb_node);
- if (!nd)
- break;
+ for (unsigned int read_idx = 1; read_idx < symbols->cnt; read_idx++) {
+ struct symbol *curr = symbols->symbols[write_idx];
+ struct symbol *next = symbols->symbols[read_idx];
- next = rb_entry(nd, struct symbol, rb_node);
- if (symbol__start(curr) != symbol__start(next))
+ if (symbol__start(curr) != symbol__start(next)) {
+ symbols->symbols[++write_idx] = next;
continue;
+ }
if (choose_best_symbol(curr, next) == SYMBOL_A) {
if (symbol__type(next) == STT_GNU_IFUNC)
symbol__set_ifunc_alias(curr, true);
- rb_erase_cached(&next->rb_node, symbols);
symbol__delete(next);
- goto again;
} else {
if (symbol__type(curr) == STT_GNU_IFUNC)
symbol__set_ifunc_alias(next, true);
- nd = rb_next(&curr->rb_node);
- rb_erase_cached(&curr->rb_node, symbols);
symbol__delete(curr);
+ symbols->symbols[write_idx] = next;
}
}
+ symbols->cnt = write_idx + 1;
+ zfree(&symbols->symbols_by_name);
+ symbols->num_by_name = 0;
+ symbols->sorted_by_name = false;
+ up_write(&symbols->lock);
}
/* Update zero-sized symbols using the address of the next symbol */
-void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms)
+void symbols__fixup_end(struct symbols *symbols, bool is_kallsyms)
{
- struct rb_node *nd, *prevnd = rb_first_cached(symbols);
struct symbol *curr, *prev;
- if (prevnd == NULL)
+ down_write(&symbols->lock);
+ symbols__sort_locked(symbols);
+
+ if (symbols->cnt == 0) {
+ up_write(&symbols->lock);
return;
+ }
- curr = rb_entry(prevnd, struct symbol, rb_node);
+ curr = symbols->symbols[0];
- for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+ for (unsigned int i = 1; i < symbols->cnt; i++) {
prev = curr;
- curr = rb_entry(nd, struct symbol, rb_node);
+ curr = symbols->symbols[i];
/*
* On some architecture kernel text segment start is located at
@@ -314,6 +414,8 @@ void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms)
if (symbol__end(curr) == symbol__start(curr))
symbol__set_end(curr,
roundup(symbol__start(curr), 4096) + 4096);
+
+ up_write(&symbols->lock);
}
struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name)
@@ -395,97 +497,92 @@ static void symbol__set_idle(struct symbol *sym, bool idle)
new_flags |= (idle_val << SYMBOL_FLAG_IDLE_SHIFT);
} while (!atomic_compare_exchange_weak(&sym->flags, &old_flags, new_flags));
}
-void symbols__delete(struct rb_root_cached *symbols)
-{
- struct symbol *pos;
- struct rb_node *next = rb_first_cached(symbols);
- while (next) {
- pos = rb_entry(next, struct symbol, rb_node);
- next = rb_next(&pos->rb_node);
- rb_erase_cached(&pos->rb_node, symbols);
- symbol__delete(pos);
- }
-}
-
-void __symbols__insert(struct rb_root_cached *symbols, struct symbol *sym)
+int __symbols__insert(struct symbols *symbols, struct symbol *sym)
{
- struct rb_node **p = &symbols->rb_root.rb_node;
- struct rb_node *parent = NULL;
- const u64 ip = symbol__start(sym);
- struct symbol *s;
- bool leftmost = true;
+ if (symbols->cnt == symbols->allocated) {
+ unsigned int to_allocate = symbols->allocated ? symbols->allocated * 2 : 32;
+ struct symbol **temp = realloc(symbols->symbols,
+ sizeof(struct symbol *) * to_allocate);
- while (*p != NULL) {
- parent = *p;
- s = rb_entry(parent, struct symbol, rb_node);
- if (ip < symbol__start(s))
- p = &(*p)->rb_left;
- else {
- p = &(*p)->rb_right;
- leftmost = false;
+ if (!temp) {
+ symbol__delete(sym);
+ return -ENOMEM;
}
+ symbols->symbols = temp;
+ symbols->allocated = to_allocate;
}
- rb_link_node(&sym->rb_node, parent, p);
- rb_insert_color_cached(&sym->rb_node, symbols, leftmost);
+
+ if (symbols->sorted && symbols->cnt > 0 &&
+ !symbol__less_or_equal(symbols->symbols[symbols->cnt - 1], sym))
+ symbols->sorted = false;
+
+ symbols->symbols[symbols->cnt++] = sym;
+ symbols->sorted_by_name = false;
+ return 0;
}
-void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym)
+int symbols__insert(struct symbols *symbols, struct symbol *sym)
{
- __symbols__insert(symbols, sym);
+ int ret;
+
+ down_write(&symbols->lock);
+ ret = __symbols__insert(symbols, sym);
+ up_write(&symbols->lock);
+ return ret;
}
-static struct symbol *symbols__find(struct rb_root_cached *symbols, u64 ip)
+/*
+ * Binary search @symbols->symbols for a symbol covering @ip. Lazily sorts
+ * @symbols under @symbols->lock if unsorted.
+ */
+static struct symbol *symbols__find(struct symbols *symbols, u64 ip)
{
- struct rb_node *n;
+ int low, high;
+ struct symbol *res = NULL;
if (symbols == NULL)
return NULL;
- n = symbols->rb_root.rb_node;
+ symbols__sort_read_lock(symbols);
- while (n) {
- struct symbol *s = rb_entry(n, struct symbol, rb_node);
+ low = 0;
+ high = (int)symbols->cnt - 1;
+ while (low <= high) {
+ int mid = low + (high - low) / 2;
+ struct symbol *s = symbols->symbols[mid];
+ u64 start = symbol__start(s);
+ u64 end = symbol__end(s);
- if (ip < symbol__start(s))
- n = n->rb_left;
- else if (ip > symbol__end(s) || (ip == symbol__end(s) && ip != symbol__start(s)))
- n = n->rb_right;
- else
- return s;
+ if (ip < start)
+ high = mid - 1;
+ else if (ip > end || (ip == end && ip != start))
+ low = mid + 1;
+ else {
+ res = s;
+ break;
+ }
}
+ up_read(&symbols->lock);
- return NULL;
-}
-
-static struct symbol *symbols__first(struct rb_root_cached *symbols)
-{
- struct rb_node *n = rb_first_cached(symbols);
-
- if (n)
- return rb_entry(n, struct symbol, rb_node);
-
- return NULL;
+ return res;
}
-static struct symbol *symbols__last(struct rb_root_cached *symbols)
+int symbols__for_each_entry(struct symbols *symbols,
+ int (*cb)(struct symbol *sym, void *data),
+ void *data)
{
- struct rb_node *n = rb_last(&symbols->rb_root);
-
- if (n)
- return rb_entry(n, struct symbol, rb_node);
-
- return NULL;
-}
-
-static struct symbol *symbols__next(struct symbol *sym)
-{
- struct rb_node *n = rb_next(&sym->rb_node);
+ int err = 0;
- if (n)
- return rb_entry(n, struct symbol, rb_node);
+ symbols__sort_read_lock(symbols);
+ for (unsigned int i = 0; i < symbols->cnt; i++) {
+ err = cb(symbols->symbols[i], data);
+ if (err)
+ break;
+ }
+ up_read(&symbols->lock);
- return NULL;
+ return err;
}
static int symbols__sort_name_cmp(const void *vlhs, const void *vrhs)
@@ -496,27 +593,31 @@ static int symbols__sort_name_cmp(const void *vlhs, const void *vrhs)
return strcmp(symbol__name(lhs), symbol__name(rhs));
}
-static struct symbol **symbols__sort_by_name(struct rb_root_cached *source, size_t *len)
+static void symbols__sort_by_name_locked(struct symbols *symbols)
{
- struct rb_node *nd;
struct symbol **result;
- size_t i = 0, size = 0;
+ unsigned int size = symbols->cnt;
- for (nd = rb_first_cached(source); nd; nd = rb_next(nd))
- size++;
+ if (symbols->sorted_by_name)
+ return;
+
+ zfree(&symbols->symbols_by_name);
+ symbols->num_by_name = 0;
+
+ if (size == 0) {
+ symbols->sorted_by_name = true;
+ return;
+ }
result = malloc(sizeof(*result) * size);
if (!result)
- return NULL;
-
- for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) {
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+ return;
- result[i++] = pos;
- }
+ memcpy(result, symbols->symbols, sizeof(*result) * size);
qsort(result, size, sizeof(*result), symbols__sort_name_cmp);
- *len = size;
- return result;
+ symbols->symbols_by_name = result;
+ symbols->num_by_name = size;
+ symbols->sorted_by_name = true;
}
int symbol__match_symbol_name(const char *name, const char *str,
@@ -586,39 +687,34 @@ static struct symbol *symbols__find_by_name(struct symbol *symbols[],
return s;
}
-void dso__reset_find_symbol_cache(struct dso *dso)
+int dso__insert_symbol(struct dso *dso, struct symbol *sym)
{
- dso__set_last_find_result_addr(dso, 0);
- dso__set_last_find_result_symbol(dso, NULL);
-}
-
-void dso__insert_symbol(struct dso *dso, struct symbol *sym)
-{
- __symbols__insert(dso__symbols(dso), sym);
-
- /* update the symbol cache if necessary */
- if (dso__last_find_result_addr(dso) >= symbol__start(sym) &&
- (dso__last_find_result_addr(dso) < symbol__end(sym) ||
- symbol__start(sym) == symbol__end(sym))) {
- dso__set_last_find_result_symbol(dso, sym);
- }
+ return symbols__insert(dso__symbols(dso), sym);
}
void dso__delete_symbol(struct dso *dso, struct symbol *sym)
{
- rb_erase_cached(&sym->rb_node, dso__symbols(dso));
- symbol__delete(sym);
- dso__reset_find_symbol_cache(dso);
+ struct symbols *symbols = dso__symbols(dso);
+
+ down_write(&symbols->lock);
+ for (unsigned int i = 0; i < symbols->cnt; i++) {
+ if (symbols->symbols[i] == sym) {
+ memmove(&symbols->symbols[i], &symbols->symbols[i + 1],
+ (symbols->cnt - i - 1) * sizeof(struct symbol *));
+ symbols->cnt--;
+ zfree(&symbols->symbols_by_name);
+ symbols->num_by_name = 0;
+ symbols->sorted_by_name = false;
+ symbol__delete(sym);
+ break;
+ }
+ }
+ up_write(&symbols->lock);
}
struct symbol *dso__find_symbol(struct dso *dso, u64 addr)
{
- if (dso__last_find_result_addr(dso) != addr || dso__last_find_result_symbol(dso) == NULL) {
- dso__set_last_find_result_addr(dso, addr);
- dso__set_last_find_result_symbol(dso, symbols__find(dso__symbols(dso), addr));
- }
-
- return dso__last_find_result_symbol(dso);
+ return symbols__find(dso__symbols(dso), addr);
}
struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr)
@@ -626,21 +722,6 @@ struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr)
return symbols__find(dso__symbols(dso), addr);
}
-struct symbol *dso__first_symbol(struct dso *dso)
-{
- return symbols__first(dso__symbols(dso));
-}
-
-struct symbol *dso__last_symbol(struct dso *dso)
-{
- return symbols__last(dso__symbols(dso));
-}
-
-struct symbol *dso__next_symbol(struct symbol *sym)
-{
- return symbols__next(sym);
-}
-
struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx)
{
if (*idx + 1 >= dso__symbol_names_len(dso))
@@ -655,9 +736,12 @@ struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx)
*/
struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name, size_t *idx)
{
- struct symbol *s = symbols__find_by_name(dso__symbol_names(dso),
- dso__symbol_names_len(dso),
- name, SYMBOL_TAG_INCLUDE__NONE, idx);
+ struct symbol *s;
+
+ dso__sort_by_name(dso);
+ s = symbols__find_by_name(dso__symbol_names(dso),
+ dso__symbol_names_len(dso),
+ name, SYMBOL_TAG_INCLUDE__NONE, idx);
if (!s) {
s = symbols__find_by_name(dso__symbol_names(dso), dso__symbol_names_len(dso),
name, SYMBOL_TAG_INCLUDE__DEFAULT_ONLY, idx);
@@ -667,17 +751,17 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name, size_
void dso__sort_by_name(struct dso *dso)
{
- mutex_lock(dso__lock(dso));
- if (!dso__sorted_by_name(dso)) {
- size_t len = 0;
+ struct symbols *symbols = dso__symbols(dso);
- dso__set_symbol_names(dso, symbols__sort_by_name(dso__symbols(dso), &len));
- if (dso__symbol_names(dso)) {
- dso__set_symbol_names_len(dso, len);
- dso__set_sorted_by_name(dso);
- }
+ down_read(&symbols->lock);
+ if (!symbols->sorted_by_name) {
+ up_read(&symbols->lock);
+ down_write(&symbols->lock);
+ symbols__sort_by_name_locked(symbols);
+ up_write(&symbols->lock);
+ return;
}
- mutex_unlock(dso__lock(dso));
+ up_read(&symbols->lock);
}
/*
@@ -877,7 +961,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
{
struct symbol *sym;
struct dso *dso = arg;
- struct rb_root_cached *root = dso__symbols(dso);
+ struct symbols *root = dso__symbols(dso);
if (!symbol_type__filter(type))
return 0;
@@ -898,9 +982,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
* We will pass the symbols to the filter later, in
* map__split_kallsyms, when we have split the maps per module
*/
- __symbols__insert(root, sym);
-
- return 0;
+ return __symbols__insert(root, sym);
}
/*
@@ -917,25 +999,32 @@ static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso)
{
struct symbol *pos;
int count = 0;
- struct rb_root_cached *root = dso__symbols(dso);
- struct rb_root_cached old_root = *root;
- struct rb_node *next = rb_first_cached(root);
+ struct symbols *root = dso__symbols(dso);
+ struct symbol **old_symbols;
+ unsigned int old_cnt;
if (!kmaps)
return -1;
- *root = RB_ROOT_CACHED;
-
- while (next) {
+ down_write(&root->lock);
+ symbols__sort_locked(root);
+ old_symbols = root->symbols;
+ old_cnt = root->cnt;
+ root->symbols = NULL;
+ root->cnt = 0;
+ root->allocated = 0;
+ root->sorted = true;
+ zfree(&root->symbols_by_name);
+ root->num_by_name = 0;
+ root->sorted_by_name = false;
+ up_write(&root->lock);
+
+ for (unsigned int i = 0; i < old_cnt; i++) {
struct map *curr_map;
struct dso *curr_map_dso;
char *module;
- pos = rb_entry(next, struct symbol, rb_node);
- next = rb_next(&pos->rb_node);
-
- rb_erase_cached(&pos->rb_node, &old_root);
- RB_CLEAR_NODE(&pos->rb_node);
+ pos = old_symbols[i];
module = strchr((char *)symbol__name(pos), '\t');
if (module)
*module = '\0';
@@ -955,11 +1044,13 @@ static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso)
symbol__set_end(pos, symbol__end(pos) -
(map__start(curr_map) - map__pgoff(curr_map)));
}
- symbols__insert(dso__symbols(curr_map_dso), pos);
- ++count;
+ if (symbols__insert(dso__symbols(curr_map_dso), pos) == 0)
+ ++count;
map__put(curr_map);
}
+ free(old_symbols);
+
/* Symbols have been adjusted */
dso__set_adjust_symbols(dso, true);
@@ -995,8 +1086,8 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
struct map *curr_map = map__get(initial_map);
struct symbol *pos;
int count = 0, moved = 0;
- struct rb_root_cached *root = dso__symbols(dso);
- struct rb_node *next = rb_first_cached(root);
+ struct symbols *root = dso__symbols(dso);
+ unsigned int i, write_idx = 0;
int kernel_range = 0;
uint16_t e_machine = EM_NONE;
@@ -1006,11 +1097,13 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
machine = maps__machine(kmaps);
e_machine = machine_or_dso_e_machine(machine, dso);
- while (next) {
+ down_write(&root->lock);
+ symbols__sort_locked(root);
+
+ for (i = 0; i < root->cnt; i++) {
char *module;
- pos = rb_entry(next, struct symbol, rb_node);
- next = rb_next(&pos->rb_node);
+ pos = root->symbols[i];
module = strchr((char *)symbol__name(pos), '\t');
if (module) {
@@ -1098,7 +1191,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
ndso = dso__new(dso_name);
map__zput(curr_map);
if (ndso == NULL)
- return -1;
+ goto out_err;
dso__set_kernel(ndso, dso__kernel(dso));
dso__set_loaded(ndso);
@@ -1106,14 +1199,14 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
curr_map = map__new2(symbol__start(pos), ndso);
if (curr_map == NULL) {
dso__put(ndso);
- return -1;
+ goto out_err;
}
map__set_mapping_type(curr_map, MAPPING_TYPE__IDENTITY);
if (maps__insert(kmaps, curr_map)) {
map__zput(curr_map);
dso__put(ndso);
- return -1;
+ goto out_err;
}
dso__put(ndso);
++kernel_range;
@@ -1126,18 +1219,24 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
if (!RC_CHK_EQUAL(curr_map, initial_map)) {
struct dso *curr_map_dso = map__dso(curr_map);
- rb_erase_cached(&pos->rb_node, root);
- symbols__insert(dso__symbols(curr_map_dso), pos);
- ++moved;
- } else
+ if (symbols__insert(dso__symbols(curr_map_dso), pos) == 0)
+ ++moved;
+ } else {
+ root->symbols[write_idx++] = pos;
++count;
+ }
continue;
discard_symbol:
- rb_erase_cached(&pos->rb_node, root);
symbol__delete(pos);
}
+ root->cnt = write_idx;
+ zfree(&root->symbols_by_name);
+ root->num_by_name = 0;
+ root->sorted_by_name = false;
+ up_write(&root->lock);
+
if (!RC_CHK_EQUAL(curr_map, initial_map) &&
dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST &&
machine__is_default_guest(maps__machine(kmaps))) {
@@ -1145,6 +1244,16 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
}
map__put(curr_map);
return count + moved;
+
+out_err:
+ memmove(&root->symbols[write_idx], &root->symbols[i],
+ (root->cnt - i) * sizeof(struct symbol *));
+ root->cnt = write_idx + (root->cnt - i);
+ zfree(&root->symbols_by_name);
+ root->num_by_name = 0;
+ root->sorted_by_name = false;
+ up_write(&root->lock);
+ return -1;
}
bool symbol__restricted_filename(const char *filename,
@@ -1705,7 +1814,8 @@ static int dso__load_perf_map(const char *map_path, struct dso *dso)
if (sym == NULL)
goto out_delete_line;
- symbols__insert(dso__symbols(dso), sym);
+ if (symbols__insert(dso__symbols(dso), sym))
+ goto out_delete_line;
nr_syms++;
}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 100a7da07834..52cd6b43696c 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -15,6 +15,7 @@
#include <errno.h>
#include "addr_location.h"
#include "path.h"
+#include "rwsem.h"
#include "symbol_conf.h"
#include "spark.h"
#include "util.h"
@@ -93,7 +94,6 @@ enum symbol_idle_kind {
* A symtab entry.
*/
struct symbol {
- struct rb_node rb_node;
/** Range of symbol [start, end). */
u64 start;
u64 end;
@@ -106,8 +106,42 @@ struct symbol {
char name[];
};
+/**
+ * struct symbols - A locked collection of symbols stored in a sorted array.
+ */
+struct symbols {
+ /** @lock: Read/write semaphore synchronizing access to the arrays. */
+ struct rw_semaphore lock;
+ /**
+ * @symbols: Dynamically allocated array of symbol pointers, sorted by
+ * address range [start, end) when @sorted is true.
+ */
+ struct symbol **symbols;
+ /**
+ * @symbols_by_name: Optional dynamically allocated array of symbol
+ * pointers sorted lexicographically by symbol__name().
+ */
+ struct symbol **symbols_by_name;
+ /** @cnt: Number of valid entries in @symbols. */
+ unsigned int cnt;
+ /** @allocated: Capacity (in entries) of the @symbols allocation. */
+ unsigned int allocated;
+ /** @num_by_name: Number of valid entries in @symbols_by_name. */
+ unsigned int num_by_name;
+ /** @sorted: True when @symbols is sorted by address range. */
+ bool sorted;
+ /**
+ * @sorted_by_name: True when @symbols_by_name is populated and sorted
+ * by name.
+ */
+ bool sorted_by_name;
+};
+
void symbol__delete(struct symbol *sym);
-void symbols__delete(struct rb_root_cached *symbols);
+void symbols__init(struct symbols *symbols);
+void symbols__exit(struct symbols *symbols);
+void symbols__delete(struct symbols *symbols);
+void symbols__sort_read_lock(struct symbols *symbols) SHARED_LOCK_FUNCTION(symbols->lock);
static inline u64 symbol__start(const struct symbol *sym)
{
@@ -199,16 +233,16 @@ void symbol__set_inlined(struct symbol *sym, bool inlined);
void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias);
void symbol__set_annotated(struct symbol *sym, bool annotated);
-/* symbols__for_each_entry - iterate over symbols (rb_root)
+/*
+ * symbols__for_each_entry - iterate over symbols calling @cb for each entry
*
- * @symbols: the rb_root of symbols
- * @pos: the 'struct symbol *' to use as a loop cursor
- * @nd: the 'struct rb_node *' to use as a temporary storage
+ * @symbols: the 'struct symbols *' of symbols
+ * @cb: callback function invoked under @symbols->lock
+ * @data: opaque data pointer passed to @cb
*/
-#define symbols__for_each_entry(symbols, pos, nd) \
- for (nd = rb_first_cached(symbols); \
- nd && (pos = rb_entry(nd, struct symbol, rb_node)); \
- nd = rb_next(nd))
+int symbols__for_each_entry(struct symbols *symbols,
+ int (*cb)(struct symbol *sym, void *data),
+ void *data);
static inline size_t symbol__size(const struct symbol *sym)
{
@@ -245,8 +279,8 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
bool no_kcore);
int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map);
-void dso__insert_symbol(struct dso *dso,
- struct symbol *sym);
+int dso__insert_symbol(struct dso *dso,
+ struct symbol *sym);
void dso__delete_symbol(struct dso *dso,
struct symbol *sym);
@@ -256,10 +290,6 @@ struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr);
struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx);
struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name, size_t *idx);
-struct symbol *dso__first_symbol(struct dso *dso);
-struct symbol *dso__last_symbol(struct dso *dso);
-struct symbol *dso__next_symbol(struct symbol *sym);
-
enum dso_type dso__type_fd(int fd);
int filename__read_build_id(const char *filename, struct build_id *id);
@@ -310,10 +340,10 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss);
char *dso__demangle_sym(struct dso *dso, int kmodule, const char *elf_name);
-void __symbols__insert(struct rb_root_cached *symbols, struct symbol *sym);
-void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym);
-void symbols__fixup_duplicate(struct rb_root_cached *symbols);
-void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms);
+int __symbols__insert(struct symbols *symbols, struct symbol *sym);
+int symbols__insert(struct symbols *symbols, struct symbol *sym);
+void symbols__fixup_duplicate(struct symbols *symbols);
+void symbols__fixup_end(struct symbols *symbols, bool is_kallsyms);
typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 4/7] perf symbol: Add reference counting and DECLARE_RC_STRUCT(symbol)
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
` (2 preceding siblings ...)
2026-09-28 7:52 ` [PATCH v1 3/7] perf symbol: Switch backing storage from rbtree to struct symbols array Ian Rogers
@ 2026-09-28 7:52 ` Ian Rogers
2026-09-28 7:52 ` [PATCH v1 5/7] perf symbol: Add LRU memory shrinking for symbols, DSOs, and machines Ian Rogers
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Rogers @ 2026-09-28 7:52 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter, James Clark,
linux-perf-users, linux-kernel, Alireza Haghdoost
Wrap struct symbol with DECLARE_RC_STRUCT(symbol) and add a refcount_t
refcnt field along with symbol__get(), symbol__put(), and symbol__zput()
helpers:
- Return a counted symbol reference acquired under symbols->lock from
symbol lookup functions (symbols__find(), dso__find_symbol(),
map__find_symbol(), dso__find_symbol_by_name(),
map__find_symbol_by_name(), dso__first_symbol(), dso__last_symbol())
and iteration helpers (symbols__first_by_idx(),
symbols__next_by_idx(), symbols__for_each_entry()).
- Update util/annotate.c and util/db-export.c to hash and compare the
underlying RC_STRUCT(symbol) pointer via RC_CHK_ACCESS(sym) and
RC_CHK_EQUAL() so REFCNT_CHECKING wrapper pointers for the same
symbol resolve to the same hashmap entry, and hold a symbol reference
in struct db_export's sym_db_ids hashmap.
- Update struct addr_location, struct map_symbol, struct call_path,
struct block_info, struct disasm_line, struct annotated_op_loc, struct
c2c_sym_Key, inline_list, srcline, thread_stack, and hist/sort/unwind
consumers to acquire and release symbol references and use
RC_CHK_EQUAL() for pointer identity comparisons.
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-kallsyms.c | 2 +
tools/perf/builtin-lock.c | 17 ++-
tools/perf/builtin-script.c | 4 +-
tools/perf/builtin-top.c | 2 +-
tools/perf/builtin-trace.c | 1 +
tools/perf/tests/dlfilter-test.c | 8 +-
tools/perf/tests/hists_cumulate.c | 4 +-
tools/perf/tests/hists_filter.c | 10 +-
tools/perf/tests/hists_link.c | 16 ++-
tools/perf/tests/hists_output.c | 7 +-
tools/perf/tests/kallsyms-split.c | 5 +-
tools/perf/tests/pe-file-parsing.c | 1 +
tools/perf/tests/vmlinux-kallsyms.c | 12 +-
tools/perf/ui/browsers/hists.c | 7 +-
tools/perf/ui/browsers/map.c | 7 +-
tools/perf/ui/stdio/hist.c | 3 +-
tools/perf/util/addr_location.c | 4 +
.../perf/util/annotate-arch/annotate-alpha.c | 2 +-
.../util/annotate-arch/annotate-loongarch.c | 4 +-
tools/perf/util/annotate-arch/annotate-s390.c | 2 +-
tools/perf/util/annotate.c | 22 ++-
tools/perf/util/block-info.c | 6 +-
tools/perf/util/bpf_lock_contention.c | 27 +++-
tools/perf/util/c2c-function.c | 13 +-
tools/perf/util/call-path.c | 15 +-
tools/perf/util/callchain.c | 4 +-
tools/perf/util/capstone.c | 1 +
tools/perf/util/db-export.c | 35 ++++-
tools/perf/util/disasm.c | 12 +-
tools/perf/util/event.c | 8 +-
tools/perf/util/hist.c | 13 +-
tools/perf/util/libdw.c | 5 +-
tools/perf/util/lock-contention.c | 8 +-
tools/perf/util/machine.c | 48 +++++--
tools/perf/util/map.h | 10 +-
tools/perf/util/map_symbol.c | 4 +-
tools/perf/util/maps.c | 3 +-
tools/perf/util/probe-event.c | 17 ++-
tools/perf/util/python.c | 12 +-
tools/perf/util/sort.c | 2 +-
tools/perf/util/srcline.c | 6 +-
tools/perf/util/symbol-elf.c | 6 +-
tools/perf/util/symbol.c | 129 +++++++++++-------
tools/perf/util/symbol.h | 60 +++++---
tools/perf/util/thread-stack.c | 12 +-
tools/perf/util/threads.c | 17 ++-
tools/perf/util/unwind-libdw.c | 2 +-
tools/perf/util/unwind-libunwind.c | 2 +-
48 files changed, 427 insertions(+), 190 deletions(-)
diff --git a/tools/perf/builtin-kallsyms.c b/tools/perf/builtin-kallsyms.c
index eb62bb4ea602..5b1b87cd54d4 100644
--- a/tools/perf/builtin-kallsyms.c
+++ b/tools/perf/builtin-kallsyms.c
@@ -53,6 +53,8 @@ static int __cmd_kallsyms(int argc, const char **argv)
map__unmap_ip(map, symbol__start(symbol)),
map__unmap_ip(map, symbol__end(symbol)),
symbol__start(symbol), symbol__end(symbol));
+ symbol__put(symbol);
+ map__put(map);
}
out:
machine__delete(machine);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index cd060c984068..9b495703cf0c 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -1003,12 +1003,16 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
(filters.nr_addrs + 1) * sizeof(*addrs));
if (addrs == NULL) {
pr_warning("memory allocation failure\n");
+ symbol__put(sym);
+ map__put(kmap);
return -ENOMEM;
}
addrs[filters.nr_addrs++] = map__unmap_ip(kmap,
symbol__start(sym));
filters.addrs = addrs;
+ symbol__put(sym);
+ map__put(kmap);
}
}
@@ -1019,9 +1023,12 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
switch (aggr_mode) {
case LOCK_AGGR_ADDR:
- sym = machine__find_kernel_symbol(machine, key, &kmap);
- if (sym)
- name = symbol__name(sym);
+ sym = machine__find_kernel_symbol(machine, key, NULL);
+ if (sym) {
+ scnprintf(buf, sizeof(buf), "%s", symbol__name(sym));
+ name = buf;
+ symbol__put(sym);
+ }
break;
case LOCK_AGGR_CALLER:
name = buf;
@@ -1668,6 +1675,8 @@ static void print_lock_stat_stdio(struct lock_contention *con, struct lock_stat
ip = st->callstack[i];
sym = machine__find_kernel_symbol(con->machine, ip, &kmap);
get_symbol_name_offset(kmap, sym, ip, buf, sizeof(buf));
+ symbol__put(sym);
+ map__put(kmap);
fprintf(lock_output, "\t\t\t%#lx %s\n", (unsigned long)ip, buf);
}
}
@@ -1721,6 +1730,8 @@ static void print_lock_stat_csv(struct lock_contention *con, struct lock_stat *s
ip = st->callstack[i];
sym = machine__find_kernel_symbol(con->machine, ip, &kmap);
get_symbol_name_offset(kmap, sym, ip, buf, sizeof(buf));
+ symbol__put(sym);
+ map__put(kmap);
fprintf(lock_output, "%s %#lx %s", i ? ":" : sep, (unsigned long) ip, buf);
}
fprintf(lock_output, "\n");
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index f1257a78d975..4b6157fa87b9 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1426,7 +1426,8 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
if (PRINT_FIELD(SRCLINE))
printed += map__fprintf_srcline(al.map, al.addr, "\t", fp);
printed += fprintf(fp, "\n");
- *lastsym = al.sym;
+ symbol__put(*lastsym);
+ *lastsym = symbol__get(al.sym);
ret = printed;
out:
@@ -1593,6 +1594,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
print_srccode(thread, x.cpumode, start + off);
}
out:
+ symbol__put(lastsym);
return printed;
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 19a21348823c..dd1e475bb4dd 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -211,7 +211,7 @@ static void perf_top__record_precise_ip(struct perf_top *top,
if (sym == NULL || (use_browser == 0 &&
(top->sym_filter_entry == NULL ||
- top->sym_filter_entry->ms.sym != sym)))
+ !RC_CHK_EQUAL(top->sym_filter_entry->ms.sym, sym))))
return;
notes = symbol__annotation(sym);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index aaa090912409..ab970fd45e26 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -778,6 +778,7 @@ size_t syscall_arg__scnprintf_ksym(char *bf, size_t size, struct syscall_arg *ar
else
printed = scnprintf(bf, size, "%s+0x%" PRIx64,
symbol__name(sym), offset);
+ symbol__put(sym);
map__put(map);
return printed;
}
diff --git a/tools/perf/tests/dlfilter-test.c b/tools/perf/tests/dlfilter-test.c
index b4649c79c309..1b7f400761bf 100644
--- a/tools/perf/tests/dlfilter-test.c
+++ b/tools/perf/tests/dlfilter-test.c
@@ -273,12 +273,16 @@ static int get_ip_addr(struct test_data *td)
return -1;
sym = map__find_symbol_by_name(map, "foo");
- if (sym)
+ if (sym) {
td->foo = symbol__start(sym);
+ symbol__put(sym);
+ }
sym = map__find_symbol_by_name(map, "bar");
- if (sym)
+ if (sym) {
td->bar = symbol__start(sym);
+ symbol__put(sym);
+ }
map__put(map);
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 95b9a629e59e..16637f1e1e23 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -114,7 +114,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
fake_samples[i].thread = thread__get(al.thread);
map__put(fake_samples[i].map);
fake_samples[i].map = map__get(al.map);
- fake_samples[i].sym = al.sym;
+ symbol__put(fake_samples[i].sym);
+ fake_samples[i].sym = symbol__get(al.sym);
}
addr_location__exit(&al);
@@ -155,6 +156,7 @@ static void put_fake_samples(void)
size_t i;
for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
+ symbol__zput(fake_samples[i].sym);
map__zput(fake_samples[i].map);
thread__zput(fake_samples[i].thread);
}
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 6c7e4cdc71a7..3bd0b0b270f5 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -93,7 +93,8 @@ static int add_hist_entries(struct evlist *evlist,
fake_samples[i].thread = thread__get(al.thread);
map__put(fake_samples[i].map);
fake_samples[i].map = map__get(al.map);
- fake_samples[i].sym = al.sym;
+ symbol__put(fake_samples[i].sym);
+ fake_samples[i].sym = symbol__get(al.sym);
}
}
addr_location__exit(&al);
@@ -109,8 +110,11 @@ static void put_fake_samples(void)
{
size_t i;
- for (i = 0; i < ARRAY_SIZE(fake_samples); i++)
- map__put(fake_samples[i].map);
+ for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
+ symbol__zput(fake_samples[i].sym);
+ map__zput(fake_samples[i].map);
+ thread__zput(fake_samples[i].thread);
+ }
}
static int test__hists_filter(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index cd32c8277627..b91a75a8fa23 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -99,7 +99,8 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine)
fake_common_samples[k].thread = thread__get(al.thread);
map__put(fake_common_samples[k].map);
fake_common_samples[k].map = map__get(al.map);
- fake_common_samples[k].sym = al.sym;
+ symbol__put(fake_common_samples[k].sym);
+ fake_common_samples[k].sym = symbol__get(al.sym);
}
for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
@@ -119,7 +120,8 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine)
fake_samples[i][k].thread = thread__get(al.thread);
map__put(fake_samples[i][k].map);
fake_samples[i][k].map = map__get(al.map);
- fake_samples[i][k].sym = al.sym;
+ symbol__put(fake_samples[i][k].sym);
+ fake_samples[i][k].sym = symbol__get(al.sym);
}
i++;
}
@@ -136,11 +138,15 @@ static void put_fake_samples(void)
{
size_t i, j;
- for (i = 0; i < ARRAY_SIZE(fake_common_samples); i++)
+ for (i = 0; i < ARRAY_SIZE(fake_common_samples); i++) {
map__put(fake_common_samples[i].map);
+ symbol__put(fake_common_samples[i].sym);
+ }
for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
- for (j = 0; j < ARRAY_SIZE(fake_samples[0]); j++)
+ for (j = 0; j < ARRAY_SIZE(fake_samples[0]); j++) {
map__put(fake_samples[i][j].map);
+ symbol__put(fake_samples[i][j].sym);
+ }
}
}
@@ -150,7 +156,7 @@ static int find_sample(struct sample *samples, size_t nr_samples,
while (nr_samples--) {
if (RC_CHK_EQUAL(samples->thread, t) &&
RC_CHK_EQUAL(samples->map, m) &&
- samples->sym == s)
+ RC_CHK_EQUAL(samples->sym, s))
return 1;
samples++;
}
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index 77fb3a187139..63b9e48ada63 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -79,7 +79,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
fake_samples[i].thread = al.thread;
map__put(fake_samples[i].map);
fake_samples[i].map = map__get(al.map);
- fake_samples[i].sym = al.sym;
+ symbol__put(fake_samples[i].sym);
+ fake_samples[i].sym = symbol__get(al.sym);
}
addr_location__exit(&al);
@@ -120,8 +121,8 @@ static void put_fake_samples(void)
size_t i;
for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
- map__put(fake_samples[i].map);
- fake_samples[i].map = NULL;
+ symbol__zput(fake_samples[i].sym);
+ map__zput(fake_samples[i].map);
}
}
diff --git a/tools/perf/tests/kallsyms-split.c b/tools/perf/tests/kallsyms-split.c
index 244daa01bd5d..0e5c029a583e 100644
--- a/tools/perf/tests/kallsyms-split.c
+++ b/tools/perf/tests/kallsyms-split.c
@@ -99,6 +99,7 @@ static int test__kallsyms_split(struct test_suite *test __maybe_unused,
{
struct machine m = { 0 };
struct map *map = NULL;
+ struct symbol *sym;
int ret = TEST_FAIL;
pr_debug("try to create fake root directory\n");
@@ -139,10 +140,12 @@ static int test__kallsyms_split(struct test_suite *test __maybe_unused,
goto out;
}
- if (machine__find_kernel_symbol_by_name(&m, "main_symbol3", &map) == NULL) {
+ sym = machine__find_kernel_symbol_by_name(&m, "main_symbol3", &map);
+ if (sym == NULL) {
pr_debug("FAIL: failed to find a symbol\n");
goto out;
}
+ symbol__put(sym);
if (!RC_CHK_EQUAL(map, machine__kernel_map(&m))) {
pr_debug("FAIL: the symbol is not in the kernel map\n");
diff --git a/tools/perf/tests/pe-file-parsing.c b/tools/perf/tests/pe-file-parsing.c
index 30c7da79e109..c9a2f418bdc5 100644
--- a/tools/perf/tests/pe-file-parsing.c
+++ b/tools/perf/tests/pe-file-parsing.c
@@ -64,6 +64,7 @@ static int run_dir(const char *d)
dso__sort_by_name(dso);
sym = dso__find_symbol_by_name(dso, "main", &idx);
TEST_ASSERT_VAL("Failed to find main", sym);
+ symbol__put(sym);
dso__delete(dso);
return TEST_OK;
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 98c2a9437ba7..53f7b44af843 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -208,7 +208,7 @@ static int test__vmlinux_matches_kallsyms_sym_cb(struct symbol *sym, void *data)
mem_end = map__unmap_ip(args->vmlinux_map, symbol__end(sym));
first_pair = machine__find_kernel_symbol(&args->kallsyms, mem_start, NULL);
- pair = first_pair;
+ pair = symbol__get(first_pair);
if (pair && UM(symbol__start(pair)) == mem_start) {
next_pair:
@@ -237,8 +237,11 @@ static int test__vmlinux_matches_kallsyms_sym_cb(struct symbol *sym, void *data)
* possible to get proper function end from
* kallsyms.
*/
+ symbol__put(pair);
+ symbol__put(first_pair);
return 0;
} else {
+ symbol__put(pair);
pair = machine__find_kernel_symbol_by_name(&args->kallsyms,
symbol__name(sym),
NULL);
@@ -249,15 +252,20 @@ static int test__vmlinux_matches_kallsyms_sym_cb(struct symbol *sym, void *data)
pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
mem_start, symbol__name(sym),
symbol__name(pair));
+ symbol__put(pair);
} else {
pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
mem_start, symbol__name(sym),
symbol__name(first_pair));
}
+ symbol__put(first_pair);
return 0;
}
- } else if (mem_start == map__end(args->kallsyms.vmlinux_map)) {
+ }
+ symbol__put(pair);
+ symbol__put(first_pair);
+ if (mem_start == map__end(args->kallsyms.vmlinux_map)) {
/*
* Ignore aliases to _etext, i.e. to the end of the kernel text area,
* such as __indirect_thunk_end.
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 206657039223..72b071f2604f 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2522,11 +2522,11 @@ static struct symbol *symbol__new_unresolved(u64 addr, struct map *map)
if (sym) {
src = symbol__hists(sym, 1);
if (!src) {
- symbol__delete(sym);
+ symbol__put(sym);
return NULL;
}
- dso__insert_symbol(map__dso(map), sym);
+ dso__insert_symbol(map__dso(map), symbol__get(sym));
}
return sym;
@@ -2812,7 +2812,7 @@ add_script_opt_2(struct popup_action *act, char **optstr,
}
act->ms.thread = thread__get(thread);
- act->ms.sym = sym;
+ act->ms.sym = symbol__get(sym);
act->fn = do_run_script;
return 1;
}
@@ -3201,6 +3201,7 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h
memset(&hotkey_act, 0, sizeof(hotkey_act));
map_symbol__copy(&hotkey_act.ms, &source_ms);
+ symbol__zput(source_ms.sym);
do_annotate(browser, &hotkey_act);
map_symbol__exit(&hotkey_act.ms);
} else {
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index bb35d4965a3a..2310fbf1ac6d 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -65,12 +65,13 @@ static int map_browser__search(struct map_browser *browser)
* cursor at that entry.
*/
for (u32 idx = 0; idx < browser->b.nr_entries; ++idx) {
- if (entries[idx] == sym) {
+ if (RC_CHK_EQUAL(entries[idx], sym)) {
browser->b.top = &entries[idx];
browser->b.index = browser->b.top_idx = idx;
break;
}
}
+ symbol__put(sym);
} else
ui_helpline__fpush("%s not found!", target);
@@ -136,7 +137,7 @@ int map__browse(struct map *map)
for (unsigned int idx = 0; idx < nr_entries; idx++) {
struct symbol *pos = symbols->symbols[idx];
- entries[idx] = pos;
+ entries[idx] = symbol__get(pos);
if (maxaddr < symbol__end(pos))
maxaddr = symbol__end(pos);
}
@@ -151,6 +152,8 @@ int map__browse(struct map *map)
mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
ret = map_browser__run(&mb);
+ for (unsigned int idx = 0; idx < nr_entries; idx++)
+ symbol__put(entries[idx]);
free(entries);
return ret;
}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index f80cc73909ed..aedc5eb8b1a4 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -908,7 +908,8 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
free(line);
out:
- zfree(&rem_sq_bracket);
+ symbol__zput(rem_sq_bracket);
+ rem_hits.ms.sym = NULL;
return ret;
}
diff --git a/tools/perf/util/addr_location.c b/tools/perf/util/addr_location.c
index 57e8217a00f9..0f21a01a3843 100644
--- a/tools/perf/util/addr_location.c
+++ b/tools/perf/util/addr_location.c
@@ -2,6 +2,7 @@
#include "addr_location.h"
#include "map.h"
#include "maps.h"
+#include "symbol.h"
#include "thread.h"
void addr_location__init(struct addr_location *al)
@@ -29,13 +30,16 @@ void addr_location__exit(struct addr_location *al)
{
map__zput(al->map);
thread__zput(al->thread);
+ symbol__zput(al->sym);
}
void addr_location__copy(struct addr_location *dst, struct addr_location *src)
{
thread__put(dst->thread);
map__put(dst->map);
+ symbol__put(dst->sym);
*dst = *src;
dst->thread = thread__get(src->thread);
dst->map = map__get(src->map);
+ dst->sym = symbol__get(src->sym);
}
diff --git a/tools/perf/util/annotate-arch/annotate-alpha.c b/tools/perf/util/annotate-arch/annotate-alpha.c
index ccb13e2338a2..e95f7628a8fe 100644
--- a/tools/perf/util/annotate-arch/annotate-alpha.c
+++ b/tools/perf/util/annotate-arch/annotate-alpha.c
@@ -89,7 +89,7 @@ static int alpha_call__parse(const struct arch *arch, struct ins_operands *ops,
if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
map__rip_2objdump(target.ms.map,
map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
- ops->target.sym = target.ms.sym;
+ ops->target.sym = symbol__get(target.ms.sym);
addr_map_symbol__exit(&target);
return 0;
diff --git a/tools/perf/util/annotate-arch/annotate-loongarch.c b/tools/perf/util/annotate-arch/annotate-loongarch.c
index d275730080b7..7fa1739966df 100644
--- a/tools/perf/util/annotate-arch/annotate-loongarch.c
+++ b/tools/perf/util/annotate-arch/annotate-loongarch.c
@@ -57,7 +57,7 @@ static int loongarch_call__parse(const struct arch *arch, struct ins_operands *o
if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
- ops->target.sym = target.ms.sym;
+ ops->target.sym = symbol__get(target.ms.sym);
addr_map_symbol__exit(&target);
return 0;
@@ -101,7 +101,7 @@ static int loongarch_jump__parse(const struct arch *arch, struct ins_operands *o
if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
- ops->target.sym = target.ms.sym;
+ ops->target.sym = symbol__get(target.ms.sym);
if (!ops->target.outside) {
ops->target.offset = target.addr - start;
diff --git a/tools/perf/util/annotate-arch/annotate-s390.c b/tools/perf/util/annotate-arch/annotate-s390.c
index af9cabd0a586..7c8050e04964 100644
--- a/tools/perf/util/annotate-arch/annotate-s390.c
+++ b/tools/perf/util/annotate-arch/annotate-s390.c
@@ -52,7 +52,7 @@ static int s390_call__parse(const struct arch *arch, struct ins_operands *ops,
if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
- ops->target.sym = target.ms.sym;
+ ops->target.sym = symbol__get(target.ms.sym);
addr_map_symbol__exit(&target);
return 0;
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 9bb7e0ee1b8e..61a5b13c4777 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -194,15 +194,22 @@ static bool sym_ptr_equal(long key1, long key2, void *ctx __maybe_unused)
struct annotation *symbol__annotation(struct symbol *sym)
{
struct annotation *notes = NULL;
- long val = 0;
+ long key, val = 0;
if (!sym)
return NULL;
+ /*
+ * Key on the underlying RC_STRUCT(symbol) pointer so all
+ * REFCNT_CHECKING wrapper pointers for the same symbol map to the
+ * same annotation entry.
+ */
+ key = (long)RC_CHK_ACCESS(sym);
+
/* Fast path: look up existing annotation under read lock if flagged. */
if (symbol__annotated(sym)) {
down_read(annotations_lock());
- if (annotations && hashmap__find(annotations, (long)sym, &val))
+ if (annotations && hashmap__find(annotations, key, &val))
notes = (struct annotation *)val;
up_read(annotations_lock());
if (notes)
@@ -217,7 +224,7 @@ struct annotation *symbol__annotation(struct symbol *sym)
up_write(annotations_lock());
return &empty_annotation;
}
- } else if (hashmap__find(annotations, (long)sym, &val)) {
+ } else if (hashmap__find(annotations, key, &val)) {
notes = (struct annotation *)val;
up_write(annotations_lock());
return notes;
@@ -229,7 +236,7 @@ struct annotation *symbol__annotation(struct symbol *sym)
return &empty_annotation;
}
annotation__init(notes);
- if (hashmap__add(annotations, (long)sym, notes) < 0) {
+ if (hashmap__add(annotations, key, notes) < 0) {
free(notes);
if (hashmap__size(annotations) == 0) {
hashmap__free(annotations);
@@ -246,14 +253,15 @@ struct annotation *symbol__annotation(struct symbol *sym)
void symbol__annotation_delete(struct symbol *sym)
{
struct annotation *notes = NULL;
- long val = 0;
+ long key, val = 0;
/* Unannotated symbols avoid taking annotations_lock on teardown. */
if (!sym || !symbol__annotated(sym))
return;
+ key = (long)RC_CHK_ACCESS(sym);
down_write(annotations_lock());
- if (annotations && hashmap__delete(annotations, (long)sym, NULL, &val)) {
+ if (annotations && hashmap__delete(annotations, key, NULL, &val)) {
notes = (struct annotation *)val;
if (hashmap__size(annotations) == 0) {
hashmap__free(annotations);
@@ -567,7 +575,7 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
* it starts on the function start.
*/
if (start &&
- (start->ms.sym == ams->ms.sym ||
+ (RC_CHK_EQUAL(start->ms.sym, ams->ms.sym) ||
(ams->ms.sym &&
start->addr == symbol__start(ams->ms.sym) + map__start(ams->ms.map))))
saddr = start->al_addr;
diff --git a/tools/perf/util/block-info.c b/tools/perf/util/block-info.c
index 5dec6c9dc1a7..6bf13482da80 100644
--- a/tools/perf/util/block-info.c
+++ b/tools/perf/util/block-info.c
@@ -64,8 +64,10 @@ static struct block_info *block_info__new(unsigned int br_cntr_nr)
void block_info__delete(struct block_info *bi)
{
- if (bi)
+ if (bi) {
+ symbol__zput(bi->sym);
free(bi->br_cntr);
+ }
free(bi);
}
@@ -105,7 +107,7 @@ static void init_block_info(struct block_info *bi, struct symbol *sym,
u64 total_cycles, unsigned int br_cntr_nr,
u64 *br_cntr, struct evsel *evsel)
{
- bi->sym = sym;
+ bi->sym = symbol__get(sym);
bi->start = ch->start;
bi->end = offset;
bi->cycles = ch->cycles;
diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
index 9832c45857d1..bf9b4dc3c3bb 100644
--- a/tools/perf/util/bpf_lock_contention.c
+++ b/tools/perf/util/bpf_lock_contention.c
@@ -145,6 +145,7 @@ static void init_numa_data(struct lock_contention *con)
if (sym) {
skel->rodata->contig_page_data_addr = map__unmap_ip(kmap,
symbol__start(sym));
+ symbol__put(sym);
map__put(kmap);
return;
}
@@ -161,6 +162,7 @@ static void init_numa_data(struct lock_contention *con)
return;
skel->rodata->node_data_addr = map__unmap_ip(kmap, symbol__start(sym));
+ symbol__put(sym);
map__put(kmap);
/* get the number of online nodes using the last node number + 1 */
@@ -264,12 +266,16 @@ int lock_contention_prepare(struct lock_contention *con)
(con->filters->nr_addrs + 1) * sizeof(*addrs));
if (addrs == NULL) {
pr_warning("memory allocation failure\n");
+ symbol__put(sym);
+ map__put(kmap);
continue;
}
addrs[con->filters->nr_addrs++] = map__unmap_ip(kmap,
symbol__start(sym));
con->filters->addrs = addrs;
+ symbol__put(sym);
+ map__put(kmap);
}
naddrs = con->filters->nr_addrs ?: has_mmap_lock;
skel->rodata->has_addr = 1;
@@ -292,6 +298,8 @@ int lock_contention_prepare(struct lock_contention *con)
con->delays[i].addr = map__unmap_ip(kmap,
symbol__start(sym));
+ symbol__put(sym);
+ map__put(kmap);
}
skel->rodata->lock_delay = 1;
bpf_map__set_max_entries(skel->maps.lock_delays, con->nr_delays);
@@ -609,9 +617,12 @@ static const char *lock_contention_get_name(struct lock_contention *con,
return "siglock";
/* global locks with symbols */
- sym = machine__find_kernel_symbol(machine, key->lock_addr_or_cgroup, &kmap);
- if (sym)
- return symbol__name(sym);
+ sym = machine__find_kernel_symbol(machine, key->lock_addr_or_cgroup, NULL);
+ if (sym) {
+ snprintf(name_buf, sizeof(name_buf), "%s", symbol__name(sym));
+ symbol__put(sym);
+ return name_buf;
+ }
/* try semi-global locks collected separately */
if (!bpf_map_lookup_elem(lock_fd, &key->lock_addr_or_cgroup, &flags)) {
@@ -658,13 +669,15 @@ static const char *lock_contention_get_name(struct lock_contention *con,
offset = map__map_ip(kmap, addr) - symbol__start(sym);
if (offset == 0)
- return symbol__name(sym);
-
- snprintf(name_buf, sizeof(name_buf), "%s+%#lx",
- symbol__name(sym), offset);
+ snprintf(name_buf, sizeof(name_buf), "%s", symbol__name(sym));
+ else
+ snprintf(name_buf, sizeof(name_buf), "%s+%#lx",
+ symbol__name(sym), offset);
+ symbol__put(sym);
} else {
snprintf(name_buf, sizeof(name_buf), "%#lx", (unsigned long)addr);
}
+ map__put(kmap);
return name_buf;
}
diff --git a/tools/perf/util/c2c-function.c b/tools/perf/util/c2c-function.c
index 0c50d816653f..5bd7e0364263 100644
--- a/tools/perf/util/c2c-function.c
+++ b/tools/perf/util/c2c-function.c
@@ -976,13 +976,13 @@ c2c_function_hists__level1_entry(struct symbol *sym,
/* mem_info__put() will map_symbol__exit() these, so take refs. */
mem_info__iaddr(mi)->ms.thread = thread__get(detail_he->ms.thread);
mem_info__iaddr(mi)->ms.map = map__get(detail_he->ms.map);
- mem_info__iaddr(mi)->ms.sym = sym;
+ mem_info__iaddr(mi)->ms.sym = symbol__get(sym);
mem_info__daddr(mi)->addr = 0;
addr_location__init(&al);
al.thread = thread__get(synthetic_thread);
al.map = map__get(detail_he->ms.map);
- al.sym = sym;
+ al.sym = symbol__get(sym);
al.addr = sym_start;
al.level = detail_he->level;
al.cpumode = detail_he->cpumode;
@@ -1064,9 +1064,12 @@ c2c_function_hists__level2_entry(struct c2c_hist_entry *level1_c2c,
return NULL;
/* Key this level by the looked-up symbol, not detail_he's. */
- level2_c2c->he.ms.sym = sym;
- if (level2_c2c->he.mem_info)
- mem_info__iaddr(level2_c2c->he.mem_info)->ms.sym = sym;
+ symbol__put(level2_c2c->he.ms.sym);
+ level2_c2c->he.ms.sym = symbol__get(sym);
+ if (level2_c2c->he.mem_info) {
+ symbol__put(mem_info__iaddr(level2_c2c->he.mem_info)->ms.sym);
+ mem_info__iaddr(level2_c2c->he.mem_info)->ms.sym = symbol__get(sym);
+ }
c2c_child_entry__insert(level1_he, &level2_c2c->he, p, parent, leftmost);
diff --git a/tools/perf/util/call-path.c b/tools/perf/util/call-path.c
index 5c60b8be1cf6..5927068fd9b6 100644
--- a/tools/perf/util/call-path.c
+++ b/tools/perf/util/call-path.c
@@ -10,12 +10,13 @@
#include <stdlib.h>
#include "call-path.h"
+#include "symbol.h"
static void call_path__init(struct call_path *cp, struct call_path *parent,
struct symbol *sym, u64 ip, bool in_kernel)
{
cp->parent = parent;
- cp->sym = sym;
+ cp->sym = symbol__get(sym);
cp->ip = sym ? 0 : ip;
cp->db_id = 0;
cp->in_kernel = in_kernel;
@@ -38,8 +39,15 @@ struct call_path_root *call_path_root__new(void)
void call_path_root__free(struct call_path_root *cpr)
{
struct call_path_block *pos, *n;
+ size_t i = 0;
+ if (!cpr)
+ return;
+
+ symbol__zput(cpr->call_path.sym);
list_for_each_entry_safe(pos, n, &cpr->blocks, node) {
+ for (size_t j = 0; j < CALL_PATH_BLOCK_SIZE && i < cpr->next; j++, i++)
+ symbol__zput(pos->cp[j].sym);
list_del_init(&pos->node);
free(pos);
}
@@ -94,10 +102,11 @@ struct call_path *call_path__findnew(struct call_path_root *cpr,
node_parent = *p;
cp = rb_entry(node_parent, struct call_path, rb_node);
- if (cp->sym == sym && cp->ip == ip)
+ if (RC_CHK_EQUAL(cp->sym, sym) && cp->ip == ip)
return cp;
- if (sym < cp->sym || (sym == cp->sym && ip < cp->ip))
+ if ((sym ? RC_CHK_ACCESS(sym) : NULL) < (cp->sym ? RC_CHK_ACCESS(cp->sym) : NULL) ||
+ (RC_CHK_EQUAL(sym, cp->sym) && ip < cp->ip))
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 993b7c744a89..7f4543ea2ab5 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1094,6 +1094,7 @@ merge_chain_branch(struct callchain_cursor *cursor,
struct map_symbol ms = {
.thread = thread__get(list->ms.thread),
.map = map__get(list->ms.map),
+ .sym = symbol__get(list->ms.sym),
};
callchain_cursor_append(cursor, list->ip, &ms, false, NULL, 0, 0, 0, list->srcline);
list_del_init(&list->list);
@@ -1204,7 +1205,8 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
map__put(al->map);
al->map = map__get(node->ms.map);
- al->sym = node->ms.sym;
+ symbol__put(al->sym);
+ al->sym = symbol__get(node->ms.sym);
al->srcline = node->srcline;
al->addr = node->ip;
diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c
index 422a48385b78..69667f41a7fe 100644
--- a/tools/perf/util/capstone.c
+++ b/tools/perf/util/capstone.c
@@ -373,6 +373,7 @@ static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len,
scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">",
orig_addr, symbol__name(sym), sym_offset);
}
+ symbol__put(sym);
map__put(found_map);
break;
}
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index 897cda3fadd2..1029f23be428 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -22,14 +22,24 @@
#include "db-export.h"
#include "hashmap.h"
+/*
+ * Hash and compare the underlying RC_STRUCT(symbol) pointer so all
+ * REFCNT_CHECKING wrapper pointers for the same symbol resolve to the same
+ * exported database ID.
+ */
static size_t sym_ptr_hash(long key, void *ctx __maybe_unused)
{
- return hash_bits((size_t)key, 16);
+ const struct symbol *sym = (const struct symbol *)key;
+
+ return hash_bits((size_t)RC_CHK_ACCESS(sym), 16);
}
static bool sym_ptr_equal(long key1, long key2, void *ctx __maybe_unused)
{
- return key1 == key2;
+ const struct symbol *sym1 = (const struct symbol *)key1;
+ const struct symbol *sym2 = (const struct symbol *)key2;
+
+ return RC_CHK_EQUAL(sym1, sym2);
}
int db_export__init(struct db_export *dbe)
@@ -40,8 +50,15 @@ int db_export__init(struct db_export *dbe)
void db_export__exit(struct db_export *dbe)
{
- hashmap__free(dbe->sym_db_ids);
- dbe->sym_db_ids = NULL;
+ if (dbe->sym_db_ids) {
+ struct hashmap_entry *cur;
+ size_t bkt;
+
+ hashmap__for_each_entry(dbe->sym_db_ids, cur, bkt)
+ symbol__put((struct symbol *)cur->pkey);
+ hashmap__free(dbe->sym_db_ids);
+ dbe->sym_db_ids = NULL;
+ }
call_return_processor__free(dbe->crp);
dbe->crp = NULL;
}
@@ -187,6 +204,7 @@ int db_export__symbol(struct db_export *dbe, struct symbol *sym,
struct dso *dso)
{
long db_id;
+ struct symbol *sym_key;
if (db_export__symbol_db_id(dbe, sym))
return 0;
@@ -202,8 +220,11 @@ int db_export__symbol(struct db_export *dbe, struct symbol *sym,
}
db_id = ++dbe->symbol_last_db_id;
- if (hashmap__set(dbe->sym_db_ids, (long)sym, db_id, NULL, NULL))
+ sym_key = symbol__get(sym);
+ if (hashmap__set(dbe->sym_db_ids, (long)sym_key, db_id, NULL, NULL)) {
+ symbol__put(sym_key);
return -ENOMEM;
+ }
if (dbe->export_symbol)
return dbe->export_symbol(dbe, sym, dso);
@@ -227,7 +248,7 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
if (!al->sym) {
al->sym = symbol__new(al->addr, 0, 0, 0, "unknown");
if (al->sym)
- dso__insert_symbol(dso, al->sym);
+ dso__insert_symbol(dso, symbol__get(al->sym));
}
if (al->sym) {
@@ -287,7 +308,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
* db_ids_from_al() to perform the export.
*/
addr_location__init(&al);
- al.sym = node->ms.sym;
+ al.sym = symbol__get(node->ms.sym);
al.map = map__get(node->ms.map);
al.addr = node->ip;
al.thread = thread__get(thread);
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 78b8811dcaa4..cc9865ac6623 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -228,6 +228,7 @@ static void ins_ops__delete(struct ins_operands *ops)
zfree(&ops->source.name);
zfree(&ops->target.raw);
zfree(&ops->target.name);
+ symbol__zput(ops->target.sym);
}
int ins__raw_scnprintf(const struct ins *ins, char *bf, size_t size,
@@ -290,7 +291,7 @@ static int call__parse(const struct arch *arch, struct ins_operands *ops, struct
if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
- ops->target.sym = target.ms.sym;
+ ops->target.sym = symbol__get(target.ms.sym);
addr_map_symbol__exit(&target);
return 0;
@@ -425,7 +426,7 @@ static int jump__parse(const struct arch *arch, struct ins_operands *ops, struct
*/
if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
- ops->target.sym = target.ms.sym;
+ ops->target.sym = symbol__get(target.ms.sym);
if (!ops->target.outside) {
ops->target.offset = target.addr - start;
@@ -471,12 +472,14 @@ int jump__scnprintf(const struct ins *ins, char *bf, size_t size,
ops->target.offset);
}
-void jump__delete(struct ins_operands *ops __maybe_unused)
+void jump__delete(struct ins_operands *ops)
{
/*
* The ops->jump.raw_comment and ops->jump.raw_func_start belong to the
* raw string, don't free them.
*/
+ if (ops)
+ symbol__zput(ops->target.sym);
}
const struct ins_ops jump_ops = {
@@ -570,6 +573,7 @@ static void lock__delete(struct ins_operands *ops)
zfree(&ops->locked.ins.name);
zfree(&ops->target.raw);
zfree(&ops->target.name);
+ symbol__zput(ops->target.sym);
}
const struct ins_ops lock_ops = {
@@ -1090,7 +1094,7 @@ static int symbol__parse_objdump_line(struct symbol *sym,
if (!maps__find_ams(thread__maps(args->ms->thread), &target) &&
symbol__start(target.ms.sym) == target.al_addr)
- dl->ops.target.sym = target.ms.sym;
+ dl->ops.target.sym = symbol__get(target.ms.sym);
addr_map_symbol__exit(&target);
}
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 939307796a88..a71267af4f3c 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -770,7 +770,7 @@ struct map *thread__find_map_fb(struct thread *thread, u8 cpumode, u64 addr,
struct symbol *thread__find_symbol(struct thread *thread, u8 cpumode,
u64 addr, struct addr_location *al)
{
- al->sym = NULL;
+ symbol__zput(al->sym);
if (thread__find_map(thread, cpumode, addr, al))
al->sym = map__find_symbol(al->map, al->addr);
return al->sym;
@@ -779,7 +779,7 @@ struct symbol *thread__find_symbol(struct thread *thread, u8 cpumode,
struct symbol *thread__find_symbol_fb(struct thread *thread, u8 cpumode,
u64 addr, struct addr_location *al)
{
- al->sym = NULL;
+ symbol__zput(al->sym);
if (thread__find_map_fb(thread, cpumode, addr, al))
al->sym = map__find_symbol(al->map, al->addr);
return al->sym;
@@ -829,7 +829,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
thread__put(thread);
thread = NULL;
- al->sym = NULL;
+ symbol__zput(al->sym);
al->cpu = sample->cpu;
al->socket = -1;
al->srcline = NULL;
@@ -937,7 +937,7 @@ void thread__resolve(struct thread *thread, struct addr_location *al,
thread__find_map_fb(thread, sample->cpumode, sample->addr, al);
al->cpu = sample->cpu;
- al->sym = NULL;
+ symbol__zput(al->sym);
if (al->map)
al->sym = map__find_symbol(al->map, al->addr);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index dd388169c25b..7ae4e7664ba7 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -542,6 +542,7 @@ static int hist_entry__init(struct hist_entry *he,
he->ms.thread = thread__get(he->ms.thread);
he->ms.map = map__get(he->ms.map);
+ he->ms.sym = symbol__get(he->ms.sym);
if (he->branch_info) {
/*
@@ -558,8 +559,10 @@ static int hist_entry__init(struct hist_entry *he,
he->branch_info->from.ms.thread = thread__get(he->branch_info->from.ms.thread);
he->branch_info->from.ms.map = map__get(he->branch_info->from.ms.map);
+ he->branch_info->from.ms.sym = symbol__get(he->branch_info->from.ms.sym);
he->branch_info->to.ms.thread = thread__get(he->branch_info->to.ms.thread);
he->branch_info->to.ms.map = map__get(he->branch_info->to.ms.map);
+ he->branch_info->to.ms.sym = symbol__get(he->branch_info->to.ms.sym);
}
if (he->mem_info) {
@@ -592,6 +595,7 @@ static int hist_entry__init(struct hist_entry *he,
INIT_LIST_HEAD(&he->pairs.node);
he->thread = thread__get(he->thread);
+ he->parent = symbol__get(he->parent);
he->hroot_in = RB_ROOT_CACHED;
he->hroot_out = RB_ROOT_CACHED;
@@ -727,6 +731,8 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
if (hists__has(hists, sym) && he->ms.map != entry->ms.map) {
if (he->ms.sym) {
u64 addr = symbol__start(he->ms.sym);
+
+ symbol__put(he->ms.sym);
he->ms.sym = map__find_symbol(entry->ms.map, addr);
}
@@ -1028,7 +1034,8 @@ iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
al->thread = thread__get(bi[i].to.ms.thread);
map__put(al->map);
al->map = map__get(bi[i].to.ms.map);
- al->sym = bi[i].to.ms.sym;
+ symbol__put(al->sym);
+ al->sym = symbol__get(bi[i].to.ms.sym);
al->addr = bi[i].to.addr;
return 1;
}
@@ -1342,9 +1349,11 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
if (al)
alm = map__get(al->map);
+ iter->parent = NULL;
err = sample__resolve_callchain(iter->sample, get_tls_callchain_cursor(), &iter->parent,
al, max_stack_depth);
if (err) {
+ symbol__zput(iter->parent);
map__put(alm);
return err;
}
@@ -1380,6 +1389,7 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
if (!err)
err = err2;
+ symbol__zput(iter->parent);
map__put(alm);
return err;
@@ -1466,6 +1476,7 @@ void hist_entry__delete(struct hist_entry *he)
}
thread__zput(he->thread);
+ symbol__zput(he->parent);
map_symbol__exit(&he->ms);
if (he->branch_info) {
diff --git a/tools/perf/util/libdw.c b/tools/perf/util/libdw.c
index c4504cceb313..ca66c9afdcd6 100644
--- a/tools/perf/util/libdw.c
+++ b/tools/perf/util/libdw.c
@@ -98,7 +98,7 @@ static int libdw_a2l_cb(Dwarf_Die *die, void *_args)
* while DWARF keeps the pre-clone linkage name, which
* left the outer frame spuriously tagged "(inlined)".
*/
- inline_sym = args->sym;
+ inline_sym = symbol__get(args->sym);
} else {
/*
* Prefer DW_AT_linkage_name so C++ inline frames keep
@@ -156,8 +156,7 @@ static int libdw_a2l_cb(Dwarf_Die *die, void *_args)
return 0;
abort_delete_sym:
- if (symbol__inlined(inline_sym))
- symbol__delete(inline_sym);
+ symbol__put(inline_sym);
abort_enomem:
args->err = -ENOMEM;
return DWARF_CB_ABORT;
diff --git a/tools/perf/util/lock-contention.c b/tools/perf/util/lock-contention.c
index 8ee1b19a8292..367666028eb2 100644
--- a/tools/perf/util/lock-contention.c
+++ b/tools/perf/util/lock-contention.c
@@ -101,7 +101,6 @@ struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags)
bool match_callstack_filter(struct machine *machine, u64 *callstack, int max_stack_depth)
{
- struct map *kmap;
struct symbol *sym;
u64 ip;
uint16_t e_machine = perf_env__e_machine(machine->env, /*e_flags=*/NULL);
@@ -130,14 +129,17 @@ bool match_callstack_filter(struct machine *machine, u64 *callstack, int max_sta
break;
ip = callstack[i];
- sym = machine__find_kernel_symbol(machine, ip, &kmap);
+ sym = machine__find_kernel_symbol(machine, ip, NULL);
if (sym == NULL)
continue;
list_for_each_entry(filter, &callstack_filters, list) {
- if (strstr(symbol__name(sym), filter->name))
+ if (strstr(symbol__name(sym), filter->name)) {
+ symbol__put(sym);
return true;
+ }
}
+ symbol__put(sym);
}
return false;
}
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index cb30d858f62d..f1155c608a95 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -824,8 +824,10 @@ static int machine__process_ksymbol_unregister(struct machine *machine,
struct dso *dso = map__dso(map);
sym = dso__find_symbol(dso, map__map_ip(map, map__start(map)));
- if (sym)
+ if (sym) {
dso__delete_symbol(dso, sym);
+ symbol__put(sym);
+ }
}
map__put(map);
return 0;
@@ -2085,7 +2087,7 @@ static void ip__resolve_ams(struct thread *thread,
ams->al_addr = al.addr;
ams->al_level = al.level;
ams->ms.thread = thread__get(al.thread);
- ams->ms.sym = al.sym;
+ ams->ms.sym = symbol__get(al.sym);
ams->ms.map = map__get(al.map);
ams->phys_addr = 0;
ams->data_page_size = 0;
@@ -2106,7 +2108,7 @@ static void ip__resolve_data(struct thread *thread,
ams->al_addr = al.addr;
ams->al_level = al.level;
ams->ms.thread = thread__get(al.thread);
- ams->ms.sym = al.sym;
+ ams->ms.sym = symbol__get(al.sym);
ams->ms.map = map__get(al.map);
ams->phys_addr = phys_addr;
ams->data_page_size = daddr_page_size;
@@ -2192,7 +2194,8 @@ static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms
.map = map__get(map),
};
list_for_each_entry(ilist, &inline_node->val, list) {
- ilist_ms.sym = ilist->symbol;
+ symbol__put(ilist_ms.sym);
+ ilist_ms.sym = symbol__get(ilist->symbol);
if (first) {
ret = callchain_cursor_append(cursor, ip, &ilist_ms,
branch, flags, nr_loop_iter,
@@ -2204,7 +2207,7 @@ static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms
first = false;
if (ret != 0)
- return ret;
+ break;
}
map_symbol__exit(&ilist_ms);
@@ -2270,7 +2273,7 @@ static int add_callchain_ip(struct thread *thread,
if (al.sym != NULL) {
if (perf_hpp_list.parent && !*parent &&
symbol__match_regex(al.sym, &parent_regex))
- *parent = al.sym;
+ *parent = symbol__get(al.sym);
else if (have_ignore_callees && root_al &&
symbol__match_regex(al.sym, &ignore_callees_regex)) {
/* Treat this symbol as the root,
@@ -2290,7 +2293,7 @@ static int add_callchain_ip(struct thread *thread,
ms.thread = thread__get(al.thread);
ms.map = map__get(al.map);
- ms.sym = al.sym;
+ ms.sym = symbol__get(al.sym);
if (append_inlines(cursor, &ms, ip, branch, flags, nr_loop_iter,
iter_cycles, branch_from) == 0)
@@ -2451,8 +2454,7 @@ static void save_lbr_cursor_node(struct thread *thread,
map_symbol__exit(&lbr_stitch->prev_lbr_cursor[idx].ms);
memcpy(&lbr_stitch->prev_lbr_cursor[idx], cursor->curr,
sizeof(struct callchain_cursor_node));
- lbr_stitch->prev_lbr_cursor[idx].ms.thread = thread__get(cursor->curr->ms.thread);
- lbr_stitch->prev_lbr_cursor[idx].ms.map = map__get(cursor->curr->ms.map);
+ map_symbol__copy(&lbr_stitch->prev_lbr_cursor[idx].ms, &cursor->curr->ms);
lbr_stitch->prev_lbr_cursor[idx].valid = true;
cursor->pos++;
@@ -2676,9 +2678,7 @@ static bool has_stitched_lbr(struct thread *thread,
memcpy(&stitch_node->cursor, &lbr_stitch->prev_lbr_cursor[i],
sizeof(struct callchain_cursor_node));
- stitch_node->cursor.ms.thread =
- thread__get(lbr_stitch->prev_lbr_cursor[i].ms.thread);
- stitch_node->cursor.ms.map = map__get(lbr_stitch->prev_lbr_cursor[i].ms.map);
+ map_symbol__copy(&stitch_node->cursor.ms, &lbr_stitch->prev_lbr_cursor[i].ms);
if (callee)
list_add(&stitch_node->node, &lbr_stitch->lists);
@@ -3282,15 +3282,21 @@ struct dso *machine__findnew_dso(struct machine *machine, const char *filename)
char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
{
struct machine *machine = vmachine;
- struct map *map;
+ struct map *map = NULL;
struct symbol *sym = machine__find_kernel_symbol(machine, *addrp, &map);
+ char *name;
- if (sym == NULL)
+ if (sym == NULL) {
+ map__put(map);
return NULL;
+ }
*modp = __map__is_kmodule(map) ? (char *)dso__short_name(map__dso(map)) : NULL;
*addrp = map__unmap_ip(map, symbol__start(sym));
- return (char *)symbol__name(sym);
+ name = (char *)symbol__name(sym);
+ symbol__put(sym);
+ map__put(map);
+ return name;
}
struct machine__for_each_dso_cb_args {
@@ -3338,19 +3344,27 @@ bool machine__is_lock_function(struct machine *machine, u64 addr)
machine->sched.text_start = map__unmap_ip(kmap,
symbol__start(sym));
+ symbol__put(sym);
+ map__put(kmap);
/* should not fail from here */
sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_end", &kmap);
machine->sched.text_end = map__unmap_ip(kmap,
symbol__start(sym));
+ symbol__put(sym);
+ map__put(kmap);
sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_start", &kmap);
machine->lock.text_start = map__unmap_ip(kmap,
symbol__start(sym));
+ symbol__put(sym);
+ map__put(kmap);
sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_end", &kmap);
machine->lock.text_end = map__unmap_ip(kmap,
symbol__start(sym));
+ symbol__put(sym);
+ map__put(kmap);
sym = machine__find_kernel_symbol_by_name(machine, "__traceiter_contention_begin", &kmap);
if (sym) {
@@ -3358,6 +3372,8 @@ bool machine__is_lock_function(struct machine *machine, u64 addr)
symbol__start(sym));
machine->traceiter.text_end = map__unmap_ip(kmap,
symbol__end(sym));
+ symbol__put(sym);
+ map__put(kmap);
}
sym = machine__find_kernel_symbol_by_name(machine, "trace_contention_begin", &kmap);
if (sym) {
@@ -3365,6 +3381,8 @@ bool machine__is_lock_function(struct machine *machine, u64 addr)
symbol__start(sym));
machine->trace.text_end = map__unmap_ip(kmap,
symbol__end(sym));
+ symbol__put(sym);
+ map__put(kmap);
}
}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 3d8f72e70d49..745eefa79c7f 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -160,13 +160,15 @@ struct thread;
* @sym_name: the symbol name
* @pos: the 'struct symbol *' to use as a loop cursor
* @idx: the cursor index in the symbol names array
+ * Note: caller must call symbol__put(pos) if breaking out of the loop early.
*/
#define __map__for_each_symbol_by_name(map, sym_name, pos, idx) \
for (pos = map__find_symbol_by_name_idx(map, sym_name, &idx); \
- pos && \
- !symbol__match_symbol_name(symbol__name(pos), sym_name, \
- SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); \
- pos = dso__next_symbol_by_name(map__dso(map), &idx))
+ pos && \
+ (!symbol__match_symbol_name(symbol__name(pos), sym_name, \
+ SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) || \
+ (symbol__zput(pos), false)); \
+ symbol__put(pos), pos = dso__next_symbol_by_name(map__dso(map), &idx))
#define map__for_each_symbol_by_name(map, sym_name, pos, idx) \
__map__for_each_symbol_by_name(map, sym_name, (pos), idx)
diff --git a/tools/perf/util/map_symbol.c b/tools/perf/util/map_symbol.c
index 11bc0a7f704c..d1ee4e05564e 100644
--- a/tools/perf/util/map_symbol.c
+++ b/tools/perf/util/map_symbol.c
@@ -2,12 +2,14 @@
#include "map_symbol.h"
#include "maps.h"
#include "map.h"
+#include "symbol.h"
#include "thread.h"
void map_symbol__exit(struct map_symbol *ms)
{
thread__zput(ms->thread);
map__zput(ms->map);
+ symbol__zput(ms->sym);
}
void addr_map_symbol__exit(struct addr_map_symbol *ams)
@@ -19,7 +21,7 @@ void map_symbol__copy(struct map_symbol *dst, struct map_symbol *src)
{
dst->thread = thread__get(src->thread);
dst->map = map__get(src->map);
- dst->sym = src->sym;
+ dst->sym = symbol__get(src->sym);
}
void addr_map_symbol__copy(struct addr_map_symbol *dst, struct addr_map_symbol *src)
diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c
index f808df2fe77b..a6cbe65cc5ca 100644
--- a/tools/perf/util/maps.c
+++ b/tools/perf/util/maps.c
@@ -788,7 +788,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, st
*mapp = map__get(map);
break;
}
- sym = NULL;
+ symbol__zput(sym);
}
for (unsigned int i = 0; i < nr_maps; i++)
@@ -810,6 +810,7 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)
}
ams->al_addr = map__map_ip(ams->ms.map, ams->addr);
+ symbol__put(ams->ms.sym);
ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr);
return ams->ms.sym ? 0 : -1;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 47dbe865c2f9..4b2d4db364b8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -152,6 +152,8 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr,
*addr = map__unmap_ip(map, symbol__start(sym)) -
((reloc) ? 0 : map__reloc(map)) -
((reladdr) ? map__start(map) : 0);
+ symbol__put(sym);
+ map__put(map);
}
return 0;
}
@@ -422,6 +424,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
pp->function);
} else
address = map__unmap_ip(map, symbol__start(sym)) - map__reloc(map);
+ symbol__put(sym);
break;
}
if (!address) {
@@ -728,11 +731,14 @@ static int post_process_probe_trace_point(struct probe_trace_point *tp,
else
free(tp->symbol);
tp->symbol = strdup(symbol__name(sym));
- if (!tp->symbol)
+ if (!tp->symbol) {
+ symbol__put(sym);
return -ENOMEM;
+ }
}
tp->offset = addr - symbol__start(sym);
tp->address -= offs;
+ symbol__put(sym);
return 0;
}
@@ -2314,6 +2320,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
ret = pp->function ? 0 : -ENOMEM;
out:
+ symbol__put(sym);
map__put(map);
return ret;
@@ -3078,7 +3085,7 @@ static int find_probe_functions_cb(struct symbol *sym, void *data)
if (strglobmatch(norm, args->name)) {
args->found++;
if (args->syms && args->found < probe_conf.max_probes)
- args->syms[args->found - 1] = sym;
+ args->syms[args->found - 1] = symbol__get(sym);
}
free(buf);
return 0;
@@ -3146,7 +3153,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
goto out;
}
- syms = malloc(sizeof(struct symbol *) * probe_conf.max_probes);
+ syms = calloc(probe_conf.max_probes, sizeof(struct symbol *));
if (!syms) {
ret = -ENOMEM;
goto out;
@@ -3291,6 +3298,10 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
}
out:
+ if (syms) {
+ for (i = 0; i < probe_conf.max_probes; i++)
+ symbol__put(syms[i]);
+ }
map__put(map);
free(syms);
return ret;
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index d47f6865021e..6c8bce6c795e 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -814,7 +814,7 @@ static PyObject *pyrf_sample_event__srccode(PyObject *self, PyObject *args)
addr_location__init(&al);
al.thread = thread__get(pevent->al.thread);
al.map = map__get(pevent->al.map);
- al.sym = pevent->al.sym;
+ al.sym = symbol__get(pevent->al.sym);
al.addr = pevent->al.addr;
}
@@ -877,6 +877,7 @@ struct pyrf_callchain_node {
static void pyrf_callchain_node__delete(struct pyrf_callchain_node *pnode)
{
map__put(pnode->map);
+ symbol__put(pnode->sym);
Py_TYPE(pnode)->tp_free((PyObject *)pnode);
}
@@ -944,8 +945,10 @@ struct pyrf_callchain {
static void pyrf_callchain__delete(struct pyrf_callchain *pchain)
{
if (pchain->frames) {
- for (u64 i = 0; i < pchain->nr_frames; i++)
+ for (u64 i = 0; i < pchain->nr_frames; i++) {
map__put(pchain->frames[i].map);
+ symbol__put(pchain->frames[i].sym);
+ }
free(pchain->frames);
}
Py_TYPE(pchain)->tp_free((PyObject *)pchain);
@@ -974,7 +977,7 @@ static PyObject *pyrf_callchain__item(PyObject *obj, Py_ssize_t i)
pnode->ip = pchain->frames[i].ip;
pnode->map = map__get(pchain->frames[i].map);
- pnode->sym = pchain->frames[i].sym;
+ pnode->sym = symbol__get(pchain->frames[i].sym);
return (PyObject *)pnode;
}
@@ -1486,7 +1489,8 @@ static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *ev
pchain->frames[i].ip = node->ip;
pchain->frames[i].map =
map__get(node->ms.map);
- pchain->frames[i].sym = node->ms.sym;
+ pchain->frames[i].sym =
+ symbol__get(node->ms.sym);
callchain_cursor_advance(cursor);
}
pevent->callchain = (PyObject *)pchain;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 89e833f35fd2..79ea71aab13c 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -466,7 +466,7 @@ int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
if (!sym_l || !sym_r)
return cmp_null(sym_l, sym_r);
- if (sym_l == sym_r)
+ if (RC_CHK_EQUAL(sym_l, sym_r))
return 0;
if (symbol__inlined(sym_l) || symbol__inlined(sym_r)) {
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 53976de3105c..4151107ccae1 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -118,7 +118,7 @@ struct symbol *new_inline_sym(struct dso *dso,
if (base_sym && strcmp(funcname, symbol__name(base_sym)) == 0) {
/* reuse the real, existing symbol */
- inline_sym = base_sym;
+ inline_sym = symbol__get(base_sym);
/* ensure that we don't alias an inlined symbol, which could
* lead to double frees in inline_node__delete
*/
@@ -468,9 +468,7 @@ void inline_node__clear_frames(struct inline_node *node)
list_for_each_entry_safe(ilist, tmp, &node->val, list) {
list_del_init(&ilist->list);
zfree_srcline(&ilist->srcline);
- /* only the inlined symbols are owned by the list */
- if (ilist->symbol && symbol__inlined(ilist->symbol))
- symbol__delete(ilist->symbol);
+ symbol__zput(ilist->symbol);
free(ilist);
}
}
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 73885413073b..90542fb643e9 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -351,10 +351,13 @@ static bool get_ifunc_name(Elf *elf, struct dso *dso, GElf_Ehdr *ehdr,
/* Expecting the address to be an IFUNC or IFUNC alias */
if (!sym || symbol__start(sym) != addr ||
- (symbol__type(sym) != STT_GNU_IFUNC && !symbol__ifunc_alias(sym)))
+ (symbol__type(sym) != STT_GNU_IFUNC && !symbol__ifunc_alias(sym))) {
+ symbol__put(sym);
return false;
+ }
snprintf(buf, buf_sz, "%s@plt", symbol__name(sym));
+ symbol__put(sym);
return true;
}
@@ -631,6 +634,7 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss)
f = dso__find_symbol_nocache(dso, shdr_plt.sh_offset);
if (f && symbol__start(f) < shdr_plt.sh_offset && symbol__end(f) > shdr_plt.sh_offset)
symbol__set_end(f, shdr_plt.sh_offset);
+ symbol__put(f);
if (!get_plt_sizes(dso, &ehdr, &shdr_plt, &plt_header_size, &plt_entry_size))
return 0;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index d25d8c96ee66..593fccfe3240 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <dirent.h>
#include <errno.h>
+#include <stdatomic.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -228,7 +229,7 @@ void symbols__init(struct symbols *symbols)
static void symbols__delete_locked(struct symbols *symbols)
{
for (unsigned int i = 0; i < symbols->cnt; i++)
- symbol__delete(symbols->symbols[i]);
+ symbol__put(symbols->symbols[i]);
zfree(&symbols->symbols);
zfree(&symbols->symbols_by_name);
@@ -331,11 +332,11 @@ void symbols__fixup_duplicate(struct symbols *symbols)
if (choose_best_symbol(curr, next) == SYMBOL_A) {
if (symbol__type(next) == STT_GNU_IFUNC)
symbol__set_ifunc_alias(curr, true);
- symbol__delete(next);
+ symbol__put(next);
} else {
if (symbol__type(curr) == STT_GNU_IFUNC)
symbol__set_ifunc_alias(next, true);
- symbol__delete(curr);
+ symbol__put(curr);
symbols->symbols[write_idx] = next;
}
}
@@ -421,81 +422,96 @@ void symbols__fixup_end(struct symbols *symbols, bool is_kallsyms)
struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name)
{
size_t namelen = strlen(name) + 1;
- struct symbol *sym = calloc(1, sizeof(*sym) + namelen);
-
- if (sym == NULL)
- return NULL;
-
- sym->start = start;
- sym->end = len ? start + len : start;
- atomic_init(&sym->flags, (type << SYMBOL_FLAG_TYPE_SHIFT) |
- (binding << SYMBOL_FLAG_BINDING_SHIFT));
- sym->namelen = namelen - 1;
-
- pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
- __func__, name, start, sym->end);
- memcpy(sym->name, name, namelen);
+ RC_STRUCT(symbol) *sym;
+ struct symbol *res;
+
+ sym = calloc(1, sizeof(*sym) + namelen);
+
+ if (ADD_RC_CHK(res, sym)) {
+ refcount_set(&sym->refcnt, 1);
+ sym->start = start;
+ sym->end = len ? start + len : start;
+ atomic_init(&sym->flags, (type << SYMBOL_FLAG_TYPE_SHIFT) |
+ (binding << SYMBOL_FLAG_BINDING_SHIFT));
+ sym->namelen = namelen - 1;
+
+ pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
+ __func__, name, start, sym->end);
+ memcpy(sym->name, name, namelen);
+ } else {
+ free(sym);
+ }
- return sym;
+ return res;
}
void symbol__delete(struct symbol *sym)
{
+ if (!sym)
+ return;
if (symbol__annotated(sym))
symbol__annotation_delete(sym);
- free(sym);
+ RC_CHK_FREE(sym);
+}
+
+void symbol__put(struct symbol *sym)
+{
+ if (sym && refcount_dec_and_test(symbol__refcnt(sym)))
+ symbol__delete(sym);
+ else
+ RC_CHK_PUT(sym);
}
void symbol__set_ignore(struct symbol *sym, bool ignore)
{
if (ignore)
- atomic_fetch_or(&sym->flags, SYMBOL_FLAG_IGNORE);
+ atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_IGNORE);
else
- atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_IGNORE);
+ atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_IGNORE);
}
void symbol__set_annotate2(struct symbol *sym, bool annotate2)
{
if (annotate2)
- atomic_fetch_or(&sym->flags, SYMBOL_FLAG_ANNOTATE2);
+ atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_ANNOTATE2);
else
- atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_ANNOTATE2);
+ atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_ANNOTATE2);
}
void symbol__set_inlined(struct symbol *sym, bool inlined)
{
if (inlined)
- atomic_fetch_or(&sym->flags, SYMBOL_FLAG_INLINED);
+ atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_INLINED);
else
- atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_INLINED);
+ atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_INLINED);
}
void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias)
{
if (ifunc_alias)
- atomic_fetch_or(&sym->flags, SYMBOL_FLAG_IFUNC_ALIAS);
+ atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_IFUNC_ALIAS);
else
- atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_IFUNC_ALIAS);
+ atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_IFUNC_ALIAS);
}
void symbol__set_annotated(struct symbol *sym, bool annotated)
{
if (annotated)
- atomic_fetch_or(&sym->flags, SYMBOL_FLAG_ANNOTATED);
+ atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_ANNOTATED);
else
- atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_ANNOTATED);
+ atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_ANNOTATED);
}
static void symbol__set_idle(struct symbol *sym, bool idle)
{
- uint16_t old_flags = atomic_load_explicit(&sym->flags, memory_order_relaxed);
+ uint16_t old_flags = atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed);
uint16_t new_flags;
uint16_t idle_val = idle ? SYMBOL_IDLE__IDLE : SYMBOL_IDLE__NOT_IDLE;
do {
new_flags = old_flags & ~SYMBOL_FLAG_IDLE_MASK;
new_flags |= (idle_val << SYMBOL_FLAG_IDLE_SHIFT);
- } while (!atomic_compare_exchange_weak(&sym->flags, &old_flags, new_flags));
+ } while (!atomic_compare_exchange_weak(&RC_CHK_ACCESS(sym)->flags, &old_flags, new_flags));
}
int __symbols__insert(struct symbols *symbols, struct symbol *sym)
@@ -506,7 +522,7 @@ int __symbols__insert(struct symbols *symbols, struct symbol *sym)
sizeof(struct symbol *) * to_allocate);
if (!temp) {
- symbol__delete(sym);
+ symbol__put(sym);
return -ENOMEM;
}
symbols->symbols = temp;
@@ -559,7 +575,7 @@ static struct symbol *symbols__find(struct symbols *symbols, u64 ip)
else if (ip > end || (ip == end && ip != start))
low = mid + 1;
else {
- res = s;
+ res = symbol__get(s);
break;
}
}
@@ -684,7 +700,7 @@ static struct symbol *symbols__find_by_name(struct symbol *symbols[],
}
}
assert(!found_idx || !s || s == symbols[*found_idx]);
- return s;
+ return symbol__get(s);
}
int dso__insert_symbol(struct dso *dso, struct symbol *sym)
@@ -698,14 +714,16 @@ void dso__delete_symbol(struct dso *dso, struct symbol *sym)
down_write(&symbols->lock);
for (unsigned int i = 0; i < symbols->cnt; i++) {
- if (symbols->symbols[i] == sym) {
+ if (RC_CHK_EQUAL(symbols->symbols[i], sym)) {
+ struct symbol *old = symbols->symbols[i];
+
memmove(&symbols->symbols[i], &symbols->symbols[i + 1],
(symbols->cnt - i - 1) * sizeof(struct symbol *));
symbols->cnt--;
zfree(&symbols->symbols_by_name);
symbols->num_by_name = 0;
symbols->sorted_by_name = false;
- symbol__delete(sym);
+ symbol__put(old);
break;
}
}
@@ -724,11 +742,17 @@ struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr)
struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx)
{
- if (*idx + 1 >= dso__symbol_names_len(dso))
- return NULL;
+ struct symbols *symbols = dso__symbols(dso);
+ struct symbol *res = NULL;
+
+ down_read(&symbols->lock);
+ if (*idx + 1 < symbols->num_by_name) {
+ ++*idx;
+ res = symbol__get(symbols->symbols_by_name[*idx]);
+ }
+ up_read(&symbols->lock);
- ++*idx;
- return dso__symbol_names(dso)[*idx];
+ return res;
}
/*
@@ -736,16 +760,26 @@ struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx)
*/
struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name, size_t *idx)
{
+ struct symbols *symbols;
struct symbol *s;
- dso__sort_by_name(dso);
- s = symbols__find_by_name(dso__symbol_names(dso),
- dso__symbol_names_len(dso),
+ symbols = dso__symbols(dso);
+ down_read(&symbols->lock);
+ while (!symbols->sorted_by_name) {
+ up_read(&symbols->lock);
+ dso__sort_by_name(dso);
+ down_read(&symbols->lock);
+ if (!symbols->sorted_by_name && !symbols->symbols_by_name)
+ break;
+ }
+ s = symbols__find_by_name(symbols->symbols_by_name,
+ symbols->num_by_name,
name, SYMBOL_TAG_INCLUDE__NONE, idx);
if (!s) {
- s = symbols__find_by_name(dso__symbol_names(dso), dso__symbol_names_len(dso),
+ s = symbols__find_by_name(symbols->symbols_by_name, symbols->num_by_name,
name, SYMBOL_TAG_INCLUDE__DEFAULT_ONLY, idx);
}
+ up_read(&symbols->lock);
return s;
}
@@ -884,7 +918,8 @@ bool symbol__is_idle(struct symbol *sym, const struct dso *dso, struct perf_env
uint16_t e_machine;
{
- uint16_t flags = atomic_load_explicit(&sym->flags, memory_order_relaxed);
+ uint16_t flags = atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags,
+ memory_order_relaxed);
uint16_t idle_val = (flags & SYMBOL_FLAG_IDLE_MASK) >> SYMBOL_FLAG_IDLE_SHIFT;
if (idle_val != SYMBOL_IDLE__UNKNOWN)
@@ -1032,7 +1067,7 @@ static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso)
curr_map = maps__find(kmaps, symbol__start(pos));
if (!curr_map) {
- symbol__delete(pos);
+ symbol__put(pos);
continue;
}
curr_map_dso = map__dso(curr_map);
@@ -1228,7 +1263,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
continue;
discard_symbol:
- symbol__delete(pos);
+ symbol__put(pos);
}
root->cnt = write_idx;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 52cd6b43696c..a3c88b5224ec 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -13,6 +13,7 @@
#include <linux/string.h>
#include <stdio.h>
#include <errno.h>
+#include <internal/rc_check.h>
#include "addr_location.h"
#include "path.h"
#include "rwsem.h"
@@ -93,10 +94,12 @@ enum symbol_idle_kind {
/**
* A symtab entry.
*/
-struct symbol {
+DECLARE_RC_STRUCT(symbol) {
/** Range of symbol [start, end). */
u64 start;
u64 end;
+ /** Reference count. */
+ refcount_t refcnt;
/** Length of the string name. */
u16 namelen;
_Atomic uint16_t flags;
@@ -143,85 +146,110 @@ void symbols__exit(struct symbols *symbols);
void symbols__delete(struct symbols *symbols);
void symbols__sort_read_lock(struct symbols *symbols) SHARED_LOCK_FUNCTION(symbols->lock);
+static inline refcount_t *symbol__refcnt(struct symbol *sym)
+{
+ return &RC_CHK_ACCESS(sym)->refcnt;
+}
+
+static inline struct symbol *symbol__get(struct symbol *sym)
+{
+ struct symbol *result;
+
+ if (RC_CHK_GET(result, sym))
+ refcount_inc(symbol__refcnt(sym));
+
+ return result;
+}
+
+void symbol__put(struct symbol *sym);
+
+static inline void __symbol__zput(struct symbol **sym)
+{
+ symbol__put(*sym);
+ *sym = NULL;
+}
+
+#define symbol__zput(sym) __symbol__zput(&sym)
+
static inline u64 symbol__start(const struct symbol *sym)
{
- return sym->start;
+ return RC_CHK_ACCESS(sym)->start;
}
static inline void symbol__set_start(struct symbol *sym, u64 start)
{
- sym->start = start;
+ RC_CHK_ACCESS(sym)->start = start;
}
static inline u64 symbol__end(const struct symbol *sym)
{
- return sym->end;
+ return RC_CHK_ACCESS(sym)->end;
}
static inline void symbol__set_end(struct symbol *sym, u64 end)
{
- sym->end = end;
+ RC_CHK_ACCESS(sym)->end = end;
}
static inline const char *symbol__name(const struct symbol *sym)
{
- return sym->name;
+ return RC_CHK_ACCESS(sym)->name;
}
static inline u16 symbol__namelen(const struct symbol *sym)
{
- return sym->namelen;
+ return RC_CHK_ACCESS(sym)->namelen;
}
static inline u8 symbol__arch_sym(const struct symbol *sym)
{
- return sym->arch_sym;
+ return RC_CHK_ACCESS(sym)->arch_sym;
}
static inline void symbol__set_arch_sym(struct symbol *sym, u8 arch_sym)
{
- sym->arch_sym = arch_sym;
+ RC_CHK_ACCESS(sym)->arch_sym = arch_sym;
}
static inline u8 symbol__type(const struct symbol *sym)
{
- return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
SYMBOL_FLAG_TYPE_MASK) >> SYMBOL_FLAG_TYPE_SHIFT;
}
static inline u8 symbol__binding(const struct symbol *sym)
{
- return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
SYMBOL_FLAG_BINDING_MASK) >> SYMBOL_FLAG_BINDING_SHIFT;
}
static inline bool symbol__ignore(const struct symbol *sym)
{
- return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
SYMBOL_FLAG_IGNORE) != 0;
}
static inline bool symbol__inlined(const struct symbol *sym)
{
- return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
SYMBOL_FLAG_INLINED) != 0;
}
static inline bool symbol__is_annotate2(const struct symbol *sym)
{
- return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
SYMBOL_FLAG_ANNOTATE2) != 0;
}
static inline bool symbol__ifunc_alias(const struct symbol *sym)
{
- return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
SYMBOL_FLAG_IFUNC_ALIAS) != 0;
}
static inline bool symbol__annotated(const struct symbol *sym)
{
- return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+ return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
SYMBOL_FLAG_ANNOTATED) != 0;
}
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
index 76867ba83365..e2c73e890158 100644
--- a/tools/perf/util/thread-stack.c
+++ b/tools/perf/util/thread-stack.c
@@ -823,7 +823,7 @@ static int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
if (ts->cnt == 1) {
struct thread_stack_entry *tse = &ts->stack[0];
- if (tse->cp->sym == sym)
+ if (RC_CHK_EQUAL(tse->cp->sym, sym))
return thread_stack__call_return(thread, ts, --ts->cnt,
timestamp, ref, false);
}
@@ -941,7 +941,7 @@ static int thread_stack__no_call_return(struct thread *thread,
else
parent = root;
- if (parent->sym == from_al->sym) {
+ if (RC_CHK_EQUAL(parent->sym, from_al->sym)) {
/*
* At the bottom of the stack, assume the missing 'call' was
* before the trace started. So, pop the current symbol and push
@@ -1069,7 +1069,7 @@ static int thread_stack__x86_retpoline(struct thread_stack *ts,
*/
ts->cnt -= 1;
sym = ts->stack[ts->cnt - 2].cp->sym;
- if (sym && sym == tsym && to_al->addr != symbol__start(tsym)) {
+ if (sym && RC_CHK_EQUAL(sym, tsym) && to_al->addr != symbol__start(tsym)) {
/*
* Target is back to the middle of the symbol we came
* from so assume it is an indirect jmp and forget it
@@ -1078,7 +1078,7 @@ static int thread_stack__x86_retpoline(struct thread_stack *ts,
ts->cnt -= 1;
return 0;
}
- } else if (sym && sym == tsym) {
+ } else if (sym && RC_CHK_EQUAL(sym, tsym)) {
/*
* Target is back to the symbol we came from so assume it is an
* indirect jmp and forget it altogether.
@@ -1169,7 +1169,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
* may be the start of a x86 retpoline.
*/
if (!err && rstate == X86_RETPOLINE_POSSIBLE && to_al->sym &&
- from_al->sym == to_al->sym &&
+ RC_CHK_EQUAL(from_al->sym, to_al->sym) &&
to_al->addr != symbol__start(to_al->sym))
ts->rstate = X86_RETPOLINE_DETECTED;
@@ -1206,7 +1206,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
} else if (sample->flags & PERF_IP_FLAG_TRACE_END) {
err = thread_stack__trace_end(ts, sample, ref);
} else if (sample->flags & PERF_IP_FLAG_BRANCH &&
- from_al->sym != to_al->sym && to_al->sym &&
+ !RC_CHK_EQUAL(from_al->sym, to_al->sym) && to_al->sym &&
to_al->addr == symbol__start(to_al->sym)) {
struct call_path_root *cpr = ts->crp->cpr;
struct call_path *cp;
diff --git a/tools/perf/util/threads.c b/tools/perf/util/threads.c
index 6ca0b178fb6c..b3ec954fe7ab 100644
--- a/tools/perf/util/threads.c
+++ b/tools/perf/util/threads.c
@@ -142,10 +142,13 @@ void threads__remove_all_threads(struct threads *threads)
down_write(&table->lock);
__threads_table_entry__set_last_match(table, NULL);
hashmap__for_each_entry_safe(&table->shard, cur, tmp, bkt) {
- struct thread *old_value;
+ struct thread *old_value = NULL;
- hashmap__delete(&table->shard, cur->key, /*old_key=*/NULL, &old_value);
- thread__put(old_value);
+ if (hashmap__delete(&table->shard, cur->key,
+ /*old_key=*/NULL, &old_value)) {
+ thread__free_stitch_list(old_value);
+ thread__put(old_value);
+ }
}
up_write(&table->lock);
}
@@ -154,14 +157,16 @@ void threads__remove_all_threads(struct threads *threads)
void threads__remove(struct threads *threads, struct thread *thread)
{
struct threads_table_entry *table = threads__table(threads, thread__tid(thread));
- struct thread *old_value;
+ struct thread *old_value = NULL;
down_write(&table->lock);
if (table->last_match && RC_CHK_EQUAL(table->last_match, thread))
__threads_table_entry__set_last_match(table, NULL);
- hashmap__delete(&table->shard, thread__tid(thread), /*old_key=*/NULL, &old_value);
- thread__put(old_value);
+ if (hashmap__delete(&table->shard, thread__tid(thread), /*old_key=*/NULL, &old_value)) {
+ thread__free_stitch_list(old_value);
+ thread__put(old_value);
+ }
up_write(&table->lock);
}
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 87ade098b5c6..eb4327aa9e7e 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -169,7 +169,7 @@ static int entry(u64 ip, struct unwind_info *ui)
e->ip = ip;
e->ms.thread = thread__get(al.thread);
e->ms.map = map__get(al.map);
- e->ms.sym = al.sym;
+ e->ms.sym = symbol__get(al.sym);
pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
al.sym ? symbol__name(al.sym) : "''",
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 6052383e862b..42872c7b6dcd 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -632,7 +632,7 @@ static int entry(uint64_t ip, struct thread *thread, unwind_entry_cb_t cb, void
e.ms.thread = thread__get(al.thread);
pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
- al.sym ? al.sym->name : "''",
+ al.sym ? symbol__name(al.sym) : "''",
ip,
al.map ? map__map_ip(al.map, ip) : (u64) 0);
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 5/7] perf symbol: Add LRU memory shrinking for symbols, DSOs, and machines
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
` (3 preceding siblings ...)
2026-09-28 7:52 ` [PATCH v1 4/7] perf symbol: Add reference counting and DECLARE_RC_STRUCT(symbol) Ian Rogers
@ 2026-09-28 7:52 ` Ian Rogers
2026-09-28 7:52 ` [PATCH v1 6/7] perf session: Periodically shrink symbols and DSOs during event processing Ian Rogers
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Rogers @ 2026-09-28 7:52 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter, James Clark,
linux-perf-users, linux-kernel, Alireza Haghdoost
Add Clock/Second-Chance LRU access tracking (SYMBOL_FLAG_ACCESSED on
struct symbol, accessed on struct dso, and shrunk on struct symbols) and
memory-shrinking helpers (symbols__shrink, dso__can_shrink_symbols,
dso__shrink, dsos__shrink, machine__shrink, machines__shrink, and
perf_session__shrink):
- symbols__shrink() scans a symbol table under symbols->lock: symbols
with refcnt > 1 are retained, symbols with SYMBOL_FLAG_ACCESSED set
have their accessed bit cleared (second chance), and unreferenced
symbols with SYMBOL_FLAG_ACCESSED clear are evicted. When symbols are
evicted, symbols->shrunk is set under symbols->lock and the backing
array is compacted when occupancy drops below 50%.
- dso__shrink() closes any cached file descriptor, frees cached 4KB DSO
data pages (__dso_cache__free()) and addr2line/libbfd/libdw state
under dso__lock(dso), and shrinks dso->symbols if the DSO supports
idempotent on-demand reloading (dso__can_shrink_symbols()). Protect
dso_cache lookup and memcpy under dso__lock(dso) so concurrent
shrinking cannot free a cache page while it is being read.
- dsos__shrink() sweeps a DSO collection using Clock/Second-Chance LRU:
accessed DSOs have their symbol tables shrunk and their accessed bit
cleared; unaccessed DSOs are fully shrunk via dso__shrink() and
evicted from struct dsos if unreferenced outside the collection
(refcnt == 1) and free of unreloadable state.
- When a DSO's symbol table has been shrunk (dso__symbols_shrunk(dso) is
true) and a subsequent symbol lookup misses in map__find_symbol() or
map__find_symbol_by_name_idx(), transparently reload the DSO on demand
while preferring actively referenced (refcnt > 1) symbols in
choose_best_symbol() and deduplicating identical (start, name) pairs
in symbols__fixup_duplicate() even when symbol_conf.allow_aliases is
enabled.
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/dso.c | 182 +++++++++++++++++++++++++++--------
tools/perf/util/dso.h | 46 +++++++++
tools/perf/util/dsos.c | 100 +++++++++++++++++++
tools/perf/util/dsos.h | 12 ++-
tools/perf/util/machine.c | 39 ++++++++
tools/perf/util/machine.h | 2 +
tools/perf/util/map.c | 26 ++++-
tools/perf/util/session.c | 15 +++
tools/perf/util/session.h | 3 +
tools/perf/util/symbol-elf.c | 5 +-
tools/perf/util/symbol.c | 142 +++++++++++++++++++++++++--
tools/perf/util/symbol.h | 36 +++++--
12 files changed, 551 insertions(+), 57 deletions(-)
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 1b96853164be..330e43cc325b 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -877,6 +877,7 @@ bool dso__data_get_fd(struct dso *dso, struct machine *machine, int *fd)
if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR)
return false;
+ dso__set_accessed(dso, true);
mutex_lock(dso__data_open_lock());
try_to_open_dso(dso, machine);
@@ -955,12 +956,11 @@ static int bpf_size(struct dso *dso)
#endif // HAVE_LIBBPF_SUPPORT
static void
-dso_cache__free(struct dso *dso)
+__dso_cache__free(struct dso *dso)
{
struct rb_root *root = &dso__data(dso)->cache;
struct rb_node *next = rb_first(root);
- mutex_lock(dso__lock(dso));
while (next) {
struct dso_cache *cache;
@@ -969,6 +969,13 @@ dso_cache__free(struct dso *dso)
rb_erase(&cache->rb_node, root);
free(cache);
}
+}
+
+static void
+dso_cache__free(struct dso *dso)
+{
+ mutex_lock(dso__lock(dso));
+ __dso_cache__free(dso);
mutex_unlock(dso__lock(dso));
}
@@ -998,7 +1005,7 @@ static struct dso_cache *__dso_cache__find(struct dso *dso, u64 offset)
}
static struct dso_cache *
-dso_cache__insert(struct dso *dso, struct dso_cache *new)
+__dso_cache__insert(struct dso *dso, struct dso_cache *new)
{
struct rb_root *root = &dso__data(dso)->cache;
struct rb_node **p = &root->rb_node;
@@ -1006,7 +1013,6 @@ dso_cache__insert(struct dso *dso, struct dso_cache *new)
struct dso_cache *cache;
u64 offset = new->offset;
- mutex_lock(dso__lock(dso));
while (*p != NULL) {
u64 end;
@@ -1019,16 +1025,13 @@ dso_cache__insert(struct dso *dso, struct dso_cache *new)
else if (offset >= end)
p = &(*p)->rb_right;
else
- goto out;
+ return cache;
}
rb_link_node(&new->rb_node, parent, p);
rb_insert_color(&new->rb_node, root);
- cache = NULL;
-out:
- mutex_unlock(dso__lock(dso));
- return cache;
+ return NULL;
}
static ssize_t dso_cache__memcpy(struct dso_cache *cache, u64 offset, u8 *data,
@@ -1082,68 +1085,69 @@ static ssize_t file_read(struct dso *dso, struct machine *machine,
return ret;
}
-static struct dso_cache *dso_cache__populate(struct dso *dso,
- struct machine *machine,
- u64 offset, ssize_t *ret)
+static ssize_t dso_cache__populate(struct dso *dso, struct machine *machine,
+ u64 offset, u8 *data, ssize_t size, bool out)
{
u64 cache_offset = offset & DSO__DATA_CACHE_MASK;
struct dso_cache *cache;
struct dso_cache *old;
+ ssize_t ret;
cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
- if (!cache) {
- *ret = -ENOMEM;
- return NULL;
- }
+ if (!cache)
+ return -ENOMEM;
#ifdef HAVE_LIBBPF_SUPPORT
if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO)
- *ret = bpf_read(dso, cache_offset, cache->data);
+ ret = bpf_read(dso, cache_offset, cache->data);
else
#endif
if (dso__binary_type(dso) == DSO_BINARY_TYPE__OOL)
- *ret = DSO__DATA_CACHE_SIZE;
+ ret = DSO__DATA_CACHE_SIZE;
else
- *ret = file_read(dso, machine, cache_offset, cache->data);
+ ret = file_read(dso, machine, cache_offset, cache->data);
- if (*ret <= 0) {
+ if (ret <= 0) {
free(cache);
- return NULL;
+ return ret;
}
cache->offset = cache_offset;
- cache->size = *ret;
+ cache->size = ret;
- old = dso_cache__insert(dso, cache);
+ mutex_lock(dso__lock(dso));
+ old = __dso_cache__insert(dso, cache);
if (old) {
/* we lose the race */
free(cache);
cache = old;
}
+ ret = dso_cache__memcpy(cache, offset, data, size, out);
+ mutex_unlock(dso__lock(dso));
- return cache;
-}
-
-static struct dso_cache *dso_cache__find(struct dso *dso,
- struct machine *machine,
- u64 offset,
- ssize_t *ret)
-{
- struct dso_cache *cache = __dso_cache__find(dso, offset);
-
- return cache ? cache : dso_cache__populate(dso, machine, offset, ret);
+ return ret;
}
+/*
+ * Look up and copy cached DSO data while holding dso__lock(dso) so a
+ * concurrent dso__shrink() / __dso_cache__free() cannot free the cache node
+ * while it is being read.
+ */
static ssize_t dso_cache_io(struct dso *dso, struct machine *machine,
u64 offset, u8 *data, ssize_t size, bool out)
{
struct dso_cache *cache;
- ssize_t ret = 0;
+ ssize_t ret;
- cache = dso_cache__find(dso, machine, offset, &ret);
- if (!cache)
+ mutex_lock(dso__lock(dso));
+ cache = __dso_cache__find(dso, offset);
+ if (cache) {
+ ret = dso_cache__memcpy(cache, offset, data, size, out);
+ mutex_unlock(dso__lock(dso));
return ret;
+ }
+ mutex_unlock(dso__lock(dso));
- return dso_cache__memcpy(cache, offset, data, size, out);
+ return dso_cache__populate(dso, machine, offset, data, size, out);
}
/*
@@ -1157,6 +1161,7 @@ static ssize_t cached_io(struct dso *dso, struct machine *machine,
ssize_t r = 0;
u8 *p = data;
+ dso__set_accessed(dso, true);
do {
ssize_t ret;
@@ -1723,6 +1728,7 @@ struct dso *dso__new_id(const char *name, const struct dso_id *id)
dso->is_kmod = 0;
dso->needs_swap = DSO_SWAP__UNSET;
dso->comp = COMP_ID__NONE;
+ atomic_init(&dso->accessed, false);
mutex_init(&dso->lock);
refcount_set(&dso->refcnt, 1);
data = &dso->data;
@@ -1776,6 +1782,106 @@ void dso__delete(struct dso *dso)
RC_CHK_FREE(dso);
}
+/**
+ * dso__can_shrink_symbols - Check if a DSO's symbol table can be shrunk and
+ * reloaded on demand.
+ * @dso: DSO to check.
+ *
+ * Shrinking evicts unreferenced symbols from @dso->symbols and relies on
+ * dso__load() being able to reload the missing symbols idempotently if a future
+ * lookup misses in map__find_symbol(). Not all DSO types support idempotent
+ * reloading:
+ *
+ * - User-space ELF binaries, debuginfo files, build-id cache files, and
+ * perf-<pid>.map JIT files (dso__kernel(dso) == DSO_SPACE__USER), as well as
+ * standalone kernel module ELF files (dso__is_kmod(dso)), load their symbols
+ * directly into @dso->symbols from a backing file on disk and can be safely
+ * reloaded on demand.
+ *
+ * - Main kernel and guest kernel DSOs (vmlinux / kallsyms where
+ * dso__kernel(dso) != DSO_SPACE__USER && !dso__is_kmod(dso)) split their
+ * loaded symbols across multiple per-section or per-module maps and DSOs in
+ * machine->kmaps (via maps__split_kallsyms()). Re-running dso__load() on one
+ * of the split kernel DSOs would either fail to find a backing file or
+ * re-split and duplicate kernel maps, so they are excluded.
+ *
+ * - KCORE / GUEST_KCORE DSOs replace and remap kernel maps in machine->kmaps
+ * when loaded from /proc/kcore, so they cannot be reloaded in place.
+ *
+ * - BPF_PROG_INFO, BPF_IMAGE, and OOL DSOs have their symbols synthesized in
+ * memory from PERF_RECORD_KSYMBOL / PERF_RECORD_BPF_EVENT meta-events rather
+ * than loaded from disk by dso__load(), so evicting their symbols would lose
+ * them permanently.
+ *
+ * Return: True if @dso->symbols can be safely shrunk and reloaded on demand.
+ */
+bool dso__can_shrink_symbols(const struct dso *dso)
+{
+ switch (dso__symtab_type(dso)) {
+ case DSO_BINARY_TYPE__KALLSYMS:
+ case DSO_BINARY_TYPE__GUEST_KALLSYMS:
+ case DSO_BINARY_TYPE__VMLINUX:
+ case DSO_BINARY_TYPE__GUEST_VMLINUX:
+ case DSO_BINARY_TYPE__JAVA_JIT:
+ case DSO_BINARY_TYPE__DEBUGLINK:
+ case DSO_BINARY_TYPE__BUILD_ID_CACHE:
+ case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
+ case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
+ case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
+ case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO:
+ case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
+ case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
+ case DSO_BINARY_TYPE__GUEST_KMODULE:
+ case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
+ case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+ case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
+ case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
+ case DSO_BINARY_TYPE__GNU_DEBUGDATA:
+ return dso__kernel(dso) == DSO_SPACE__USER || dso__is_kmod(dso);
+ case DSO_BINARY_TYPE__KCORE:
+ case DSO_BINARY_TYPE__GUEST_KCORE:
+ case DSO_BINARY_TYPE__BPF_PROG_INFO:
+ case DSO_BINARY_TYPE__BPF_IMAGE:
+ case DSO_BINARY_TYPE__OOL:
+ case DSO_BINARY_TYPE__NOT_FOUND:
+ default:
+ return false;
+ }
+}
+
+/**
+ * dso__shrink - Reclaim cached file data, debuginfo, and unreferenced symbols
+ * from a DSO.
+ * @dso: DSO to shrink.
+ *
+ * Closes any cached file descriptor, frees the 4KB page cache (@dso->data.cache),
+ * releases cached addr2line / libbfd / libdw handles, and shrinks @dso->symbols
+ * if supported by dso__can_shrink_symbols().
+ *
+ * Return: Number of symbols evicted from @dso->symbols.
+ */
+size_t dso__shrink(struct dso *dso)
+{
+ size_t removed = 0;
+
+ if (!dso)
+ return 0;
+
+ dso__data_close(dso);
+
+ mutex_lock(dso__lock(dso));
+ __dso_cache__free(dso);
+ dso__free_a2l(dso);
+ dso__free_a2l_libbfd(dso);
+ dso__free_libdw(dso);
+
+ if (dso__can_shrink_symbols(dso))
+ removed = symbols__shrink(dso__symbols(dso));
+ mutex_unlock(dso__lock(dso));
+
+ return removed;
+}
+
struct dso *dso__get(struct dso *dso)
{
struct dso *result;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 1de446966f01..3f27cb1a76df 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -285,13 +285,24 @@ struct dso_bpf_prog {
struct auxtrace_cache;
+/**
+ * struct dso - Dynamic Shared Object (executable, shared library, kernel, or
+ * module) metadata, symbol table, and cached file state.
+ */
DECLARE_RC_STRUCT(dso) {
+ /** @lock: Mutex serializing symbol loading and DSO state updates. */
struct mutex lock;
+ /** @dsos: Owning collection of DSOs, or NULL if not in a struct dsos. */
struct dsos *dsos;
+ /** @symbols: Sorted array of symbols belonging to this DSO. */
struct symbols symbols;
+ /** @inlined_nodes: Cached DWARF inline call-tree nodes for addresses. */
struct rb_root_cached inlined_nodes;
+ /** @srclines: Cached address-to-source-line mappings. */
struct rb_root_cached srclines;
+ /** @data_types: Cached DWARF annotated data type definitions. */
struct rb_root data_types;
+ /** @global_vars: Cached DWARF global variable locations. */
struct rb_root global_vars;
u64 text_offset;
@@ -319,6 +330,7 @@ DECLARE_RC_STRUCT(dso) {
struct dso_id id;
unsigned int a2l_fails;
int comp;
+ /** @refcnt: Reference count tracking active holders of the DSO. */
refcount_t refcnt;
enum dso_load_errno load_errno;
u16 long_name_len;
@@ -338,6 +350,12 @@ DECLARE_RC_STRUCT(dso) {
u8 short_name_allocated:1;
u8 long_name_allocated:1;
u8 is_64_bit:1;
+ /**
+ * @accessed: Clock/Second-Chance LRU flag set when the DSO or its
+ * symbols/data are looked up or read, and cleared by dsos__shrink().
+ */
+ _Atomic bool accessed;
+ /** @loaded: True once dso__load() has attempted to load symbols. */
bool loaded;
u8 rel;
char name[];
@@ -589,9 +607,30 @@ static inline enum dso_load_errno *dso__load_errno(struct dso *dso)
return &RC_CHK_ACCESS(dso)->load_errno;
}
+static inline bool dso__accessed(const struct dso *dso)
+{
+ return atomic_load_explicit(&RC_CHK_ACCESS(dso)->accessed, memory_order_relaxed);
+}
+
+static inline void dso__set_accessed(struct dso *dso, bool val)
+{
+ atomic_store_explicit(&RC_CHK_ACCESS(dso)->accessed, val, memory_order_relaxed);
+}
+
+static inline bool dso__symbols_shrunk(const struct dso *dso)
+{
+ return atomic_load_explicit(&RC_CHK_ACCESS(dso)->symbols.shrunk, memory_order_acquire);
+}
+
+static inline void dso__set_symbols_shrunk(struct dso *dso, bool val)
+{
+ atomic_store_explicit(&RC_CHK_ACCESS(dso)->symbols.shrunk, val, memory_order_release);
+}
+
static inline void dso__set_loaded(struct dso *dso)
{
RC_CHK_ACCESS(dso)->loaded = true;
+ dso__set_symbols_shrunk(dso, false);
}
static inline struct mutex *dso__lock(struct dso *dso)
@@ -661,6 +700,11 @@ static inline void dso__set_rel(struct dso *dso, u8 rel)
RC_CHK_ACCESS(dso)->rel = rel;
}
+static inline refcount_t *dso__refcnt(struct dso *dso)
+{
+ return &RC_CHK_ACCESS(dso)->refcnt;
+}
+
static inline const char *dso__short_name(const struct dso *dso)
{
return RC_CHK_ACCESS(dso)->short_name;
@@ -756,6 +800,8 @@ static inline void dso__set_text_offset(struct dso *dso, u64 val)
struct dso *dso__new_id(const char *name, const struct dso_id *id);
struct dso *dso__new(const char *name);
void dso__delete(struct dso *dso);
+bool dso__can_shrink_symbols(const struct dso *dso);
+size_t dso__shrink(struct dso *dso);
int dso__cmp_id(struct dso *a, struct dso *b);
void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated);
diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c
index e927e707abac..f64551ec2728 100644
--- a/tools/perf/util/dsos.c
+++ b/tools/perf/util/dsos.c
@@ -278,9 +278,13 @@ static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, const st
};
__dsos__for_each_dso(dsos, dsos__find_id_cb, &args);
+ if (args.res)
+ dso__set_accessed(args.res, true);
return args.res;
}
res = __dsos__find_by_longname_id(dsos, name, id, write_locked);
+ if (res)
+ dso__set_accessed(res, true);
return res;
}
@@ -324,6 +328,7 @@ static struct dso *__dsos__addnew_id(struct dsos *dsos, const char *name, const
* the array isn't sorted.
*/
dso__set_basename(dso);
+ dso__set_accessed(dso, true);
__dsos__add(dsos, dso);
}
return dso;
@@ -446,6 +451,7 @@ struct dso *dsos__findnew_module_dso(struct dsos *dsos,
dso__set_module_info(dso, m, machine);
dso__set_long_name(dso, strdup(filename), true);
dso__set_kernel(dso, DSO_SPACE__KERNEL);
+ dso__set_accessed(dso, true);
__dsos__add(dsos, dso);
up_write(&dsos->lock);
@@ -493,3 +499,97 @@ int dsos__for_each_dso(struct dsos *dsos, int (*cb)(struct dso *dso, void *data)
up_read(&dsos->lock);
return err;
}
+
+/**
+ * dsos__shrink - Reclaim cold symbols, DSO caches, and unreferenced DSOs.
+ * @dsos: Collection of DSOs to shrink.
+ *
+ * Implements a two-tier Clock/Second-Chance LRU eviction pass:
+ * 1. Snapshot all DSOs under the read lock and release @dsos->lock to respect
+ * the lock ordering (dso__lock() -> dsos->lock).
+ * - If a DSO was accessed since the previous shrink pass (dso__accessed(dso)
+ * is true), its file-level caches (fd, data cache, srclines, inlines,
+ * addr2line/libdw handles) get a second chance, while its unreferenced
+ * cold symbols are still shrunk via symbols__shrink().
+ * - If a DSO was not accessed since the previous shrink pass, dso__shrink()
+ * is called to release its file descriptor, data cache, debuginfo caches,
+ * and unreferenced symbols.
+ * 2. Re-acquire @dsos->lock for writing:
+ * - Clear @dso->accessed on DSOs that were accessed during the interval.
+ * - Evict and release cold user-space DSOs that have no remaining symbols,
+ * no header build-id, and refcount == 1 (referenced only by @dsos->dsos).
+ *
+ * Return: Number of DSOs evicted from @dsos.
+ */
+size_t dsos__shrink(struct dsos *dsos)
+{
+ struct dso **snapshot = NULL;
+ unsigned int cnt = 0, dst = 0;
+ size_t removed = 0;
+
+ if (!dsos)
+ return 0;
+
+ down_read(&dsos->lock);
+ if (dsos->cnt > 0) {
+ snapshot = calloc(dsos->cnt, sizeof(*snapshot));
+ if (snapshot) {
+ cnt = dsos->cnt;
+ for (unsigned int i = 0; i < cnt; i++)
+ snapshot[i] = dso__get(dsos->dsos[i]);
+ }
+ }
+ up_read(&dsos->lock);
+
+ if (!snapshot)
+ return 0;
+
+ for (unsigned int i = 0; i < cnt; i++) {
+ struct dso *dso = snapshot[i];
+
+ if (dso__accessed(dso)) {
+ mutex_lock(dso__lock(dso));
+ if (dso__can_shrink_symbols(dso))
+ symbols__shrink(dso__symbols(dso));
+ mutex_unlock(dso__lock(dso));
+ } else {
+ dso__shrink(dso);
+ }
+ dso__put(dso);
+ }
+ free(snapshot);
+
+ down_write(&dsos->lock);
+ for (unsigned int src = 0; src < dsos->cnt; src++) {
+ struct dso *dso = dsos->dsos[src];
+
+ if (dso__accessed(dso)) {
+ dso__set_accessed(dso, false);
+ dsos->dsos[dst++] = dso;
+ } else if (!dso__has_symbols(dso) &&
+ !dso__header_build_id(dso) &&
+ !dso__kernel(dso) &&
+ refcount_read(dso__refcnt(dso)) == 1) {
+ dso__set_dsos(dso, NULL);
+ dso__put(dso);
+ removed++;
+ } else {
+ dsos->dsos[dst++] = dso;
+ }
+ }
+ dsos->cnt = dst;
+ if (dst == 0) {
+ zfree(&dsos->dsos);
+ dsos->allocated = 0;
+ } else if (dst < dsos->allocated / 2) {
+ struct dso **temp = realloc(dsos->dsos, sizeof(*temp) * dst);
+
+ if (temp) {
+ dsos->dsos = temp;
+ dsos->allocated = dst;
+ }
+ }
+ up_write(&dsos->lock);
+
+ return removed;
+}
diff --git a/tools/perf/util/dsos.h b/tools/perf/util/dsos.h
index a26774950866..5c27f5efb74b 100644
--- a/tools/perf/util/dsos.h
+++ b/tools/perf/util/dsos.h
@@ -13,15 +13,20 @@ struct dso_id;
struct kmod_path;
struct machine;
-/*
- * Collection of DSOs as an array for iteration speed, but sorted for O(n)
- * lookup.
+/**
+ * struct dsos - Collection of DSOs stored as a sorted array for iteration speed
+ * and O(log n) lookup.
*/
struct dsos {
+ /** @lock: Read/write semaphore synchronizing access to @dsos. */
struct rw_semaphore lock;
+ /** @dsos: Dynamically allocated array of struct dso pointers. */
struct dso **dsos;
+ /** @cnt: Number of valid entries in @dsos. */
unsigned int cnt;
+ /** @allocated: Capacity (in entries) of the @dsos allocation. */
unsigned int allocated;
+ /** @sorted: True when @dsos is sorted by long name, dso_id, and short name. */
bool sorted;
};
@@ -48,5 +53,6 @@ struct dso *dsos__findnew_module_dso(struct dsos *dsos, struct machine *machine,
struct dso *dsos__find_kernel_dso(struct dsos *dsos);
int dsos__for_each_dso(struct dsos *dsos, int (*cb)(struct dso *dso, void *data), void *data);
+size_t dsos__shrink(struct dsos *dsos);
#endif /* __PERF_DSOS */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index f1155c608a95..ba0b982828c2 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -962,6 +962,45 @@ size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
return ret;
}
+/**
+ * machine__shrink - Reclaim unreferenced symbols, DSO caches, and cold DSOs
+ * for a machine.
+ * @machine: Machine to shrink.
+ *
+ * Return: Number of DSOs evicted from @machine->dsos.
+ */
+size_t machine__shrink(struct machine *machine)
+{
+ if (!machine)
+ return 0;
+
+ return dsos__shrink(&machine->dsos);
+}
+
+/**
+ * machines__shrink - Reclaim unreferenced symbols, DSO caches, and cold DSOs
+ * across the host and all guest machines.
+ * @machines: Collection of host and guest machines to shrink.
+ *
+ * Return: Total number of DSOs evicted across all machines.
+ */
+size_t machines__shrink(struct machines *machines)
+{
+ struct rb_node *nd;
+ size_t ret;
+
+ if (!machines)
+ return 0;
+
+ ret = machine__shrink(&machines->host);
+ for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
+
+ ret += machine__shrink(pos);
+ }
+ return ret;
+}
+
struct machine_fprintf_cb_args {
FILE *fp;
size_t printed;
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 973a59f7c26a..115e60979ec6 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -268,6 +268,8 @@ size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
size_t machines__fprintf_dsos(struct machines *machines, FILE *fp);
size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
bool (skip)(struct dso *dso, int parm), int parm);
+size_t machine__shrink(struct machine *machine);
+size_t machines__shrink(struct machines *machines);
void machine__destroy_kernel_maps(struct machine *machine);
int machine__create_kernel_maps(struct machine *machine);
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 19afe676adf2..633989615cf6 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -377,15 +377,30 @@ int map__load(struct map *map)
struct symbol *map__find_symbol(struct map *map, u64 addr)
{
+ struct dso *dso;
+ struct symbol *sym;
+
if (map__load(map) < 0)
return NULL;
- return dso__find_symbol(map__dso(map), addr);
+ dso = map__dso(map);
+ sym = dso__find_symbol(dso, addr);
+ /*
+ * If the DSO's symbol table was previously shrunk by symbols__shrink()
+ * and the lookup missed, transparently reload the DSO so evicted
+ * symbols are restored on demand rather than reported as [unknown].
+ */
+ if (!sym && dso__symbols_shrunk(dso)) {
+ if (dso__load(dso, map) >= 0)
+ sym = dso__find_symbol(dso, addr);
+ }
+ return sym;
}
struct symbol *map__find_symbol_by_name_idx(struct map *map, const char *name, size_t *idx)
{
struct dso *dso;
+ struct symbol *sym;
if (map__load(map) < 0)
return NULL;
@@ -393,7 +408,14 @@ struct symbol *map__find_symbol_by_name_idx(struct map *map, const char *name, s
dso = map__dso(map);
dso__sort_by_name(dso);
- return dso__find_symbol_by_name(dso, name, idx);
+ sym = dso__find_symbol_by_name(dso, name, idx);
+ if (!sym && dso__symbols_shrunk(dso)) {
+ if (dso__load(dso, map) >= 0) {
+ dso__sort_by_name(dso);
+ sym = dso__find_symbol_by_name(dso, name, idx);
+ }
+ }
+ return sym;
}
struct symbol *map__find_symbol_by_name(struct map *map, const char *name)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 7fea9e72726c..555d940a866a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -3933,6 +3933,21 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp
return machines__fprintf_dsos_buildid(&session->machines, fp, skip, parm);
}
+/**
+ * perf_session__shrink - Reclaim unreferenced symbols, DSO caches, and cold
+ * DSOs across all machines in the session.
+ * @session: Session to shrink.
+ *
+ * Return: Number of DSOs evicted across the session's machines.
+ */
+size_t perf_session__shrink(struct perf_session *session)
+{
+ if (!session)
+ return 0;
+
+ return machines__shrink(&session->machines);
+}
+
size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
{
size_t ret;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index ac5803d5fb4e..4b223c2cee7f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -91,7 +91,9 @@ struct perf_session {
u64 bytes_compressed;
/** @zstd_data: Owner of global compression state, buffers, etc. */
struct zstd_data zstd_data;
+ /** @decomp_data: Decompression state for the session data file. */
struct decomp_data decomp_data;
+ /** @active_decomp: Currently active decompression context. */
struct decomp_data *active_decomp;
};
@@ -175,6 +177,7 @@ size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp);
size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
bool (fn)(struct dso *dso, int parm), int parm);
+size_t perf_session__shrink(struct perf_session *session);
size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 90542fb643e9..00d088b43f94 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1826,9 +1826,10 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
/*
* Modules may already have symbols from kallsyms, but those symbols
- * have the wrong values for the dso maps, so remove them.
+ * have the wrong values for the dso maps, so remove them unless we are
+ * reloading a previously shrunk module.
*/
- if (kmodule && syms_ss->symtab)
+ if (kmodule && syms_ss->symtab && !dso__symbols_shrunk(dso))
symbols__delete(dso__symbols(dso));
if (!syms_ss->symtab) {
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 593fccfe3240..33cfd86156d2 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -164,6 +164,14 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
s64 b;
size_t na, nb;
+ /* Prefer a symbol that is actively referenced */
+ a = refcount_read(symbol__refcnt(syma)) > 1;
+ b = refcount_read(symbol__refcnt(symb)) > 1;
+ if (a && !b)
+ return SYMBOL_A;
+ if (b && !a)
+ return SYMBOL_B;
+
/* Prefer a symbol with non zero length */
a = symbol__end(syma) - symbol__start(syma);
b = symbol__end(symb) - symbol__start(symb);
@@ -224,6 +232,7 @@ void symbols__init(struct symbols *symbols)
symbols->num_by_name = 0;
symbols->sorted = true;
symbols->sorted_by_name = false;
+ atomic_init(&symbols->shrunk, false);
}
static void symbols__delete_locked(struct symbols *symbols)
@@ -238,6 +247,7 @@ static void symbols__delete_locked(struct symbols *symbols)
symbols->num_by_name = 0;
symbols->sorted = true;
symbols->sorted_by_name = false;
+ atomic_store_explicit(&symbols->shrunk, false, memory_order_release);
}
void symbols__delete(struct symbols *symbols)
@@ -253,6 +263,68 @@ void symbols__exit(struct symbols *symbols)
exit_rwsem(&symbols->lock);
}
+/**
+ * symbols__shrink - Evict unreferenced, unaccessed symbols using Clock LRU.
+ * @symbols: Symbol table to shrink.
+ *
+ * Scans @symbols in place:
+ * - Symbols with refcount > 1 (held by an external owner such as a hist_entry,
+ * callchain_cursor_node, or inline_list) are always retained.
+ * - Symbols with refcount == 1 that have SYMBOL_FLAG_ACCESSED set are given a
+ * second chance: their accessed bit is cleared and they remain in @symbols.
+ * - Symbols with refcount == 1 and SYMBOL_FLAG_ACCESSED clear are evicted and
+ * released via symbol__put().
+ *
+ * If any symbols are evicted, the secondary @symbols_by_name index is freed so
+ * it will be rebuilt lazily if needed, and the backing @symbols array is
+ * compacted when occupancy drops below 50%.
+ *
+ * Return: Number of symbols evicted and freed.
+ */
+size_t symbols__shrink(struct symbols *symbols)
+{
+ unsigned int write_idx = 0;
+ size_t freed = 0;
+
+ if (!symbols)
+ return 0;
+
+ down_write(&symbols->lock);
+ for (unsigned int read_idx = 0; read_idx < symbols->cnt; read_idx++) {
+ struct symbol *sym = symbols->symbols[read_idx];
+
+ if (refcount_read(symbol__refcnt(sym)) > 1 || symbol__accessed(sym)) {
+ symbol__set_accessed(sym, false);
+ symbols->symbols[write_idx++] = sym;
+ } else {
+ symbol__put(sym);
+ freed++;
+ }
+ }
+ if (freed > 0) {
+ symbols->cnt = write_idx;
+ zfree(&symbols->symbols_by_name);
+ symbols->num_by_name = 0;
+ symbols->sorted_by_name = false;
+ atomic_store_explicit(&symbols->shrunk, true, memory_order_release);
+ if (symbols->cnt == 0) {
+ zfree(&symbols->symbols);
+ symbols->allocated = 0;
+ } else if (symbols->cnt < symbols->allocated / 2 && symbols->allocated > 32) {
+ unsigned int new_alloc = max(symbols->cnt, 32U);
+ struct symbol **temp = realloc(symbols->symbols,
+ sizeof(struct symbol *) * new_alloc);
+
+ if (temp) {
+ symbols->symbols = temp;
+ symbols->allocated = new_alloc;
+ }
+ }
+ }
+ up_write(&symbols->lock);
+ return freed;
+}
+
static inline bool symbol__less_or_equal(const struct symbol *a, const struct symbol *b)
{
if (symbol__start(a) != symbol__start(b))
@@ -310,9 +382,6 @@ void symbols__fixup_duplicate(struct symbols *symbols)
{
unsigned int write_idx = 0;
- if (symbol_conf.allow_aliases)
- return;
-
down_write(&symbols->lock);
symbols__sort_locked(symbols);
if (symbols->cnt <= 1) {
@@ -329,6 +398,38 @@ void symbols__fixup_duplicate(struct symbols *symbols)
continue;
}
+ /*
+ * When aliases are allowed, distinct symbol names at the same
+ * address are kept, but identical (start, name) pairs (such as
+ * when reloading a shrunk DSO that still holds referenced
+ * symbols) are deduplicated using choose_best_symbol().
+ */
+ if (symbol_conf.allow_aliases) {
+ bool dup = false;
+
+ for (unsigned int k = write_idx; ; k--) {
+ struct symbol *existing = symbols->symbols[k];
+
+ if (symbol__start(existing) != symbol__start(next))
+ break;
+ if (!strcmp(symbol__name(existing), symbol__name(next))) {
+ if (choose_best_symbol(existing, next) == SYMBOL_A) {
+ symbol__put(next);
+ } else {
+ symbol__put(existing);
+ symbols->symbols[k] = next;
+ }
+ dup = true;
+ break;
+ }
+ if (k == 0)
+ break;
+ }
+ if (!dup)
+ symbols->symbols[++write_idx] = next;
+ continue;
+ }
+
if (choose_best_symbol(curr, next) == SYMBOL_A) {
if (symbol__type(next) == STT_GNU_IFUNC)
symbol__set_ifunc_alias(curr, true);
@@ -502,6 +603,14 @@ void symbol__set_annotated(struct symbol *sym, bool annotated)
atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_ANNOTATED);
}
+void symbol__set_accessed(struct symbol *sym, bool accessed)
+{
+ if (accessed)
+ atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_ACCESSED);
+ else
+ atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_ACCESSED);
+}
+
static void symbol__set_idle(struct symbol *sym, bool idle)
{
uint16_t old_flags = atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed);
@@ -576,6 +685,7 @@ static struct symbol *symbols__find(struct symbols *symbols, u64 ip)
low = mid + 1;
else {
res = symbol__get(s);
+ symbol__set_accessed(res, true);
break;
}
}
@@ -700,7 +810,11 @@ static struct symbol *symbols__find_by_name(struct symbol *symbols[],
}
}
assert(!found_idx || !s || s == symbols[*found_idx]);
- return symbol__get(s);
+ if (s) {
+ s = symbol__get(s);
+ symbol__set_accessed(s, true);
+ }
+ return s;
}
int dso__insert_symbol(struct dso *dso, struct symbol *sym)
@@ -732,11 +846,17 @@ void dso__delete_symbol(struct dso *dso, struct symbol *sym)
struct symbol *dso__find_symbol(struct dso *dso, u64 addr)
{
+ if (!dso)
+ return NULL;
+ dso__set_accessed(dso, true);
return symbols__find(dso__symbols(dso), addr);
}
struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr)
{
+ if (!dso)
+ return NULL;
+ dso__set_accessed(dso, true);
return symbols__find(dso__symbols(dso), addr);
}
@@ -763,6 +883,9 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name, size_
struct symbols *symbols;
struct symbol *s;
+ if (!dso)
+ return NULL;
+ dso__set_accessed(dso, true);
symbols = dso__symbols(dso);
down_read(&symbols->lock);
while (!symbols->sorted_by_name) {
@@ -1857,6 +1980,9 @@ static int dso__load_perf_map(const char *map_path, struct dso *dso)
free(line);
fclose(file);
+ if (nr_syms > 0)
+ symbols__fixup_duplicate(dso__symbols(dso));
+
return nr_syms;
out_delete_line:
@@ -1967,6 +2093,7 @@ int dso__load(struct dso *dso, struct map *map)
char newmapname[PATH_MAX];
const char *map_path = dso__long_name(dso);
+ dso__set_accessed(dso, true);
mutex_lock(dso__lock(dso));
perfmap = is_perf_pid_map_name(map_path);
@@ -1981,7 +2108,7 @@ int dso__load(struct dso *dso, struct map *map)
nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
/* check again under the dso->lock */
- if (dso__loaded(dso)) {
+ if (dso__loaded(dso) && !dso__symbols_shrunk(dso)) {
ret = 1;
goto out;
}
@@ -2140,8 +2267,10 @@ int dso__load(struct dso *dso, struct map *map)
int nr_plt;
nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss);
- if (nr_plt > 0)
+ if (nr_plt > 0) {
+ symbols__fixup_duplicate(dso__symbols(dso));
ret += nr_plt;
+ }
}
for (; ss_pos > 0; ss_pos--)
@@ -2151,6 +2280,7 @@ int dso__load(struct dso *dso, struct map *map)
if (ret < 0 && strstr(dso__name(dso), " (deleted)") != NULL)
ret = 0;
out:
+ dso__set_symbols_shrunk(dso, false);
dso__set_loaded(dso);
mutex_unlock(dso__lock(dso));
nsinfo__mountns_exit(&nsc);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index a3c88b5224ec..a76613c43ba9 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -91,21 +91,32 @@ enum symbol_idle_kind {
#define SYMBOL_FLAG_ANNOTATE2 (1 << 12)
#define SYMBOL_FLAG_IFUNC_ALIAS (1 << 13)
#define SYMBOL_FLAG_ANNOTATED (1 << 14)
+#define SYMBOL_FLAG_ACCESSED (1U << 15)
+
/**
- * A symtab entry.
+ * struct symbol - A symtab entry.
*/
DECLARE_RC_STRUCT(symbol) {
- /** Range of symbol [start, end). */
+ /** @start: Start address of symbol range [start, end). */
u64 start;
+ /** @end: End address (exclusive) of symbol range [start, end). */
u64 end;
- /** Reference count. */
+ /** @refcnt: Reference count tracking active holders of the symbol. */
refcount_t refcnt;
- /** Length of the string name. */
+ /** @namelen: Length of the string @name (excluding trailing NUL). */
u16 namelen;
+ /**
+ * @flags: Atomic bitfield of SYMBOL_FLAG_* values encoding symbol type,
+ * binding, idle classification, ignore/inlined/annotate/ifunc flags,
+ * and Clock LRU access state (SYMBOL_FLAG_ACCESSED).
+ */
_Atomic uint16_t flags;
- /** Architecture specific. Unused except on PPC where it holds st_other. */
+ /**
+ * @arch_sym: Architecture specific value. Unused except on PPC where it
+ * holds st_other.
+ */
u8 arch_sym;
- /** The name of length namelen associated with the symbol. */
+ /** @name: NUL-terminated symbol name of length @namelen. */
char name[];
};
@@ -138,6 +149,11 @@ struct symbols {
* by name.
*/
bool sorted_by_name;
+ /**
+ * @shrunk: Set under @lock when symbols__shrink() evicts one or more
+ * symbols so a subsequent lookup miss knows to reload the DSO on demand.
+ */
+ _Atomic bool shrunk;
};
void symbol__delete(struct symbol *sym);
@@ -145,6 +161,7 @@ void symbols__init(struct symbols *symbols);
void symbols__exit(struct symbols *symbols);
void symbols__delete(struct symbols *symbols);
void symbols__sort_read_lock(struct symbols *symbols) SHARED_LOCK_FUNCTION(symbols->lock);
+size_t symbols__shrink(struct symbols *symbols);
static inline refcount_t *symbol__refcnt(struct symbol *sym)
{
@@ -253,6 +270,12 @@ static inline bool symbol__annotated(const struct symbol *sym)
SYMBOL_FLAG_ANNOTATED) != 0;
}
+static inline bool symbol__accessed(const struct symbol *sym)
+{
+ return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
+ SYMBOL_FLAG_ACCESSED) != 0;
+}
+
bool symbol__is_idle(struct symbol *sym, const struct dso *dso, struct perf_env *env);
void symbol__set_ignore(struct symbol *sym, bool ignore);
@@ -260,6 +283,7 @@ void symbol__set_annotate2(struct symbol *sym, bool annotate2);
void symbol__set_inlined(struct symbol *sym, bool inlined);
void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias);
void symbol__set_annotated(struct symbol *sym, bool annotated);
+void symbol__set_accessed(struct symbol *sym, bool accessed);
/*
* symbols__for_each_entry - iterate over symbols calling @cb for each entry
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 6/7] perf session: Periodically shrink symbols and DSOs during event processing
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
` (4 preceding siblings ...)
2026-09-28 7:52 ` [PATCH v1 5/7] perf symbol: Add LRU memory shrinking for symbols, DSOs, and machines Ian Rogers
@ 2026-09-28 7:52 ` Ian Rogers
2026-09-28 7:52 ` [PATCH v1 7/7] perf test symbols: Add tests for symbol and DSO LRU shrinking Ian Rogers
2026-09-28 15:37 ` [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and " Ian Rogers
7 siblings, 0 replies; 9+ messages in thread
From: Ian Rogers @ 2026-09-28 7:52 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter, James Clark,
linux-perf-users, linux-kernel, Alireza Haghdoost
Add periodic calls to perf_session__shrink() so that both live profiling
and trace-processing commands reclaim unused symbol and DSO memory:
- In perf_session__deliver_event(), trigger perf_session__shrink()
every 16,384 events, or after at least 512 events when at least
65,536 new symbols have been inserted across DSOs (tracked via
symbols__inserted_cnt()). This bounds memory usage for session-based
commands such as 'perf script' and 'perf report' even on short traces
that load many large binaries, while giving hot symbols in newly
loaded DSOs a window to be marked SYMBOL_FLAG_ACCESSED.
- In perf_top__resort_hists(), call perf_session__shrink() on each
display refresh cycle so 'perf top' periodically ages out unused
symbols and DSOs.
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-top.c | 2 ++
tools/perf/util/session.c | 16 ++++++++++++++++
tools/perf/util/session.h | 10 ++++++++++
tools/perf/util/symbol.c | 15 +++++++++++++++
tools/perf/util/symbol.h | 1 +
5 files changed, 44 insertions(+)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index dd1e475bb4dd..c96530f33fe4 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -320,6 +320,8 @@ static void perf_top__resort_hists(struct perf_top *t)
evlist__for_each_entry(evlist, pos) {
evsel__output_resort(pos, NULL);
}
+
+ perf_session__shrink(t->session);
}
static void perf_top__print_sym_table(struct perf_top *top)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 555d940a866a..74a564c6589b 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -164,6 +164,7 @@ struct perf_session *__perf_session__new(struct perf_data *data,
session->tool = tool;
session->decomp_data.zstd_decomp = &session->zstd_data;
session->active_decomp = &session->decomp_data;
+ session->last_symbols_inserted = symbols__inserted_cnt();
INIT_LIST_HEAD(&session->auxtrace_index);
perf_env__init(&session->header.env);
if (machines__init(&session->machines, session))
@@ -2351,6 +2352,19 @@ static int perf_session__deliver_event(struct perf_session *session,
if (dump_trace && sample.aux_sample.size)
auxtrace__dump_auxtrace_sample(session, &sample);
+
+ /*
+ * Periodically reclaim unreferenced symbols, DSO caches, and cold DSOs
+ * during event processing (e.g., perf script, perf report). Trigger
+ * either every 16,384 events, or after at least 512 events when more
+ * than 65,536 symbols have been newly loaded across DSOs.
+ */
+ session->events_since_shrink++;
+ if (session->events_since_shrink >= 16384 ||
+ (session->events_since_shrink >= 512 &&
+ symbols__inserted_cnt() - session->last_symbols_inserted >= 65536)) {
+ perf_session__shrink(session);
+ }
out:
perf_sample__exit(&sample);
return ret;
@@ -3945,6 +3959,8 @@ size_t perf_session__shrink(struct perf_session *session)
if (!session)
return 0;
+ session->events_since_shrink = 0;
+ session->last_symbols_inserted = symbols__inserted_cnt();
return machines__shrink(&session->machines);
}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 4b223c2cee7f..030d5e931160 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -95,6 +95,16 @@ struct perf_session {
struct decomp_data decomp_data;
/** @active_decomp: Currently active decompression context. */
struct decomp_data *active_decomp;
+ /**
+ * @events_since_shrink: Number of events delivered via
+ * perf_session__deliver_event() since the last perf_session__shrink().
+ */
+ u64 events_since_shrink;
+ /**
+ * @last_symbols_inserted: Snapshot of symbols__inserted_cnt() taken at
+ * the last perf_session__shrink() pass.
+ */
+ unsigned long last_symbols_inserted;
};
struct decomp {
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 33cfd86156d2..57894c3dc5b5 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -623,6 +623,20 @@ static void symbol__set_idle(struct symbol *sym, bool idle)
} while (!atomic_compare_exchange_weak(&RC_CHK_ACCESS(sym)->flags, &old_flags, new_flags));
}
+static atomic_ulong symbols_inserted_cnt;
+
+/**
+ * symbols__inserted_cnt - Return cumulative count of symbols inserted.
+ *
+ * Monotonically increasing counter incremented each time a symbol is inserted
+ * into a struct symbols collection. Used by perf_session__deliver_event() to
+ * detect burst symbol loading across large DSOs and trigger periodic shrinking.
+ */
+unsigned long symbols__inserted_cnt(void)
+{
+ return atomic_load_explicit(&symbols_inserted_cnt, memory_order_relaxed);
+}
+
int __symbols__insert(struct symbols *symbols, struct symbol *sym)
{
if (symbols->cnt == symbols->allocated) {
@@ -644,6 +658,7 @@ int __symbols__insert(struct symbols *symbols, struct symbol *sym)
symbols->symbols[symbols->cnt++] = sym;
symbols->sorted_by_name = false;
+ atomic_fetch_add_explicit(&symbols_inserted_cnt, 1, memory_order_relaxed);
return 0;
}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index a76613c43ba9..783d9735aa3f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -162,6 +162,7 @@ void symbols__exit(struct symbols *symbols);
void symbols__delete(struct symbols *symbols);
void symbols__sort_read_lock(struct symbols *symbols) SHARED_LOCK_FUNCTION(symbols->lock);
size_t symbols__shrink(struct symbols *symbols);
+unsigned long symbols__inserted_cnt(void);
static inline refcount_t *symbol__refcnt(struct symbol *sym)
{
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v1 7/7] perf test symbols: Add tests for symbol and DSO LRU shrinking
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
` (5 preceding siblings ...)
2026-09-28 7:52 ` [PATCH v1 6/7] perf session: Periodically shrink symbols and DSOs during event processing Ian Rogers
@ 2026-09-28 7:52 ` Ian Rogers
2026-09-28 15:37 ` [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and " Ian Rogers
7 siblings, 0 replies; 9+ messages in thread
From: Ian Rogers @ 2026-09-28 7:52 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter, James Clark,
linux-perf-users, linux-kernel, Alireza Haghdoost
Add unit tests in tools/perf/tests/symbols.c covering:
- symbols__shrink(): Second-Chance / Clock eviction of unaccessed
symbols, clearing of SYMBOL_FLAG_ACCESSED on survival, and retention
of symbols with external reference counts (refcnt > 1).
- dsos__shrink(): Second-Chance / Clock eviction of cold DSOs from
struct dsos while retaining accessed DSOs and externally referenced
DSOs.
- dso__shrink() and map__find_symbol(): Shrinking a loaded DSO's symbol
table and verifying that a subsequent map__find_symbol() transparently
reloads the symbol table on demand.
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/symbols.c | 228 +++++++++++++++++++++++++++++++++++++
1 file changed, 228 insertions(+)
diff --git a/tools/perf/tests/symbols.c b/tools/perf/tests/symbols.c
index 440d800d9f4d..6113acbaf602 100644
--- a/tools/perf/tests/symbols.c
+++ b/tools/perf/tests/symbols.c
@@ -3,6 +3,8 @@
#include <linux/string.h>
#include <sys/mman.h>
#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
#include "debug.h"
#include "dso.h"
#include "env.h"
@@ -178,6 +180,221 @@ static int process_subdivided_dso(struct machine *machine, struct dso *dso)
return ret < 0 ? TEST_FAIL : TEST_OK;
}
+static int test_symbols_shrink(void)
+{
+ struct symbols symbols;
+ struct symbol *sym1, *sym2, *sym3, *held;
+ int ret = TEST_FAIL;
+
+ symbols__init(&symbols);
+
+ sym1 = symbol__new(0x100, 0x50, STB_GLOBAL, STT_FUNC, "sym1");
+ sym2 = symbol__new(0x200, 0x50, STB_GLOBAL, STT_FUNC, "sym2");
+ sym3 = symbol__new(0x300, 0x50, STB_GLOBAL, STT_FUNC, "sym3");
+ if (!sym1 || !sym2 || !sym3) {
+ symbol__put(sym1);
+ symbol__put(sym2);
+ symbol__put(sym3);
+ goto out;
+ }
+
+ /* Hold an active reference on sym1, and mark sym2 accessed. */
+ held = symbol__get(sym1);
+ symbol__set_accessed(sym2, true);
+
+ symbols__insert(&symbols, sym1);
+ symbols__insert(&symbols, sym2);
+ symbols__insert(&symbols, sym3);
+
+ /*
+ * First shrink: sym3 (unreferenced) is evicted; sym2 gets a second
+ * chance because SYMBOL_FLAG_ACCESSED was set; sym1 has refcnt > 1.
+ */
+ if (symbols__shrink(&symbols) != 1 || symbols.cnt != 2) {
+ pr_debug("First symbols__shrink failed (cnt=%u)!\n", symbols.cnt);
+ symbol__put(held);
+ goto out;
+ }
+
+ /*
+ * Second shrink: sym2 was not accessed since first shrink, so it is now
+ * evicted; sym1 still has refcnt > 1.
+ */
+ if (symbols__shrink(&symbols) != 1 || symbols.cnt != 1) {
+ pr_debug("Second symbols__shrink failed (cnt=%u)!\n", symbols.cnt);
+ symbol__put(held);
+ goto out;
+ }
+
+ symbol__set_accessed(held, false);
+ symbol__put(held);
+ if (symbols__shrink(&symbols) != 1 || symbols.cnt != 0) {
+ pr_debug("Third symbols__shrink failed (cnt=%u)!\n", symbols.cnt);
+ goto out;
+ }
+
+ ret = TEST_OK;
+out:
+ symbols__exit(&symbols);
+ return ret;
+}
+
+static int test_dsos_shrink(void)
+{
+ struct dsos dsos;
+ struct dso *dso1, *dso2;
+ int ret = TEST_FAIL;
+
+ dsos__init(&dsos);
+
+ dso1 = dsos__findnew_id(&dsos, "/tmp/perf_test_dso1", NULL);
+ dso2 = dsos__findnew_id(&dsos, "/tmp/perf_test_dso2", NULL);
+ if (!dso1 || !dso2) {
+ dso__put(dso1);
+ dso__put(dso2);
+ goto out;
+ }
+
+ /* Keep the caller's active reference on dso1; drop caller reference on dso2. */
+ dso__put(dso2);
+
+ /*
+ * First shrink: both DSOs had accessed=true from creation, so neither
+ * is evicted on the first pass (Clock second chance), and accessed is
+ * cleared.
+ */
+ if (dsos__shrink(&dsos) != 0 || dsos.cnt != 2) {
+ pr_debug("First dsos__shrink failed (cnt=%u)!\n", dsos.cnt);
+ dso__put(dso1);
+ goto out;
+ }
+
+ /*
+ * Second shrink: dso2 has refcnt == 1 and accessed == false, so it is
+ * evicted; dso1 has refcnt == 2, so it is kept.
+ */
+ if (dsos__shrink(&dsos) != 1 || dsos.cnt != 1) {
+ pr_debug("Second dsos__shrink failed (cnt=%u)!\n", dsos.cnt);
+ dso__put(dso1);
+ goto out;
+ }
+
+ dso__put(dso1);
+ if (dsos__shrink(&dsos) != 1 || dsos.cnt != 0) {
+ pr_debug("Third dsos__shrink failed (cnt=%u)!\n", dsos.cnt);
+ goto out;
+ }
+
+ ret = TEST_OK;
+out:
+ dsos__exit(&dsos);
+ return ret;
+}
+
+struct shrink_reload_find_args {
+ struct symbol *kept;
+ u64 first_start;
+ u64 second_start;
+ char *second_name;
+};
+
+static int shrink_reload_find_cb(struct symbol *sym, void *data)
+{
+ struct shrink_reload_find_args *args = data;
+
+ if (!args->kept) {
+ args->kept = symbol__get(sym);
+ args->first_start = symbol__start(sym);
+ return 0;
+ }
+ if (symbol__start(sym) != args->first_start) {
+ args->second_start = symbol__start(sym);
+ args->second_name = strdup(symbol__name(sym));
+ return args->second_name ? 1 : -ENOMEM;
+ }
+ return 0;
+}
+
+static int test_dso_shrink_and_reload(struct dso *dso, struct map *map)
+{
+ struct shrink_reload_find_args args = {
+ .kept = NULL,
+ .first_start = 0,
+ .second_start = 0,
+ .second_name = NULL,
+ };
+ struct symbol *sym, *reloaded;
+ size_t removed;
+
+ if (!dso__can_shrink_symbols(dso) || dso__kernel(dso))
+ return TEST_OK;
+
+ if (dso__for_each_symbol(dso, shrink_reload_find_cb, &args) < 0) {
+ symbol__put(args.kept);
+ return TEST_FAIL;
+ }
+ if (!args.second_name) {
+ symbol__put(args.kept);
+ return TEST_OK;
+ }
+
+ /* Unreferenced symbols have SYMBOL_FLAG_ACCESSED == false and are evicted immediately. */
+ removed = dso__shrink(dso);
+ if (removed == 0 || !dso__symbols_shrunk(dso)) {
+ pr_debug("dso__shrink did not evict any symbols!\n");
+ free(args.second_name);
+ symbol__put(args.kept);
+ return TEST_FAIL;
+ }
+
+ /* Kept symbol is still found without reloading. */
+ sym = dso__find_symbol(dso, args.first_start);
+ if (!RC_CHK_EQUAL(sym, args.kept)) {
+ pr_debug("Kept symbol not found after dso__shrink!\n");
+ symbol__put(sym);
+ free(args.second_name);
+ symbol__put(args.kept);
+ return TEST_FAIL;
+ }
+ symbol__put(sym);
+
+ /* Evicted symbol is no longer in dso->symbols before reload. */
+ sym = dso__find_symbol(dso, args.second_start);
+ if (sym != NULL) {
+ pr_debug("Evicted symbol still present after dso__shrink!\n");
+ symbol__put(sym);
+ free(args.second_name);
+ symbol__put(args.kept);
+ return TEST_FAIL;
+ }
+
+ /* Lookup via map__find_symbol transparently reloads the DSO. */
+ reloaded = map__find_symbol(map, args.second_start);
+ if (!reloaded || strcmp(symbol__name(reloaded), args.second_name) != 0) {
+ pr_debug("Failed to reload evicted symbol %s!\n", args.second_name);
+ symbol__put(reloaded);
+ free(args.second_name);
+ symbol__put(args.kept);
+ return TEST_FAIL;
+ }
+ symbol__put(reloaded);
+
+ /* Kept symbol pointer was preserved across reload deduplication. */
+ sym = dso__find_symbol(dso, args.first_start);
+ if (!RC_CHK_EQUAL(sym, args.kept)) {
+ pr_debug("Kept symbol pointer was not preserved across reload!\n");
+ symbol__put(sym);
+ free(args.second_name);
+ symbol__put(args.kept);
+ return TEST_FAIL;
+ }
+ symbol__put(sym);
+
+ free(args.second_name);
+ symbol__put(args.kept);
+ return TEST_OK;
+}
+
static int test_file(struct test_info *ti, char *filename)
{
struct map *map = NULL;
@@ -209,6 +426,9 @@ static int test_file(struct test_info *ti, char *filename)
/* Module dso is split into many dsos by section */
if (ret == TEST_OK && dso__kernel(dso) != DSO_SPACE__USER)
ret = process_subdivided_dso(ti->machine, dso);
+
+ if (ret == TEST_OK)
+ ret = test_dso_shrink_and_reload(dso, map);
out_put:
map__put(map);
@@ -221,6 +441,14 @@ static int test__symbols(struct test_suite *test __maybe_unused, int subtest __m
struct test_info ti;
int ret;
+ ret = test_symbols_shrink();
+ if (ret != TEST_OK)
+ return ret;
+
+ ret = test_dsos_shrink();
+ if (ret != TEST_OK)
+ return ret;
+
ret = init_test_info(&ti);
if (ret != TEST_OK)
return ret;
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
` (6 preceding siblings ...)
2026-09-28 7:52 ` [PATCH v1 7/7] perf test symbols: Add tests for symbol and DSO LRU shrinking Ian Rogers
@ 2026-09-28 15:37 ` Ian Rogers
7 siblings, 0 replies; 9+ messages in thread
From: Ian Rogers @ 2026-09-28 15:37 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Adrian Hunter, James Clark,
linux-perf-users, linux-kernel, Alireza Haghdoost
On Mon, Sep 28, 2026 at 12:52 AM Ian Rogers <irogers@google.com> wrote:
>
> This series modernizes struct symbol memory management and backing storage in
> tools/perf to support reference counting (DECLARE_RC_STRUCT(symbol)) and
> periodic LRU memory shrinking during long or large profiling sessions:
>
> 1. Field accessors (Patch 1): Introduces inline getters/setters for
> struct symbol fields across tools/perf in preparation for wrapping
> struct symbol with DECLARE_RC_STRUCT(symbol).
> 2. Remove negative-offset private allocations (Patch 2): Replaces
> symbol_conf.priv_size and symbol__priv() negative-offset allocations in
> util/annotate.c and util/db-export.c with hashmaps keyed by symbol
> pointer (struct annotated_symbol protected by an rw_semaphore, and
> sym_db_ids on struct db_export).
> 3. Flat sorted array backing storage (Patch 3): Replaces the dual
> address-sorted and name-sorted red-black trees (rb_node) in struct dso
> with a struct symbols container backed by dynamically sorted flat arrays
> protected by struct rw_semaphore (util/rwsem.h) with Clang thread-safety
> annotations. Saves 48 bytes per struct symbol (two rb_nodes) and provides
> cache-friendly binary search (bsearch) and callback-based iteration.
> 4. Reference counting and DECLARE_RC_STRUCT(symbol) (Patch 4): Wraps
> struct symbol with DECLARE_RC_STRUCT(symbol) and adds refcount_t refcnt
> along with symbol__get(), symbol__put(), and symbol__zput(). Lookup
> functions return a counted reference acquired under symbols->lock, and
> lifetime holders (addr_location, map_symbol, hist_entry, call_path,
> block_info, disasm_line, thread_stack, db_export, etc.) properly
> manage symbol references.
> 5. LRU memory shrinking (Patch 5): Adds an accessed bit to struct dso
> and implements symbols__shrink(), dso__shrink_symbols(), dsos__shrink(),
> machine__shrink(), and machines__shrink(). Unreferenced symbols (refcnt == 1)
> in cold DSOs are reclaimed, and shrunken DSOs transparently reload on demand
> via dso__load() while preserving live symbols and their RC_STRUCT(symbol)
> identity.
> 6. Periodic session shrinking (Patch 6): Hooks machines__shrink() into
> perf_session event processing so long-running sessions periodically reclaim
> cold symbols and DSOs.
> 7. Unit tests (Patch 7): Adds unit tests in tools/perf/tests/symbols.c
> covering symbol reference counting, symbols__shrink() retention of active
> symbols, dsos__shrink() two-pass LRU clock behavior, and on-demand reload
> preserving live symbol identity.
This needs a rebase to after the changes to the python integration,
hence no Sashiko reviews. I'll do that asap.
Thanks,
Ian
> Ian Rogers (7):
> perf symbol: Add accessor functions for struct symbol fields
> perf symbol: Remove symbol_conf.priv_size and negative-offset
> allocations
> perf symbol: Switch backing storage from rbtree to struct symbols
> array
> perf symbol: Add reference counting and DECLARE_RC_STRUCT(symbol)
> perf symbol: Add LRU memory shrinking for symbols, DSOs, and machines
> perf session: Periodically shrink symbols and DSOs during event
> processing
> perf test symbols: Add tests for symbol and DSO LRU shrinking
>
> .../arch/powerpc/util/skip-callchain-idx.c | 2 +-
> tools/perf/arch/powerpc/util/sym-handling.c | 40 +-
> tools/perf/builtin-annotate.c | 15 +-
> tools/perf/builtin-c2c.c | 14 -
> tools/perf/builtin-diff.c | 5 +-
> tools/perf/builtin-kallsyms.c | 10 +-
> tools/perf/builtin-kmem.c | 66 +-
> tools/perf/builtin-kwork.c | 4 +-
> tools/perf/builtin-lock.c | 27 +-
> tools/perf/builtin-mem.c | 2 +-
> tools/perf/builtin-report.c | 14 -
> tools/perf/builtin-sched.c | 6 +-
> tools/perf/builtin-script.c | 18 +-
> tools/perf/builtin-timechart.c | 2 +-
> tools/perf/builtin-top.c | 29 +-
> tools/perf/builtin-trace.c | 12 +-
> tools/perf/tests/builtin-test.c | 1 -
> tools/perf/tests/dlfilter-test.c | 12 +-
> tools/perf/tests/dwarf-unwind.c | 2 +-
> tools/perf/tests/hists_common.c | 4 +-
> tools/perf/tests/hists_cumulate.c | 8 +-
> tools/perf/tests/hists_filter.c | 10 +-
> tools/perf/tests/hists_link.c | 16 +-
> tools/perf/tests/hists_output.c | 9 +-
> tools/perf/tests/kallsyms-split.c | 5 +-
> tools/perf/tests/pe-file-parsing.c | 1 +
> tools/perf/tests/symbols.c | 289 +++++-
> tools/perf/tests/vmlinux-kallsyms.c | 191 ++--
> tools/perf/ui/browsers/annotate.c | 11 +-
> tools/perf/ui/browsers/hists.c | 17 +-
> tools/perf/ui/browsers/map.c | 87 +-
> tools/perf/ui/gtk/annotate.c | 7 +-
> tools/perf/ui/stdio/hist.c | 6 +-
> tools/perf/util/addr_location.c | 4 +
> .../perf/util/annotate-arch/annotate-alpha.c | 2 +-
> .../util/annotate-arch/annotate-loongarch.c | 8 +-
> tools/perf/util/annotate-arch/annotate-s390.c | 2 +-
> tools/perf/util/annotate-arch/annotate-x86.c | 14 +-
> tools/perf/util/annotate-data.c | 14 +-
> tools/perf/util/annotate.c | 211 ++++-
> tools/perf/util/annotate.h | 6 +-
> tools/perf/util/auxtrace.c | 111 ++-
> tools/perf/util/block-info.c | 13 +-
> tools/perf/util/bpf_lock_contention.c | 39 +-
> tools/perf/util/c2c-function.c | 25 +-
> tools/perf/util/call-path.c | 15 +-
> tools/perf/util/callchain.c | 19 +-
> tools/perf/util/capstone.c | 21 +-
> tools/perf/util/data-convert-json.c | 4 +-
> tools/perf/util/db-export.c | 76 +-
> tools/perf/util/db-export.h | 6 +
> tools/perf/util/debug.c | 3 +-
> tools/perf/util/disasm.c | 57 +-
> tools/perf/util/dlfilter.c | 12 +-
> tools/perf/util/dso.c | 236 +++--
> tools/perf/util/dso.h | 85 +-
> tools/perf/util/dsos.c | 100 +++
> tools/perf/util/dsos.h | 12 +-
> tools/perf/util/event.c | 12 +-
> tools/perf/util/evsel_fprintf.c | 2 +-
> tools/perf/util/hist.c | 30 +-
> tools/perf/util/intel-pt.c | 74 +-
> tools/perf/util/libbfd.c | 5 +-
> tools/perf/util/libdw.c | 5 +-
> tools/perf/util/llvm.c | 6 +-
> tools/perf/util/lock-contention.c | 8 +-
> tools/perf/util/machine.c | 143 ++-
> tools/perf/util/machine.h | 2 +
> tools/perf/util/map.c | 53 +-
> tools/perf/util/map.h | 18 +-
> tools/perf/util/map_symbol.c | 4 +-
> tools/perf/util/maps.c | 3 +-
> tools/perf/util/probe-event.c | 135 +--
> tools/perf/util/python.c | 20 +-
> .../util/scripting-engines/trace-event-perl.c | 8 +-
> .../scripting-engines/trace-event-python.c | 38 +-
> tools/perf/util/session.c | 31 +
> tools/perf/util/session.h | 13 +
> tools/perf/util/sort.c | 44 +-
> tools/perf/util/srcline.c | 19 +-
> tools/perf/util/symbol-elf.c | 22 +-
> tools/perf/util/symbol.c | 845 ++++++++++++------
> tools/perf/util/symbol.h | 203 ++++-
> tools/perf/util/symbol_conf.h | 1 -
> tools/perf/util/symbol_fprintf.c | 14 +-
> tools/perf/util/thread-stack.c | 18 +-
> tools/perf/util/threads.c | 17 +-
> tools/perf/util/unwind-libdw.c | 4 +-
> tools/perf/util/unwind-libunwind.c | 2 +-
> 89 files changed, 2644 insertions(+), 1192 deletions(-)
>
> --
> 2.56.0.rc1.315.gc6ed9934b7-goog
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-09-28 15:38 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-28 7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
2026-09-28 7:52 ` [PATCH v1 1/7] perf symbol: Add accessor functions for struct symbol fields Ian Rogers
2026-09-28 7:52 ` [PATCH v1 2/7] perf symbol: Remove symbol_conf.priv_size and negative-offset allocations Ian Rogers
2026-09-28 7:52 ` [PATCH v1 3/7] perf symbol: Switch backing storage from rbtree to struct symbols array Ian Rogers
2026-09-28 7:52 ` [PATCH v1 4/7] perf symbol: Add reference counting and DECLARE_RC_STRUCT(symbol) Ian Rogers
2026-09-28 7:52 ` [PATCH v1 5/7] perf symbol: Add LRU memory shrinking for symbols, DSOs, and machines Ian Rogers
2026-09-28 7:52 ` [PATCH v1 6/7] perf session: Periodically shrink symbols and DSOs during event processing Ian Rogers
2026-09-28 7:52 ` [PATCH v1 7/7] perf test symbols: Add tests for symbol and DSO LRU shrinking Ian Rogers
2026-09-28 15:37 ` [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and " Ian Rogers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®