Commit 694bf407 authored by Anton Blanchard's avatar Anton Blanchard Committed by Arnaldo Carvalho de Melo

perf symbols: Add some heuristics for choosing the best duplicate symbol

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.orgSigned-off-by: default avatarAnton Blanchard <anton@samba.org>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 31877908
...@@ -86,6 +86,92 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type) ...@@ -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) static void symbols__fixup_end(struct rb_root *symbols)
{ {
struct rb_node *nd, *prevnd = rb_first(symbols); struct rb_node *nd, *prevnd = rb_first(symbols);
...@@ -692,6 +778,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, ...@@ -692,6 +778,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
if (dso__load_all_kallsyms(dso, filename, map) < 0) if (dso__load_all_kallsyms(dso, filename, map) < 0)
return -1; return -1;
symbols__fixup_duplicate(&dso->symbols[map->type]);
symbols__fixup_end(&dso->symbols[map->type]); symbols__fixup_end(&dso->symbols[map->type]);
if (dso->kernel == DSO_TYPE_GUEST_KERNEL) if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
...@@ -1269,6 +1356,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, ...@@ -1269,6 +1356,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
* For misannotated, zeroed, ASM function sizes. * For misannotated, zeroed, ASM function sizes.
*/ */
if (nr > 0) { if (nr > 0) {
symbols__fixup_duplicate(&dso->symbols[map->type]);
symbols__fixup_end(&dso->symbols[map->type]); symbols__fixup_end(&dso->symbols[map->type]);
if (kmap) { if (kmap) {
/* /*
......
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