Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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.org


Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 31877908
Loading
Loading
Loading
Loading
+88 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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)
@@ -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) {
			/*