diff options
author | Ian Rogers <irogers@google.com> | 2023-06-22 22:45:19 -0700 |
---|---|---|
committer | Namhyung Kim <namhyung@kernel.org> | 2023-06-23 21:47:20 -0700 |
commit | 259dce914e93482a0e25a6ddef88f5b6d85df9bd (patch) | |
tree | d5486c05e7ef74f11272c11c4b121d6428052651 /tools/perf/util/symbol.c | |
parent | ce5b293405fda0f80c803b6c838f51ec7f618f90 (diff) |
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: Ian Rogers <irogers@google.com>
Acked-by: Namhyung 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: Namhyung Kim <namhyung@kernel.org>
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 124 |
1 files changed, 63 insertions, 61 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index bb02047e1c59..bc79291b9f3b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -440,38 +440,35 @@ static struct symbol *symbols__next(struct symbol *sym) 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; - struct rb_node *parent = NULL; - struct symbol_name_rb_node *symn, *s; - bool leftmost = true; + const struct symbol *lhs = *((const struct symbol **)vlhs); + const struct symbol *rhs = *((const struct symbol **)vrhs); - symn = container_of(sym, struct symbol_name_rb_node, sym); - - 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); + return strcmp(lhs->name, rhs->name); } -static void symbols__sort_by_name(struct rb_root_cached *symbols, - struct rb_root_cached *source) +static struct symbol **symbols__sort_by_name(struct rb_root_cached *source, size_t *len) { 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)) { 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, @@ -491,48 +488,51 @@ int symbol__match_symbol_name(const char *name, const char *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, - enum symbol_tag_include includes) + enum symbol_tag_include includes, + size_t *found_idx) { - struct rb_node *n; - struct symbol_name_rb_node *s = NULL; + size_t i, lower = 0, upper = symbols_len; + struct symbol *s; - if (symbols == NULL) + if (!symbols_len) return NULL; - n = symbols->rb_root.rb_node; - - while (n) { + while (lower < upper) { int cmp; - s = rb_entry(n, struct symbol_name_rb_node, rb_node); - cmp = symbol__match_symbol_name(s->sym.name, name, includes); + i = (lower + upper) / 2; + s = symbols[i]; + cmp = symbol__match_symbol_name(s->name, name, includes); if (cmp > 0) - n = n->rb_left; + upper = i; else if (cmp < 0) - n = n->rb_right; - else + lower = i + 1; + else { + if (found_idx) + *found_idx = i; break; + } } - - if (n == NULL) - return NULL; - - if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) + if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) { /* return first symbol that has same name (if any) */ - for (n = rb_prev(n); n; n = rb_prev(n)) { - struct symbol_name_rb_node *tmp; + for (; i > 0; i--) { + struct symbol *tmp = symbols[i - 1]; - tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); - if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) + if (!arch__compare_symbol_names(tmp->name, s->name)) { + if (found_idx) + *found_idx = i - 1; + } else break; s = tmp; } - - return &s->sym; + } + assert(!found_idx || s == symbols[*found_idx]); + return s; } void dso__reset_find_symbol_cache(struct dso *dso) @@ -590,24 +590,25 @@ struct symbol *dso__next_symbol(struct symbol *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); - struct rb_node *n = rb_next(&s->rb_node); + if (*idx + 1 >= dso->symbol_names_len) + 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. */ -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, - SYMBOL_TAG_INCLUDE__NONE); + struct symbol *s = symbols__find_by_name(dso->symbol_names, dso->symbol_names_len, + name, SYMBOL_TAG_INCLUDE__NONE, idx); if (!s) - s = symbols__find_by_name(&dso->symbol_names, name, - SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); + s = symbols__find_by_name(dso->symbol_names, dso->symbol_names_len, + name, SYMBOL_TAG_INCLUDE__DEFAULT_ONLY, idx); return s; } @@ -615,8 +616,13 @@ void dso__sort_by_name(struct dso *dso) { mutex_lock(&dso->lock); if (!dso__sorted_by_name(dso)) { - symbols__sort_by_name(&dso->symbol_names, &dso->symbols); - dso__set_sorted_by_name(dso); + 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); + } } mutex_unlock(&dso->lock); } @@ -2660,10 +2666,6 @@ int symbol__init(struct perf_env *env) 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) return -1; |