Skip to content

Commit

Permalink
perf symbols: Add some heuristics for choosing the best duplicate symbol
Browse files Browse the repository at this point in the history
Try and pick the best symbol based on a few heuristics:

-  Prefer a non weak symbol over a weak one
-  Prefer a global symbol over a non global one
-  Prefer a symbol with less underscores (idea taken from kallsyms.c)
-  If all else fails, choose the symbol with the longest name

Cc: Eric B Munson <emunson@mgebm.net>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20110824065243.161953371@samba.org
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
antonblanchard authored and acmel committed Sep 23, 2011
1 parent 3187790 commit 694bf40
Showing 1 changed file with 88 additions and 0 deletions.
88 changes: 88 additions & 0 deletions tools/perf/util/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,92 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type)
}
}

static int prefix_underscores_count(const char *str)
{
const char *tail = str;

while (*tail == '_')
tail++;

return tail - str;
}

#define SYMBOL_A 0
#define SYMBOL_B 1

static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
{
s64 a;
s64 b;

/* Prefer a symbol with non zero length */
a = syma->end - syma->start;
b = symb->end - symb->start;
if ((b == 0) && (a > 0))
return SYMBOL_A;
else if ((a == 0) && (b > 0))
return SYMBOL_B;

/* Prefer a non weak symbol over a weak one */
a = syma->binding == STB_WEAK;
b = symb->binding == STB_WEAK;
if (b && !a)
return SYMBOL_A;
if (a && !b)
return SYMBOL_B;

/* Prefer a global symbol over a non global one */
a = syma->binding == STB_GLOBAL;
b = symb->binding == STB_GLOBAL;
if (a && !b)
return SYMBOL_A;
if (b && !a)
return SYMBOL_B;

/* Prefer a symbol with less underscores */
a = prefix_underscores_count(syma->name);
b = prefix_underscores_count(symb->name);
if (b > a)
return SYMBOL_A;
else if (a > b)
return SYMBOL_B;

/* If all else fails, choose the symbol with the longest name */
if (strlen(syma->name) >= strlen(symb->name))
return SYMBOL_A;
else
return SYMBOL_B;
}

static void symbols__fixup_duplicate(struct rb_root *symbols)
{
struct rb_node *nd;
struct symbol *curr, *next;

nd = rb_first(symbols);

while (nd) {
curr = rb_entry(nd, struct symbol, rb_node);
again:
nd = rb_next(&curr->rb_node);
next = rb_entry(nd, struct symbol, rb_node);

if (!nd)
break;

if (curr->start != next->start)
continue;

if (choose_best_symbol(curr, next) == SYMBOL_A) {
rb_erase(&next->rb_node, symbols);
goto again;
} else {
nd = rb_next(&curr->rb_node);
rb_erase(&curr->rb_node, symbols);
}
}
}

static void symbols__fixup_end(struct rb_root *symbols)
{
struct rb_node *nd, *prevnd = rb_first(symbols);
Expand Down Expand Up @@ -692,6 +778,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
if (dso__load_all_kallsyms(dso, filename, map) < 0)
return -1;

symbols__fixup_duplicate(&dso->symbols[map->type]);
symbols__fixup_end(&dso->symbols[map->type]);

if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Expand Down Expand Up @@ -1269,6 +1356,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
* For misannotated, zeroed, ASM function sizes.
*/
if (nr > 0) {
symbols__fixup_duplicate(&dso->symbols[map->type]);
symbols__fixup_end(&dso->symbols[map->type]);
if (kmap) {
/*
Expand Down

0 comments on commit 694bf40

Please sign in to comment.