diff options
author | Anton Blanchard <anton@samba.org> | 2011-08-24 02:40:17 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-09-23 13:36:36 -0400 |
commit | 694bf407b06113f5e0f71764756f11903126fec0 (patch) | |
tree | ee1593aa431242c12d9be39b7330dc70e5c4b57a /tools | |
parent | 318779086086f46127a249878eeebb3dc80578eb (diff) |
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: Anton Blanchard <anton@samba.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/symbol.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 0d94ddb55bd7..870b3b8c649b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -86,6 +86,92 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type) | |||
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | static int prefix_underscores_count(const char *str) | ||
90 | { | ||
91 | const char *tail = str; | ||
92 | |||
93 | while (*tail == '_') | ||
94 | tail++; | ||
95 | |||
96 | return tail - str; | ||
97 | } | ||
98 | |||
99 | #define SYMBOL_A 0 | ||
100 | #define SYMBOL_B 1 | ||
101 | |||
102 | static int choose_best_symbol(struct symbol *syma, struct symbol *symb) | ||
103 | { | ||
104 | s64 a; | ||
105 | s64 b; | ||
106 | |||
107 | /* Prefer a symbol with non zero length */ | ||
108 | a = syma->end - syma->start; | ||
109 | b = symb->end - symb->start; | ||
110 | if ((b == 0) && (a > 0)) | ||
111 | return SYMBOL_A; | ||
112 | else if ((a == 0) && (b > 0)) | ||
113 | return SYMBOL_B; | ||
114 | |||
115 | /* Prefer a non weak symbol over a weak one */ | ||
116 | a = syma->binding == STB_WEAK; | ||
117 | b = symb->binding == STB_WEAK; | ||
118 | if (b && !a) | ||
119 | return SYMBOL_A; | ||
120 | if (a && !b) | ||
121 | return SYMBOL_B; | ||
122 | |||
123 | /* Prefer a global symbol over a non global one */ | ||
124 | a = syma->binding == STB_GLOBAL; | ||
125 | b = symb->binding == STB_GLOBAL; | ||
126 | if (a && !b) | ||
127 | return SYMBOL_A; | ||
128 | if (b && !a) | ||
129 | return SYMBOL_B; | ||
130 | |||
131 | /* Prefer a symbol with less underscores */ | ||
132 | a = prefix_underscores_count(syma->name); | ||
133 | b = prefix_underscores_count(symb->name); | ||
134 | if (b > a) | ||
135 | return SYMBOL_A; | ||
136 | else if (a > b) | ||
137 | return SYMBOL_B; | ||
138 | |||
139 | /* If all else fails, choose the symbol with the longest name */ | ||
140 | if (strlen(syma->name) >= strlen(symb->name)) | ||
141 | return SYMBOL_A; | ||
142 | else | ||
143 | return SYMBOL_B; | ||
144 | } | ||
145 | |||
146 | static void symbols__fixup_duplicate(struct rb_root *symbols) | ||
147 | { | ||
148 | struct rb_node *nd; | ||
149 | struct symbol *curr, *next; | ||
150 | |||
151 | nd = rb_first(symbols); | ||
152 | |||
153 | while (nd) { | ||
154 | curr = rb_entry(nd, struct symbol, rb_node); | ||
155 | again: | ||
156 | nd = rb_next(&curr->rb_node); | ||
157 | next = rb_entry(nd, struct symbol, rb_node); | ||
158 | |||
159 | if (!nd) | ||
160 | break; | ||
161 | |||
162 | if (curr->start != next->start) | ||
163 | continue; | ||
164 | |||
165 | if (choose_best_symbol(curr, next) == SYMBOL_A) { | ||
166 | rb_erase(&next->rb_node, symbols); | ||
167 | goto again; | ||
168 | } else { | ||
169 | nd = rb_next(&curr->rb_node); | ||
170 | rb_erase(&curr->rb_node, symbols); | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
89 | static void symbols__fixup_end(struct rb_root *symbols) | 175 | static void symbols__fixup_end(struct rb_root *symbols) |
90 | { | 176 | { |
91 | struct rb_node *nd, *prevnd = rb_first(symbols); | 177 | struct rb_node *nd, *prevnd = rb_first(symbols); |
@@ -692,6 +778,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
692 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | 778 | if (dso__load_all_kallsyms(dso, filename, map) < 0) |
693 | return -1; | 779 | return -1; |
694 | 780 | ||
781 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
695 | symbols__fixup_end(&dso->symbols[map->type]); | 782 | symbols__fixup_end(&dso->symbols[map->type]); |
696 | 783 | ||
697 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 784 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
@@ -1269,6 +1356,7 @@ new_symbol: | |||
1269 | * For misannotated, zeroed, ASM function sizes. | 1356 | * For misannotated, zeroed, ASM function sizes. |
1270 | */ | 1357 | */ |
1271 | if (nr > 0) { | 1358 | if (nr > 0) { |
1359 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
1272 | symbols__fixup_end(&dso->symbols[map->type]); | 1360 | symbols__fixup_end(&dso->symbols[map->type]); |
1273 | if (kmap) { | 1361 | if (kmap) { |
1274 | /* | 1362 | /* |