mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
The unwind-libdw dwfl has ELF binaries associated with mmap addresses. Experimenting with using the per dso dwfl it is required to alter the address to be 0 based variant. Unfortunately libdwfl doesn't allow a single unwind and then an update to the return address to be 0 based as there are assertions that registers aren't updated once an unwind has started, etc. As removing the dwfl didn't prove possible, an alternative is to just not discard the dwfl when the unwind ends. The dwfl is valid for a process unless a dso is loaded at the same address as a previous one. So keep the dwfl with the maps, invalidate it if a map is removed (in case a new map replaces it) and recycle the dwfl in the unwinding code. A wrinkly in the implementation of this is that the attached thread argument is remembered by the dwfl and so it needs to be a pointer to memory that also persists with the dwfl (struct dwfl_ui_thread_info in the code). Recording 10 seconds of system wide data with --call-graph=dwarf and then processing with perf report shows a total runtime improvement from 41.583s to 2.279s (an 18x speedup). Signed-off-by: Ian Rogers <irogers@google.com> Cc: Aditya Bodkhe <aditya.b1@linux.ibm.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Albert Ou <aou@eecs.berkeley.edu> Cc: Alexandre Ghiti <alex@ghiti.fr> Cc: Andi Kleen <ak@linux.intel.com> Cc: Athira Rajeev <atrajeev@linux.ibm.com> Cc: Chun-Tse Shao <ctshao@google.com> Cc: Dmitriy Vyukov <dvyukov@google.com> Cc: Dr. David Alan Gilbert <linux@treblig.org> Cc: Guo Ren <guoren@kernel.org> Cc: Haibo Xu <haibo1.xu@intel.com> Cc: Howard Chu <howardchu95@gmail.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: John Garry <john.g.garry@oracle.com> Cc: Krzysztof Łopatowski <krzysztof.m.lopatowski@gmail.com> Cc: Leo Yan <leo.yan@linux.dev> Cc: Mark Wielaard <mark@klomp.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Palmer Dabbelt <palmer@dabbelt.com> Cc: Paul Walmsley <pjw@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Sergei Trofimovich <slyich@gmail.com> Cc: Shimin Guo <shimin.guo@skydio.com> Cc: Stephen Brennan <stephen.s.brennan@oracle.com> Cc: Thomas Falcon <thomas.falcon@intel.com> Cc: Will Deacon <will@kernel.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
86 lines
2.6 KiB
C
86 lines
2.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __PERF_MAPS_H
|
|
#define __PERF_MAPS_H
|
|
|
|
#include <linux/refcount.h>
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <linux/types.h>
|
|
|
|
struct ref_reloc_sym;
|
|
struct machine;
|
|
struct map;
|
|
struct maps;
|
|
|
|
#define KMAP_NAME_LEN 256
|
|
|
|
struct kmap {
|
|
struct ref_reloc_sym *ref_reloc_sym;
|
|
struct maps *kmaps;
|
|
char name[KMAP_NAME_LEN];
|
|
};
|
|
|
|
struct maps *maps__new(struct machine *machine);
|
|
bool maps__empty(struct maps *maps);
|
|
int maps__copy_from(struct maps *maps, struct maps *parent);
|
|
|
|
struct maps *maps__get(struct maps *maps);
|
|
void maps__put(struct maps *maps);
|
|
|
|
static inline void __maps__zput(struct maps **map)
|
|
{
|
|
maps__put(*map);
|
|
*map = NULL;
|
|
}
|
|
|
|
#define maps__zput(map) __maps__zput(&map)
|
|
|
|
bool maps__equal(struct maps *a, struct maps *b);
|
|
|
|
/* Iterate over map calling cb for each entry. */
|
|
int maps__for_each_map(struct maps *maps, int (*cb)(struct map *map, void *data), void *data);
|
|
/* Iterate over map removing an entry if cb returns true. */
|
|
void maps__remove_maps(struct maps *maps, bool (*cb)(struct map *map, void *data), void *data);
|
|
|
|
struct machine *maps__machine(const struct maps *maps);
|
|
unsigned int maps__nr_maps(const struct maps *maps); /* Test only. */
|
|
refcount_t *maps__refcnt(struct maps *maps); /* Test only. */
|
|
|
|
#ifdef HAVE_LIBUNWIND_SUPPORT
|
|
void *maps__addr_space(const struct maps *maps);
|
|
void maps__set_addr_space(struct maps *maps, void *addr_space);
|
|
const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct maps *maps);
|
|
void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind_libunwind_ops *ops);
|
|
#endif
|
|
#ifdef HAVE_LIBDW_SUPPORT
|
|
void *maps__libdw_addr_space_dwfl(const struct maps *maps);
|
|
void maps__set_libdw_addr_space_dwfl(struct maps *maps, void *dwfl);
|
|
#endif
|
|
|
|
size_t maps__fprintf(struct maps *maps, FILE *fp);
|
|
|
|
int maps__insert(struct maps *maps, struct map *map);
|
|
void maps__remove(struct maps *maps, struct map *map);
|
|
|
|
struct map *maps__find(struct maps *maps, u64 addr);
|
|
struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp);
|
|
struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp);
|
|
|
|
struct addr_map_symbol;
|
|
|
|
int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams);
|
|
|
|
int maps__fixup_overlap_and_insert(struct maps *maps, struct map *new);
|
|
|
|
struct map *maps__find_by_name(struct maps *maps, const char *name);
|
|
|
|
struct map *maps__find_next_entry(struct maps *maps, struct map *map);
|
|
|
|
int maps__merge_in(struct maps *kmaps, struct map *new_map);
|
|
|
|
void maps__fixup_end(struct maps *maps);
|
|
|
|
void maps__load_first(struct maps *maps);
|
|
|
|
#endif // __PERF_MAPS_H
|