Commit 259dce91 authored by Ian Rogers's avatar Ian Rogers Committed by Namhyung Kim

perf symbol: Remove symbol_name_rb_node

Most perf commands want to sort symbols by name and this is done via
an invasive rbtree that on 64-bit systems costs 24 bytes. Sorting the
symbols in a DSO by name is optional and not done by default, however,
if sorting is requested the 24 bytes is allocated for every
symbol.

This change removes the rbtree and uses a sorted array of symbol
pointers instead (costing 8 bytes per symbol). As the array is created
on demand then there are further memory savings. The complexity of
sorting the array and using the rbtree are the same.

To support going to the next symbol, the index of the current symbol
needs to be passed around as a pair with the current symbol. This
requires some API changes.
Signed-off-by: default avatarIan Rogers <irogers@google.com>
Acked-by: default avatarNamhyung Kim <namhyung@kernel.org>
Cc: Carsten Haitzler <carsten.haitzler@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Jason Wang <wangborong@cdjrlc.com>
Cc: Changbin Du <changbin.du@huawei.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Link: https://lore.kernel.org/r/20230623054520.4118442-3-irogers@google.com
[ minimize change in symbols__sort_by_name() ]
Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
parent ce5b2934
...@@ -1320,7 +1320,9 @@ struct dso *dso__new_id(const char *name, struct dso_id *id) ...@@ -1320,7 +1320,9 @@ struct dso *dso__new_id(const char *name, struct dso_id *id)
dso->id = *id; dso->id = *id;
dso__set_long_name_id(dso, dso->name, id, false); dso__set_long_name_id(dso, dso->name, id, false);
dso__set_short_name(dso, dso->name, false); dso__set_short_name(dso, dso->name, false);
dso->symbols = dso->symbol_names = RB_ROOT_CACHED; dso->symbols = RB_ROOT_CACHED;
dso->symbol_names = NULL;
dso->symbol_names_len = 0;
dso->data.cache = RB_ROOT; dso->data.cache = RB_ROOT;
dso->inlined_nodes = RB_ROOT_CACHED; dso->inlined_nodes = RB_ROOT_CACHED;
dso->srclines = RB_ROOT_CACHED; dso->srclines = RB_ROOT_CACHED;
...@@ -1364,7 +1366,8 @@ void dso__delete(struct dso *dso) ...@@ -1364,7 +1366,8 @@ void dso__delete(struct dso *dso)
inlines__tree_delete(&dso->inlined_nodes); inlines__tree_delete(&dso->inlined_nodes);
srcline__tree_delete(&dso->srclines); srcline__tree_delete(&dso->srclines);
symbols__delete(&dso->symbols); symbols__delete(&dso->symbols);
dso->symbol_names_len = 0;
zfree(&dso->symbol_names);
if (dso->short_name_allocated) { if (dso->short_name_allocated) {
zfree((char **)&dso->short_name); zfree((char **)&dso->short_name);
dso->short_name_allocated = false; dso->short_name_allocated = false;
......
...@@ -150,7 +150,8 @@ struct dso { ...@@ -150,7 +150,8 @@ struct dso {
struct rb_node rb_node; /* rbtree node sorted by long name */ struct rb_node rb_node; /* rbtree node sorted by long name */
struct rb_root *root; /* root of rbtree that rb_node is in */ struct rb_root *root; /* root of rbtree that rb_node is in */
struct rb_root_cached symbols; struct rb_root_cached symbols;
struct rb_root_cached symbol_names; struct symbol **symbol_names;
size_t symbol_names_len;
struct rb_root_cached inlined_nodes; struct rb_root_cached inlined_nodes;
struct rb_root_cached srclines; struct rb_root_cached srclines;
struct { struct {
......
...@@ -390,7 +390,7 @@ struct symbol *map__find_symbol(struct map *map, u64 addr) ...@@ -390,7 +390,7 @@ struct symbol *map__find_symbol(struct map *map, u64 addr)
return dso__find_symbol(map__dso(map), addr); return dso__find_symbol(map__dso(map), addr);
} }
struct symbol *map__find_symbol_by_name(struct map *map, const char *name) struct symbol *map__find_symbol_by_name_idx(struct map *map, const char *name, size_t *idx)
{ {
struct dso *dso; struct dso *dso;
...@@ -400,7 +400,14 @@ struct symbol *map__find_symbol_by_name(struct map *map, const char *name) ...@@ -400,7 +400,14 @@ struct symbol *map__find_symbol_by_name(struct map *map, const char *name)
dso = map__dso(map); dso = map__dso(map);
dso__sort_by_name(dso); dso__sort_by_name(dso);
return dso__find_symbol_by_name(dso, name); return dso__find_symbol_by_name(dso, name, idx);
}
struct symbol *map__find_symbol_by_name(struct map *map, const char *name)
{
size_t idx;
return map__find_symbol_by_name_idx(map, name, &idx);
} }
struct map *map__clone(struct map *from) struct map *map__clone(struct map *from)
......
...@@ -148,16 +148,17 @@ struct thread; ...@@ -148,16 +148,17 @@ struct thread;
* @map: the 'struct map *' in which symbols are iterated * @map: the 'struct map *' in which symbols are iterated
* @sym_name: the symbol name * @sym_name: the symbol name
* @pos: the 'struct symbol *' to use as a loop cursor * @pos: the 'struct symbol *' to use as a loop cursor
* @idx: the cursor index in the symbol names array
*/ */
#define __map__for_each_symbol_by_name(map, sym_name, pos) \ #define __map__for_each_symbol_by_name(map, sym_name, pos, idx) \
for (pos = map__find_symbol_by_name(map, sym_name); \ for (pos = map__find_symbol_by_name_idx(map, sym_name, &idx); \
pos && \ pos && \
!symbol__match_symbol_name(pos->name, sym_name, \ !symbol__match_symbol_name(pos->name, sym_name, \
SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); \ SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); \
pos = symbol__next_by_name(pos)) pos = dso__next_symbol_by_name(map__dso(map), &idx))
#define map__for_each_symbol_by_name(map, sym_name, pos) \ #define map__for_each_symbol_by_name(map, sym_name, pos, idx) \
__map__for_each_symbol_by_name(map, sym_name, (pos)) __map__for_each_symbol_by_name(map, sym_name, (pos), idx)
void map__init(struct map *map, void map__init(struct map *map,
u64 start, u64 end, u64 pgoff, struct dso *dso); u64 start, u64 end, u64 pgoff, struct dso *dso);
...@@ -202,6 +203,7 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, ...@@ -202,6 +203,7 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
int map__load(struct map *map); int map__load(struct map *map);
struct symbol *map__find_symbol(struct map *map, u64 addr); struct symbol *map__find_symbol(struct map *map, u64 addr);
struct symbol *map__find_symbol_by_name(struct map *map, const char *name); struct symbol *map__find_symbol_by_name(struct map *map, const char *name);
struct symbol *map__find_symbol_by_name_idx(struct map *map, const char *name, size_t *idx);
void map__fixup_start(struct map *map); void map__fixup_start(struct map *map);
void map__fixup_end(struct map *map); void map__fixup_end(struct map *map);
......
...@@ -382,6 +382,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo, ...@@ -382,6 +382,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
struct symbol *sym; struct symbol *sym;
u64 address = 0; u64 address = 0;
int ret = -ENOENT; int ret = -ENOENT;
size_t idx;
/* This can work only for function-name based one */ /* This can work only for function-name based one */
if (!pp->function || pp->file) if (!pp->function || pp->file)
...@@ -392,7 +393,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo, ...@@ -392,7 +393,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
return -EINVAL; return -EINVAL;
/* Find the address of given function */ /* Find the address of given function */
map__for_each_symbol_by_name(map, pp->function, sym) { map__for_each_symbol_by_name(map, pp->function, sym, idx) {
if (uprobes) { if (uprobes) {
address = sym->start; address = sym->start;
if (sym->type == STT_GNU_IFUNC) if (sym->type == STT_GNU_IFUNC)
...@@ -3738,7 +3739,6 @@ int del_perf_probe_events(struct strfilter *filter) ...@@ -3738,7 +3739,6 @@ int del_perf_probe_events(struct strfilter *filter)
int show_available_funcs(const char *target, struct nsinfo *nsi, int show_available_funcs(const char *target, struct nsinfo *nsi,
struct strfilter *_filter, bool user) struct strfilter *_filter, bool user)
{ {
struct rb_node *nd;
struct map *map; struct map *map;
struct dso *dso; struct dso *dso;
int ret; int ret;
...@@ -3772,11 +3772,11 @@ int show_available_funcs(const char *target, struct nsinfo *nsi, ...@@ -3772,11 +3772,11 @@ int show_available_funcs(const char *target, struct nsinfo *nsi,
/* Show all (filtered) symbols */ /* Show all (filtered) symbols */
setup_pager(); setup_pager();
for (nd = rb_first_cached(&dso->symbol_names); nd; nd = rb_next(nd)) { for (size_t i = 0; i < dso->symbol_names_len; i++) {
struct symbol_name_rb_node *pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); struct symbol *pos = dso->symbol_names[i];
if (strfilter__compare(_filter, pos->sym.name)) if (strfilter__compare(_filter, pos->name))
printf("%s\n", pos->sym.name); printf("%s\n", pos->name);
} }
end: end:
map__put(map); map__put(map);
......
...@@ -440,38 +440,35 @@ static struct symbol *symbols__next(struct symbol *sym) ...@@ -440,38 +440,35 @@ static struct symbol *symbols__next(struct symbol *sym)
return NULL; return NULL;
} }
static void symbols__insert_by_name(struct rb_root_cached *symbols, struct symbol *sym) static int symbols__sort_name_cmp(const void *vlhs, const void *vrhs)
{ {
struct rb_node **p = &symbols->rb_root.rb_node; const struct symbol *lhs = *((const struct symbol **)vlhs);
struct rb_node *parent = NULL; const struct symbol *rhs = *((const struct symbol **)vrhs);
struct symbol_name_rb_node *symn, *s;
bool leftmost = true;
symn = container_of(sym, struct symbol_name_rb_node, sym); return strcmp(lhs->name, rhs->name);
while (*p != NULL) {
parent = *p;
s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
if (strcmp(sym->name, s->sym.name) < 0)
p = &(*p)->rb_left;
else {
p = &(*p)->rb_right;
leftmost = false;
}
}
rb_link_node(&symn->rb_node, parent, p);
rb_insert_color_cached(&symn->rb_node, symbols, leftmost);
} }
static void symbols__sort_by_name(struct rb_root_cached *symbols, static struct symbol **symbols__sort_by_name(struct rb_root_cached *source, size_t *len)
struct rb_root_cached *source)
{ {
struct rb_node *nd; struct rb_node *nd;
struct symbol **result;
size_t i = 0, size = 0;
for (nd = rb_first_cached(source); nd; nd = rb_next(nd))
size++;
result = malloc(sizeof(*result) * size);
if (!result)
return NULL;
for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) { for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) {
struct symbol *pos = rb_entry(nd, struct symbol, rb_node); struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
symbols__insert_by_name(symbols, pos);
result[i++] = pos;
} }
qsort(result, size, sizeof(*result), symbols__sort_name_cmp);
*len = size;
return result;
} }
int symbol__match_symbol_name(const char *name, const char *str, int symbol__match_symbol_name(const char *name, const char *str,
...@@ -491,48 +488,51 @@ int symbol__match_symbol_name(const char *name, const char *str, ...@@ -491,48 +488,51 @@ int symbol__match_symbol_name(const char *name, const char *str,
return arch__compare_symbol_names(name, str); return arch__compare_symbol_names(name, str);
} }
static struct symbol *symbols__find_by_name(struct rb_root_cached *symbols, static struct symbol *symbols__find_by_name(struct symbol *symbols[],
size_t symbols_len,
const char *name, const char *name,
enum symbol_tag_include includes) enum symbol_tag_include includes,
size_t *found_idx)
{ {
struct rb_node *n; size_t i, lower = 0, upper = symbols_len;
struct symbol_name_rb_node *s = NULL; struct symbol *s;
if (symbols == NULL) if (!symbols_len)
return NULL; return NULL;
n = symbols->rb_root.rb_node; while (lower < upper) {
while (n) {
int cmp; int cmp;
s = rb_entry(n, struct symbol_name_rb_node, rb_node); i = (lower + upper) / 2;
cmp = symbol__match_symbol_name(s->sym.name, name, includes); s = symbols[i];
cmp = symbol__match_symbol_name(s->name, name, includes);
if (cmp > 0) if (cmp > 0)
n = n->rb_left; upper = i;
else if (cmp < 0) else if (cmp < 0)
n = n->rb_right; lower = i + 1;
else else {
if (found_idx)
*found_idx = i;
break; break;
} }
}
if (n == NULL) if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) {
return NULL;
if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY)
/* return first symbol that has same name (if any) */ /* return first symbol that has same name (if any) */
for (n = rb_prev(n); n; n = rb_prev(n)) { for (; i > 0; i--) {
struct symbol_name_rb_node *tmp; struct symbol *tmp = symbols[i - 1];
tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); if (!arch__compare_symbol_names(tmp->name, s->name)) {
if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) if (found_idx)
*found_idx = i - 1;
} else
break; break;
s = tmp; s = tmp;
} }
}
return &s->sym; assert(!found_idx || s == symbols[*found_idx]);
return s;
} }
void dso__reset_find_symbol_cache(struct dso *dso) void dso__reset_find_symbol_cache(struct dso *dso)
...@@ -590,24 +590,25 @@ struct symbol *dso__next_symbol(struct symbol *sym) ...@@ -590,24 +590,25 @@ struct symbol *dso__next_symbol(struct symbol *sym)
return symbols__next(sym); return symbols__next(sym);
} }
struct symbol *symbol__next_by_name(struct symbol *sym) struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx)
{ {
struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); if (*idx + 1 >= dso->symbol_names_len)
struct rb_node *n = rb_next(&s->rb_node); return NULL;
return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; ++*idx;
return dso->symbol_names[*idx];
} }
/* /*
* Returns first symbol that matched with @name. * Returns first symbol that matched with @name.
*/ */
struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name) 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, name, struct symbol *s = symbols__find_by_name(dso->symbol_names, dso->symbol_names_len,
SYMBOL_TAG_INCLUDE__NONE); name, SYMBOL_TAG_INCLUDE__NONE, idx);
if (!s) if (!s)
s = symbols__find_by_name(&dso->symbol_names, name, s = symbols__find_by_name(dso->symbol_names, dso->symbol_names_len,
SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); name, SYMBOL_TAG_INCLUDE__DEFAULT_ONLY, idx);
return s; return s;
} }
...@@ -615,9 +616,14 @@ void dso__sort_by_name(struct dso *dso) ...@@ -615,9 +616,14 @@ void dso__sort_by_name(struct dso *dso)
{ {
mutex_lock(&dso->lock); mutex_lock(&dso->lock);
if (!dso__sorted_by_name(dso)) { if (!dso__sorted_by_name(dso)) {
symbols__sort_by_name(&dso->symbol_names, &dso->symbols); size_t len;
dso->symbol_names = symbols__sort_by_name(&dso->symbols, &len);
if (dso->symbol_names) {
dso->symbol_names_len = len;
dso__set_sorted_by_name(dso); dso__set_sorted_by_name(dso);
} }
}
mutex_unlock(&dso->lock); mutex_unlock(&dso->lock);
} }
...@@ -2660,10 +2666,6 @@ int symbol__init(struct perf_env *env) ...@@ -2660,10 +2666,6 @@ int symbol__init(struct perf_env *env)
symbol__elf_init(); symbol__elf_init();
if (symbol_conf.sort_by_name)
symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
sizeof(struct symbol));
if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
return -1; return -1;
......
...@@ -43,8 +43,7 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, ...@@ -43,8 +43,7 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
/** /**
* A symtab entry. When allocated this may be preceded by an annotation (see * A symtab entry. When allocated this may be preceded by an annotation (see
* symbol__annotation), a browser_index (see symbol__browser_index) and rb_node * symbol__annotation) and/or a browser_index (see symbol__browser_index).
* to sort by name (see struct symbol_name_rb_node).
*/ */
struct symbol { struct symbol {
struct rb_node rb_node; struct rb_node rb_node;
...@@ -95,11 +94,6 @@ static inline size_t symbol__size(const struct symbol *sym) ...@@ -95,11 +94,6 @@ static inline size_t symbol__size(const struct symbol *sym)
struct strlist; struct strlist;
struct intlist; struct intlist;
struct symbol_name_rb_node {
struct rb_node rb_node;
struct symbol sym;
};
static inline int __symbol__join_symfs(char *bf, size_t size, const char *path) static inline int __symbol__join_symfs(char *bf, size_t size, const char *path)
{ {
return path__join(bf, size, symbol_conf.symfs, path); return path__join(bf, size, symbol_conf.symfs, path);
...@@ -136,9 +130,9 @@ void dso__delete_symbol(struct dso *dso, ...@@ -136,9 +130,9 @@ void dso__delete_symbol(struct dso *dso,
struct symbol *dso__find_symbol(struct dso *dso, u64 addr); struct symbol *dso__find_symbol(struct dso *dso, u64 addr);
struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr); struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr);
struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name);
struct symbol *symbol__next_by_name(struct symbol *sym); 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__first_symbol(struct dso *dso);
struct symbol *dso__last_symbol(struct dso *dso); struct symbol *dso__last_symbol(struct dso *dso);
......
...@@ -63,13 +63,11 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso, ...@@ -63,13 +63,11 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
FILE *fp) FILE *fp)
{ {
size_t ret = 0; size_t ret = 0;
struct rb_node *nd;
struct symbol_name_rb_node *pos;
for (nd = rb_first_cached(&dso->symbol_names); nd; nd = rb_next(nd)) { for (size_t i = 0; i < dso->symbol_names_len; i++) {
pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); struct symbol *pos = dso->symbol_names[i];
ret += fprintf(fp, "%s\n", pos->sym.name);
}
ret += fprintf(fp, "%s\n", pos->name);
}
return ret; return ret;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment