Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Always use non inlined file name for 'srcfile' sort key

When profiling the kernel with the 'srcfile' sort key it's common to
"get stuck" in include. For example a lot of code uses current or other
inlines, so they get accounted to some random include file. This is not
very useful as a high level categorization.

For example just profiling the idle loop usually shows mostly inlines,
so you never see the actual cpuidle file.

This patch changes the 'srcfile' sort key to always unwind the inline
stack using BFD/DWARF. So we always account to the base function that
called the inline.

In a few cases include is still shown (for example for MSR accesses),
but that is because they get inlining expanded as part of assigning to a
global function pointer. For the majority it works fine though.

v2: Use simpler while loop. Add maximum iteration count.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Link: http://lkml.kernel.org/r/1441133239-31254-1-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Andi Kleen and committed by
Arnaldo Carvalho de Melo
2f84b42b 5b923564

+28 -7
+2 -2
tools/perf/util/sort.c
··· 328 328 char *sf, *p; 329 329 struct map *map = e->ms.map; 330 330 331 - sf = get_srcline(map->dso, map__rip_2objdump(map, e->ip), 332 - e->ms.sym, true); 331 + sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), 332 + e->ms.sym, false, true); 333 333 if (!strcmp(sf, SRCLINE_UNKNOWN)) 334 334 return no_srcfile; 335 335 p = strchr(sf, ':');
+24 -5
tools/perf/util/srcline.c
··· 149 149 free(a2l); 150 150 } 151 151 152 + #define MAX_INLINE_NEST 1024 153 + 152 154 static int addr2line(const char *dso_name, u64 addr, 153 - char **file, unsigned int *line, struct dso *dso) 155 + char **file, unsigned int *line, struct dso *dso, 156 + bool unwind_inlines) 154 157 { 155 158 int ret = 0; 156 159 struct a2l_data *a2l = dso->a2l; ··· 172 169 a2l->found = false; 173 170 174 171 bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); 172 + 173 + if (a2l->found && unwind_inlines) { 174 + int cnt = 0; 175 + 176 + while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, 177 + &a2l->funcname, &a2l->line) && 178 + cnt++ < MAX_INLINE_NEST) 179 + ; 180 + } 175 181 176 182 if (a2l->found && a2l->filename) { 177 183 *file = strdup(a2l->filename); ··· 209 197 210 198 static int addr2line(const char *dso_name, u64 addr, 211 199 char **file, unsigned int *line_nr, 212 - struct dso *dso __maybe_unused) 200 + struct dso *dso __maybe_unused, 201 + bool unwind_inlines __maybe_unused) 213 202 { 214 203 FILE *fp; 215 204 char cmd[PATH_MAX]; ··· 267 254 */ 268 255 #define A2L_FAIL_LIMIT 123 269 256 270 - char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 271 - bool show_sym) 257 + char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 258 + bool show_sym, bool unwind_inlines) 272 259 { 273 260 char *file = NULL; 274 261 unsigned line = 0; ··· 289 276 if (!strncmp(dso_name, "/tmp/perf-", 10)) 290 277 goto out; 291 278 292 - if (!addr2line(dso_name, addr, &file, &line, dso)) 279 + if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines)) 293 280 goto out; 294 281 295 282 if (asprintf(&srcline, "%s:%u", ··· 322 309 { 323 310 if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0) 324 311 free(srcline); 312 + } 313 + 314 + char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 315 + bool show_sym) 316 + { 317 + return __get_srcline(dso, addr, sym, show_sym, false); 325 318 }
+2
tools/perf/util/util.h
··· 321 321 extern bool srcline_full_filename; 322 322 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 323 323 bool show_sym); 324 + char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 325 + bool show_sym, bool unwind_inlines); 324 326 void free_srcline(char *srcline); 325 327 326 328 int filename__read_str(const char *filename, char **buf, size_t *sizep);