perf script: add BTS analysis features
Subsystems (2)
v5 cover perf script: add BTS analysis features
Hi Frederic, David,
This patch series adds the functions to analyze BTS logs to perf-script and, makes perf-script more informative version 5.
The patches add the following functions.
- Unify the expression to "[unknown]"
- Fix BTS record header to resolve DSOs and symbols of user-space
- Resolve DSOs and symbols for BTS's branch_from addresses
- Show the offset of symbols with the 'symoff' field specifier.
- Resolve the real path of [kernel.kallsym] using '--show-kernel-path' option.
Usage:
First, get the BTS log with the following command.
# perf record -e branches:u -c 1 -d <command>
Second, analyze that trace data.
# perf script -f ip,addr,sym,symoff,dso [--show-kernel-path] This command's output format is: <branch_from addr> <branch_from function+offset> <branch_from DSO> => <branch_to addr> <branch_to function+offset> <branch_to DSO>
Output sample:
# perf record -e branches:u -c 1 -d ls
[snip]
# perf script -f ip,addr,sym,dso,symoff --show-kernel-path
[snip]
3430c21399 __libc_start_main+0xe9 (/lib64/libc-2.14.so) => 402c1c main+0x0 (/root/bin/ls)
402c41 main+0x25 (/root/bin/ls) => 40b390 set_program_name+0x0 (/root/bin/ls)
ffffffff814ac5ed irq_return+0x0 (/lib/modules/3.2.0+/build/vmlinux) => 40b390 set_program_name+0x0 (/root/bin/ls)
40b39e set_program_name+0xe (/root/bin/ls) => 401e20 strrchr@plt+0x0 (/root/bin/ls)
401e20 strrchr@plt+0x0 (/root/bin/ls) => 401e26 strrchr@plt+0x6 (/root/bin/ls)
401e2b strrchr@plt+0xb (/root/bin/ls) => 401b80 _init+0x18 (/root/bin/ls)
401b86 _init+0x1e (/root/bin/ls) => 3430813850 _dl_runtime_resolve+0x0 (/lib64/ld-2.14.so)
[snip]It shows the tracee application's execution path.
Future Works:
- add source code path field, line number field ...etc.
- add record/report script to use easily and, show human-friendly output.
- filtering kernel functions using scripts
Changes in v5:
- Use fprintf() instead of printf() in struct map/symbol's functions to print something.
- Abolish using 'self' in function's paramater
e.g. map__print_dsoname(self) => map__fprintf_dsoname(map, fp)
- Change the specifier to print symbol_offset 'offs' to 'symoff'
- Change the output format "<branch_to> <branch_from>" to "<branch_from> => <branch_to>"
Changes in v4:
- add check routine to set correct perf_sample's header.
Changes in v3:
- remove the bug fix patch already fixed.
- unify the "[unknown]" expressions in perf-script.
- fix perf_event_header of BTS events.
- fix patch's descriptions
Changes in v2:
- add a bug fix patch that prints correct IP address
- output the magic word "(unknown)" as symbol name when perf-script can't resolve symbols.
- output "[unknown]" as DSO name when perf-script can't resolve DSO path.
- change the way to output offset of symbols from '--show-symbol-offset' to 'offs' field.
- clean up codes.
Thanks,
---
Akihiro Nagai (5):
perf script: add option resolving vmlinux path perf script: add the offset field specifier
perf script: print branch_from and branch_to of BTS events
perf: set correct value to perf_event_header.misc for BTS
perf-script: unify the expressions indicate "unknown"
arch/x86/kernel/cpu/perf_event_intel_ds.c | 31 +++++++---- tools/perf/Documentation/perf-script.txt | 5 +- tools/perf/builtin-script.c | 80 ++++++++++++++++++++++++----- tools/perf/util/map.c | 15 +++++ tools/perf/util/map.h | 1 tools/perf/util/session.c | 39 +++++--------- tools/perf/util/session.h | 2 - tools/perf/util/symbol.c | 22 ++++++++ tools/perf/util/symbol.h | 4 + 9 files changed, 147 insertions(+), 52 deletions(-)
Signature · 1 line
Akihiro Nagai ([email protected])
PATCH v5 1/5 perf-script: unify the expressions indicate "unknown"
perf-script uses various expressions to indicate "unknown". It is unfriendly for user scripts to parse it. So, this patch unifies the expressions to "[unknown]".
Changes in v5:
- Use fprintf() instead of printf() in struct map/symbol's functions to print something.
- Abolish using 'self' in function's paramater
Changes in v3:
- unify all expressions to [unknown]
Changes in v2:
- add this patch
---
tools/perf/builtin-script.c | 20 ++++++-------------- tools/perf/util/map.c | 12 ++++++++++++ tools/perf/util/map.h | 1 + tools/perf/util/session.c | 35 ++++++++++------------------------- tools/perf/util/symbol.c | 12 ++++++++++++ tools/perf/util/symbol.h | 1 + 6 files changed, 42 insertions(+), 39 deletions(-)
tools/perf/builtin-script.c +6 -14
@@ -300,7 +300,7 @@ static void print_sample_start(struct perf_sample *sample, }else evname =__event_name (attr->type, attr->config); -printf ("%s: " , evname ? evname :"(unknown)" ); +printf ("%s: " , evname ? evname :"[unknown]" ); } }
@@ -323,7 +323,6 @@ static void print_sample_addr(union perf_event *event, {struct addr_location al;u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -const char *symname, *dsoname;printf ("%16" PRIx64, sample->addr);
@@ -343,21 +342,14 @@ static void print_sample_addr(union perf_event *event, al.sym =map__find_symbol (al.map, al.addr,NULL );if (PRINT_FIELD (SYM )) { -if (al.sym && al.sym->name) - symname = al.sym->name; -else - symname ="" ; - -printf (" %16s" , symname); +printf (" " ); +symbol__fprintf_symname (al.sym, stdout); }if (PRINT_FIELD (DSO )) { -if (al.map && al.map->dso && al.map->dso->name) - dsoname = al.map->dso->name; -else - dsoname ="" ; - -printf (" (%s)" , dsoname); +printf (" (" ); +map__fprintf_dsoname (al.map, stdout); +printf (")" ); } }
tools/perf/util/map.c +12 -0
@@ -212,6 +212,18 @@ size_t map__fprintf(struct map *self, FILE *fp) self->start, self->end, self->pgoff, self->dso->name); } +size_t map__fprintf_dsoname (struct map *map,FILE *fp) +{ +const char *dsoname; + +if (map && map->dso && map->dso->name) + dsoname = map->dso->name; +else + dsoname ="[unknown]" ; + +return fprintf (fp,"%s" , dsoname); +} +/* * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
tools/perf/util/map.h +1 -0
@@ -118,6 +118,7 @@ void map__delete(struct map *self);struct map *map__clone (struct map *self);int map__overlap (struct map *l,struct map *r);size_t map__fprintf (struct map *self,FILE *fp); +size_t map__fprintf_dsoname (struct map *map,FILE *fp);int map__load (struct map *self,symbol_filter_t filter); struct symbol *map__find_symbol(struct map *self,
tools/perf/util/session.c +10 -25
@@ -1296,7 +1296,6 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, int print_sym, int print_dso) {struct addr_location al; -const char *symname, *dsoname;struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;struct callchain_cursor_node *node;
@@ -1324,20 +1323,13 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,printf ("\t%16" PRIx64, node->ip);if (print_sym) { -if (node->sym && node->sym->name) - symname = node->sym->name; -else - symname ="" ; - -printf (" %s" , symname); +printf (" " ); +symbol__fprintf_symname (node->sym, stdout); }if (print_dso) { -if (node->map && node->map->dso && node->map->dso->name) - dsoname = node->map->dso->name; -else - dsoname ="" ; - -printf (" (%s)" , dsoname); +printf (" (" ); +map__fprintf_dsoname (al.map, stdout); +printf (")" ); }printf ("\n" );
@@ -1347,21 +1339,14 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, }else {printf ("%16" PRIx64, sample->ip);if (print_sym) { -if (al.sym && al.sym->name) - symname = al.sym->name; -else - symname ="" ; - -printf (" %s" , symname); +printf (" " ); +symbol__fprintf_symname (al.sym, stdout); }if (print_dso) { -if (al.map && al.map->dso && al.map->dso->name) - dsoname = al.map->dso->name; -else - dsoname ="" ; - -printf (" (%s)" , dsoname); +printf (" (" ); +map__fprintf_dsoname (al.map, stdout); +printf (")" ); } } }
tools/perf/util/symbol.c +12 -0
@@ -264,6 +264,18 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp) sym->name); } +size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp) +{ +const char *symname; + +if (sym && sym->name) + symname = sym->name; +else + symname ="[unknown]" ; + +return fprintf (fp,"%s" , symname); +} +void dso__set_long_name (struct dso *dso,char *name) {if (name ==NULL )
tools/perf/util/symbol.h +1 -0
@@ -241,6 +241,7 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);int symbol__init (void );void symbol__exit (void ); +size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp);bool symbol_type__is_a (char symbol_type,enum map_type map_type);size_t machine__fprintf_vmlinux_path (struct machine *machine,FILE *fp);
[tip:perf/core] perf script: Unify the expressions indicating " unknown"
Commit-ID: 547a92e0aedb88129e7fbd804697a11949de2e5a Gitweb: http://git.kernel.org/tip/547a92e0aedb88129e7fbd804697a11949de2e5a Author: Akihiro Nagai <[email protected]> AuthorDate: Mon, 30 Jan 2012 13:42:57 +0900 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Mon, 30 Jan 2012 17:57:57 -0200
perf script: Unify the expressions indicating "unknown"
The perf script command uses various expressions to indicate "unknown".
It is unfriendly for user scripts to parse it. So, this patch unifies the expressions to "[unknown]".
--- tools/perf/builtin-script.c | 20 ++++++-------------- tools/perf/util/map.c | 12 ++++++++++++ tools/perf/util/map.h | 1 + tools/perf/util/session.c | 35 ++++++++++------------------------- tools/perf/util/symbol.c | 12 ++++++++++++ tools/perf/util/symbol.h | 1 + 6 files changed, 42 insertions(+), 39 deletions(-)
tools/perf/builtin-script.c +6 -14
@@ -300,7 +300,7 @@ static void print_sample_start(struct perf_sample *sample, }else evname =__event_name (attr->type, attr->config); -printf ("%s: " , evname ? evname :"(unknown)" ); +printf ("%s: " , evname ? evname :"[unknown]" ); } }
@@ -323,7 +323,6 @@ static void print_sample_addr(union perf_event *event, {struct addr_location al;u8 cpumode = event->header.misc &PERF_RECORD_MISC_CPUMODE_MASK ; -const char *symname, *dsoname;printf ("%16" PRIx64, sample->addr);
@@ -343,21 +342,14 @@ static void print_sample_addr(union perf_event *event, al.sym =map__find_symbol (al.map, al.addr,NULL );if (PRINT_FIELD (SYM )) { -if (al.sym && al.sym->name) - symname = al.sym->name; -else - symname ="" ; - -printf (" %16s" , symname); +printf (" " ); +symbol__fprintf_symname (al.sym, stdout); }if (PRINT_FIELD (DSO )) { -if (al.map && al.map->dso && al.map->dso->name) - dsoname = al.map->dso->name; -else - dsoname ="" ; - -printf (" (%s)" , dsoname); +printf (" (" ); +map__fprintf_dsoname (al.map, stdout); +printf (")" ); } }
tools/perf/util/map.c +12 -0
@@ -212,6 +212,18 @@ size_t map__fprintf(struct map *self, FILE *fp) self->start, self->end, self->pgoff, self->dso->name); } +size_t map__fprintf_dsoname (struct map *map,FILE *fp) +{ +const char *dsoname; + +if (map && map->dso && map->dso->name) + dsoname = map->dso->name; +else + dsoname ="[unknown]" ; + +return fprintf (fp,"%s" , dsoname); +} +/* * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
tools/perf/util/map.h +1 -0
@@ -118,6 +118,7 @@ void map__delete(struct map *self);struct map *map__clone (struct map *self);int map__overlap (struct map *l,struct map *r);size_t map__fprintf (struct map *self,FILE *fp); +size_t map__fprintf_dsoname (struct map *map,FILE *fp);int map__load (struct map *self,symbol_filter_t filter); struct symbol *map__find_symbol(struct map *self,
tools/perf/util/session.c +10 -25
@@ -1296,7 +1296,6 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, int print_sym, int print_dso) {struct addr_location al; -const char *symname, *dsoname;struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;struct callchain_cursor_node *node;
@@ -1324,20 +1323,13 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,printf ("\t%16" PRIx64, node->ip);if (print_sym) { -if (node->sym && node->sym->name) - symname = node->sym->name; -else - symname ="" ; - -printf (" %s" , symname); +printf (" " ); +symbol__fprintf_symname (node->sym, stdout); }if (print_dso) { -if (node->map && node->map->dso && node->map->dso->name) - dsoname = node->map->dso->name; -else - dsoname ="" ; - -printf (" (%s)" , dsoname); +printf (" (" ); +map__fprintf_dsoname (al.map, stdout); +printf (")" ); }printf ("\n" );
@@ -1347,21 +1339,14 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, }else {printf ("%16" PRIx64, sample->ip);if (print_sym) { -if (al.sym && al.sym->name) - symname = al.sym->name; -else - symname ="" ; - -printf (" %s" , symname); +printf (" " ); +symbol__fprintf_symname (al.sym, stdout); }if (print_dso) { -if (al.map && al.map->dso && al.map->dso->name) - dsoname = al.map->dso->name; -else - dsoname ="" ; - -printf (" (%s)" , dsoname); +printf (" (" ); +map__fprintf_dsoname (al.map, stdout); +printf (")" ); } } }
tools/perf/util/symbol.c +12 -0
@@ -263,6 +263,18 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp) sym->name); } +size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp) +{ +const char *symname; + +if (sym && sym->name) + symname = sym->name; +else + symname ="[unknown]" ; + +return fprintf (fp,"%s" , symname); +} +void dso__set_long_name (struct dso *dso,char *name) {if (name ==NULL )
tools/perf/util/symbol.h +1 -0
@@ -241,6 +241,7 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);int symbol__init (void );void symbol__exit (void ); +size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp);bool symbol_type__is_a (char symbol_type,enum map_type map_type);size_t machine__fprintf_vmlinux_path (struct machine *machine,FILE *fp);
PATCH v5 2/5 perf: set correct value to perf_event_header.misc for BTS
In reply to Akihiro NagaiSet correct value to perf_event_headder.misc of BTS record to resolve symbols and DSOs correctly by user-space tools.
Changes in v4:
- Add check routine to set correct value
---
arch/x86/kernel/cpu/perf_event_intel_ds.c | 31 +++++++++++++++++++---------- 1 files changed, 20 insertions(+), 11 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_ds.c +20 -11
@@ -285,6 +285,18 @@ void intel_pmu_disable_bts(void)update_debugctlmsr (debugctlmsr); } + +#include <asm/insn.h> + +static inline bool kernel_ip (unsigned long ip) +{ +#ifdef CONFIG_X86_32 +return ip >PAGE_OFFSET ; +#else +return (long )ip <0 ; +#endif +} +int intel_pmu_drain_bts_buffer (void ) {struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events);
@@ -330,6 +342,14 @@ int intel_pmu_drain_bts_buffer(void)return 1 ;for (; at < top; at++) { +/* +* To resolve user space symbols and DSOs correctly, set +* PERF_RECORD_MISC_USER if from_addr or to_addr is user space. +*/ +if (!kernel_ip (data.ip) || !kernel_ip (data.addr)) { + header.misc &= ~PERF_RECORD_MISC_CPUMODE_MASK ; + header.misc |=PERF_RECORD_MISC_USER ; + } data.ip = at->from; data.addr = at->to;
@@ -476,17 +496,6 @@ void intel_pmu_pebs_disable_all(void)wrmsrl (MSR_IA32_PEBS_ENABLE ,0 ); } -#include <asm/insn.h> - -static inline bool kernel_ip (unsigned long ip) -{ -#ifdef CONFIG_X86_32 -return ip >PAGE_OFFSET ; -#else -return (long )ip <0 ; -#endif -} -static int intel_pmu_pebs_fixup_ip (struct pt_regs *regs) {struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events);
Peter Zijlstra
maintainerRe: [PATCH -tip v5 2/5] perf: set correct value to perf_event_header.misc for BTS
Quoted 4 lines · Akihiro Nagai
arch/x86/kernel/cpu/perf_event_intel_ds.c +0
-0@@ -330,6 +342,14 @@ int intel_pmu_drain_bts_buffer(void)return 1 ;for (; at < top; at++) {
arch/x86/kernel/cpu/perf_event_intel_ds.c int intel_pmu_drain_bts_buffer(void) · line 354
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_ds.c +8
-0+/* +* To resolve user space symbols and DSOs correctly, set +* PERF_RECORD_MISC_USER if from_addr or to_addr is user space. +*/ +if (!kernel_ip (data.ip) || !kernel_ip (data.addr)) { + header.misc &= ~PERF_RECORD_MISC_CPUMODE_MASK ; + header.misc |=PERF_RECORD_MISC_USER ; + } data.ip = at->from; data.addr = at->to;
Why not key off of the from? If its a jump from userspace its a user event, its a jump from kernel space its a kernel event?
Re: [PATCH -tip v5 2/5] perf: set correct value to perf_event_header.misc for BTS
Quoted 4 lines · Peter Zijlstra
Quoted 3 lines · Akihiro Nagai
arch/x86/kernel/cpu/perf_event_intel_ds.c +0
-0@@ -330,6 +342,14 @@ int intel_pmu_drain_bts_buffer(void)return 1 ;
Quoted 14 lines
arch/x86/kernel/cpu/perf_event_intel_ds.c int intel_pmu_drain_bts_buffer(void) · line 354
Quoted 11 lines
arch/x86/kernel/cpu/perf_event_intel_ds.c +8
-0for (; at< top; at++) { +/* +* To resolve user space symbols and DSOs correctly, set +* PERF_RECORD_MISC_USER if from_addr or to_addr is user space. +*/ +if (!kernel_ip (data.ip) || !kernel_ip (data.addr)) { + header.misc&= ~PERF_RECORD_MISC_CPUMODE_MASK ; + header.misc |=PERF_RECORD_MISC_USER ; + } data.ip = at->from; data.addr = at->to;Why not key off of the from? If its a jump from userspace its a user event, its a jump from kernel space its a kernel event?
Of course, originally, perf does that. And, in those cases, BTS records the both addresses of kernel and user in one perf_sample on branches from kernel to user. Current perf sets PERF_RECORD_MISC_KERNEL to all BTS events, and perf-script doesn't resolve symbols and DSOs about the user-space address, because it is a kernel event. So, to solve both kernel and user symbols on an event, I had to add this change.
Thank you,
Peter Zijlstra
maintainerRe: [PATCH -tip v5 2/5] perf: set correct value to perf_event_header.misc for BTS
Quoted 20 lines · Akihiro Nagai
Quoted 4 lines · Peter Zijlstra
Quoted 3 lines · Akihiro Nagai
(quoted diff) +0
-0@@ -330,6 +342,14 @@ int intel_pmu_drain_bts_buffer(void) return 1;Quoted 14 lines
Review int intel_pmu_drain_bts_buffer(void) · line 354
Quoted 11 lines
(quoted diff) +8
-0for (; at< top; at++) { + /* + * To resolve user space symbols and DSOs correctly, set + * PERF_RECORD_MISC_USER if from_addr or to_addr is user space. + */ + if (!kernel_ip(data.ip) || !kernel_ip(data.addr)) { + header.misc&= ~PERF_RECORD_MISC_CPUMODE_MASK; + header.misc |= PERF_RECORD_MISC_USER; + } data.ip = at->from; data.addr = at->to;Why not key off of the from? If its a jump from userspace its a user event, its a jump from kernel space its a kernel event?
Quoted 1 line
Of course, originally, perf does that.
I don't think it does.
Quoted 3 lines
And, in those cases,
BTS records the both addresses of kernel and user in oneperf_sampleon branches from kernel to user.
Sorry, I don't get this.
Quoted 1 line
Current perf sets
PERF_RECORD_MISC_KERNELto all BTS events,
It doesn't, it does something far more stupid.. it sets the state to wherever we were when the BTS overflow interrupt happens. If that was in kernel space, we mark all of them as in-kernel, if that was in user-space we mark all of then in-user.
Quoted 3 lines
and
perf-script doesn't resolve symbols and DSOs about the user-space address, because it is a kernel event.
Well, that's a perf-script problem, not something you should change the kernel for.
So how about something like this?
--- arch/x86/kernel/cpu/perf_event_intel_ds.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-)
(quoted diff) +0 -0
b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index d6bd49f..81e788c 100644
arch/x86/kernel/cpu/perf_event_intel_ds.c +7 -0
@@ -333,6 +333,13 @@ int intel_pmu_drain_bts_buffer(void) data.ip = at->from; data.addr = at->to; +/* XXX doesn't do virt muck properly */ + header.misc &= ~PERF_RECORD_MISC_CPUMODE_MASK ; +if (kernel_ip (at->from)) + header.misc |=PERF_RECORD_MISC_KERNEL ; +else + header.misc |=PERF_RECORD_MISC_USER ; +perf_output_sample (&handle, &header, &data, event); }
Re: [PATCH -tip v5 2/5] perf: set correct value to perf_event_header.misc for BTS
Quoted 29 lines · Peter Zijlstra
Quoted 20 lines · Akihiro Nagai
Quoted 4 lines · Peter Zijlstra
Quoted 3 lines · Akihiro Nagai
(quoted diff) +0
-0@@ -330,6 +342,14 @@ int intel_pmu_drain_bts_buffer(void) return 1;Quoted 14 lines
Review int intel_pmu_drain_bts_buffer(void) · line 354
Quoted 11 lines
(quoted diff) +8
-0for (; at< top; at++) { + /* + * To resolve user space symbols and DSOs correctly, set + * PERF_RECORD_MISC_USER if from_addr or to_addr is user space. + */ + if (!kernel_ip(data.ip) || !kernel_ip(data.addr)) { + header.misc&= ~PERF_RECORD_MISC_CPUMODE_MASK; + header.misc |= PERF_RECORD_MISC_USER; + } data.ip = at->from; data.addr = at->to;Why not key off of the from? If its a jump from userspace its a user event, its a jump from kernel space its a kernel event?
Quoted 1 line
Of course, originally, perf does that.
I don't think it does.
Quoted 3 lines
And, in those cases,
BTS records the both addresses of kernel and user in oneperf_sampleon branches from kernel to user.
Quoted 8 lines
Sorry, I don't get this.
Quoted 1 line
Current perf sets
PERF_RECORD_MISC_KERNELto all BTS events,It doesn't, it does something far more stupid.. it sets the state to wherever we were when the BTS overflow interrupt happens. If that was in kernel space, we mark all of them as in-kernel, if that was in user-space we mark all of then in-user.
Normally, perf does. However, BTS (intel_pmu_drain_bts_buffer) uses local-defined and not-initialized pt_regs to decide PERF_RECORD_MISC_KERNEL or USER. Accordingly, almost all BTS events are set PERF_RECORD_MISC_KERNEL.
BTW, I think it's a bug that uses not-initialized pt_regs. So, it needs initialize:
- struct pt_regs regs;
+ struct pt_regs regs = {0};
Or, intel_pmu_drain_bts_buffer() get pt_regs from a function argument.
- int intel_pmu_drain_bts_buffer(void)
+ int intel_pmu_drain_bts_buffer(struct pt_regs *regs)
Quoted 7 lines
Quoted 4 lines
and
perf-script doesn't resolve symbols and DSOs about the user-space address, because it is a kernel event.Well, that's a perf-script problem, not something you should change the kernel for.
Exactly. I'm going to fix perf-script.
Quoted 15 lines
So how about something like this?
--- arch/x86/kernel/cpu/perf_event_intel_ds.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-)arch/x86/kernel/cpu/perf_event_intel_ds.c +0
-0@@ -333,6 +333,13 @@ int intel_pmu_drain_bts_buffer(void) data.ip = at->from; data.addr = at->to;
arch/x86/kernel/cpu/perf_event_intel_ds.c int intel_pmu_drain_bts_buffer(void) · line 344
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_ds.c +7
-0+/* XXX doesn't do virt muck properly */ + header.misc&= ~PERF_RECORD_MISC_CPUMODE_MASK ; +if (kernel_ip (at->from)) + header.misc |=PERF_RECORD_MISC_KERNEL ; +else + header.misc |=PERF_RECORD_MISC_USER ; +perf_output_sample (&handle,&header,&data, event); }
It looks good. I think it's correct semantically to set PERF_RECORD_MISC_KERNEL or USER by the from-address. However, this patch needs perf-script fix too. I'm going to send next patches including this patch.
Thank you,
PATCH v5 3/5 perf script: print branch_from and branch_to of BTS events
In reply to Akihiro NagaiBTS records branch_from_addr and branch_to_addr in IP and ADDR field in perf_sample. This patch enables to print them in following format,
<from_addr> <from_symbol> (<from_dso>) => <to_addr> <to_symbol> (<to_dso>)
Sample:
# perf script -f ip,addr,dso,sym
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e016b0 _start (/lib64/ld-2.14.so)
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e016b0 _start (/lib64/ld-2.14.so)
3f03e016b3 _start (/lib64/ld-2.14.so) => 3f03e04b80 _dl_start (/lib64/ld-2.14.so)
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e04b80 _dl_start (/lib64/ld-2.14.so)
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e04ba6 _dl_start (/lib64/ld-2.14.so)
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e04bad _dl_start (/lib64/ld-2.14.so)
3f03e04bfb _dl_start (/lib64/ld-2.14.so) => 3f03e04c1d _dl_start (/lib64/ld-2.14.so)
[snip]Changes in v5:
- Change the output format "<branch_to> <branch_from>" to "<branch_from> => <branch_to>"
---
tools/perf/builtin-script.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 42 insertions(+), 0 deletions(-)
tools/perf/builtin-script.c +42 -0
@@ -304,6 +304,13 @@ static void print_sample_start(struct perf_sample *sample, } } +static bool is_bts_event (struct perf_event_attr *attr) +{ +return ((attr->type ==PERF_TYPE_HARDWARE ) && + (attr->config &PERF_COUNT_HW_BRANCH_INSTRUCTIONS ) && + (attr->sample_period ==1 )); +} +static bool sample_addr_correlates_sym (struct perf_event_attr *attr) { if ((attr->type == PERF_TYPE_SOFTWARE) &&
@@ -312,6 +319,9 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr) (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))return true; +if (is_bts_event (attr)) +return true; +return false; }
@@ -353,6 +363,33 @@ static void print_sample_addr(union perf_event *event, } } +static void print_sample_bts (union perf_event *event, +struct perf_sample *sample, +struct perf_evsel *evsel, +struct machine *machine, +struct thread *thread) +{ +struct perf_event_attr *attr = &evsel->attr; + +/* print branch_from information */ +if (PRINT_FIELD (IP )) { +if (!symbol_conf.use_callchain) +printf (" " ); +else +printf ("\n" ); +perf_event__print_ip (event, sample, machine, evsel, +PRINT_FIELD (SYM ),PRINT_FIELD (DSO )); + } + +printf (" => " ); + +/* print branch_to information */ +if (PRINT_FIELD (ADDR )) +print_sample_addr (event, sample, machine, thread, attr); + +printf ("\n" ); +} + static void process_event(union perf_event *event __unused, struct perf_sample *sample, struct perf_evsel *evsel,
@@ -366,6 +403,11 @@ static void process_event(union perf_event *event __unused,print_sample_start (sample, thread, attr); +if (is_bts_event (attr)) { +print_sample_bts (event, sample, evsel, machine, thread); +return ; + } +if (PRINT_FIELD (TRACE ))print_trace_event (sample->cpu, sample->raw_data, sample->raw_size);
[tip:perf/core] perf script: Print branch_from and branch_to of BTS events
Commit-ID: 9558259697b827106b464648e850e568e0b0c931 Gitweb: http://git.kernel.org/tip/9558259697b827106b464648e850e568e0b0c931 Author: Akihiro Nagai <[email protected]> AuthorDate: Mon, 30 Jan 2012 13:43:09 +0900 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Mon, 30 Jan 2012 18:08:43 -0200
perf script: Print branch_from and branch_to of BTS events
BTS records branch_from_addr and branch_to_addr in IP and ADDR field in perf_sample. This patch enables to print them in following format,
<from_addr> <from_symbol> (<from_dso>) => <to_addr> <to_symbol> (<to_dso>)
Sample:
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e016b0 _start (/lib64/ld-2.14.so)
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e016b0 _start (/lib64/ld-2.14.so)
3f03e016b3 _start (/lib64/ld-2.14.so) => 3f03e04b80 _dl_start (/lib64/ld-2.14.so)
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e04b80 _dl_start (/lib64/ld-2.14.so)
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e04ba6 _dl_start (/lib64/ld-2.14.so)
ffffffff814675d2 irq_return ([kernel.kallsyms]) => 3f03e04bad _dl_start (/lib64/ld-2.14.so)
3f03e04bfb _dl_start (/lib64/ld-2.14.so) => 3f03e04c1d _dl_start (/lib64/ld-2.14.so)[snip]
--- tools/perf/builtin-script.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 42 insertions(+), 0 deletions(-)
tools/perf/builtin-script.c +42 -0
@@ -304,6 +304,13 @@ static void print_sample_start(struct perf_sample *sample, } } +static bool is_bts_event (struct perf_event_attr *attr) +{ +return ((attr->type ==PERF_TYPE_HARDWARE ) && + (attr->config &PERF_COUNT_HW_BRANCH_INSTRUCTIONS ) && + (attr->sample_period ==1 )); +} +static bool sample_addr_correlates_sym (struct perf_event_attr *attr) { if ((attr->type == PERF_TYPE_SOFTWARE) &&
@@ -312,6 +319,9 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr) (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))return true; +if (is_bts_event (attr)) +return true; +return false; }
@@ -353,6 +363,33 @@ static void print_sample_addr(union perf_event *event, } } +static void print_sample_bts (union perf_event *event, +struct perf_sample *sample, +struct perf_evsel *evsel, +struct machine *machine, +struct thread *thread) +{ +struct perf_event_attr *attr = &evsel->attr; + +/* print branch_from information */ +if (PRINT_FIELD (IP )) { +if (!symbol_conf.use_callchain) +printf (" " ); +else +printf ("\n" ); +perf_event__print_ip (event, sample, machine, evsel, +PRINT_FIELD (SYM ),PRINT_FIELD (DSO )); + } + +printf (" => " ); + +/* print branch_to information */ +if (PRINT_FIELD (ADDR )) +print_sample_addr (event, sample, machine, thread, attr); + +printf ("\n" ); +} + static void process_event(union perf_event *event __unused, struct perf_sample *sample, struct perf_evsel *evsel,
@@ -366,6 +403,11 @@ static void process_event(union perf_event *event __unused,print_sample_start (sample, thread, attr); +if (is_bts_event (attr)) { +print_sample_bts (event, sample, evsel, machine, thread); +return ; + } +if (PRINT_FIELD (TRACE ))print_trace_event (sample->cpu, sample->raw_data, sample->raw_size);
PATCH v5 4/5 perf script: add the offset field specifier
In reply to Akihiro NagaiAdd the offset field specifier 'symoff' to show the offset from the symbols in the output of perf-script. We can get the more detailed address information.
Output sample:
# perf script -f ip,addr,sym,symoff
ffffffff81467612 irq_return+0x0 => 301ec016b0 _start+0x0
ffffffff81467612 irq_return+0x0 => 301ec016b0 _start+0x0
301ec016b3 _start+0x3 => 301ec04b70 _dl_start+0x0
ffffffff81467612 irq_return+0x0 => 301ec04b70 _dl_start+0x0
ffffffff81467612 irq_return+0x0 => 301ec04b96 _dl_start+0x26
ffffffff81467612 irq_return+0x0 => 301ec04b9d _dl_start+0x2d
301ec04beb _dl_start+0x7b => 301ec04c0d _dl_start+0x9d
301ec04c11 _dl_start+0xa1 => 301ec04bf0 _dl_start+0x80
[snip]Changes in v5:
- rename offset specifier 'offs' to 'symoff'
Changes in v2:
- change the way to output offset from '--show-symbol-offset' to 'offs' field.
- clean up codes.
---
tools/perf/Documentation/perf-script.txt | 2 +- tools/perf/builtin-script.c | 23 +++++++++++++++++++---- tools/perf/util/session.c | 8 ++++++-- tools/perf/util/session.h | 2 +- tools/perf/util/symbol.c | 24 +++++++++++++++++------- tools/perf/util/symbol.h | 2 ++ 6 files changed, 46 insertions(+), 15 deletions(-)
tools/perf/Documentation/perf-script.txt +1 -1
@@ -115,7 +115,7 @@ OPTIONS -f:: --fields:: Comma separated list of fields to print. Options are: - comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr. + comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff. Field list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
tools/perf/builtin-script.c +19 -4
@@ -40,6 +40,7 @@ enum perf_output_field {PERF_OUTPUT_SYM =1U <<8 ,PERF_OUTPUT_DSO =1U <<9 ,PERF_OUTPUT_ADDR =1U <<10 , + PERF_OUTPUT_SYMOFFSET = 1U << 11, }; struct output_option {
@@ -57,6 +58,7 @@ struct output_option { {.str = "sym", .field = PERF_OUTPUT_SYM}, {.str = "dso", .field = PERF_OUTPUT_DSO}, {.str = "addr", .field = PERF_OUTPUT_ADDR}, + {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, };/* default set to maintain compatibility with current format */
@@ -193,6 +195,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, "to symbols.\n");return -EINVAL ; } +if (PRINT_FIELD (SYMOFFSET ) && !PRINT_FIELD (SYM )) { +pr_err ("Display of offsets requested but symbol is not" +"selected.\n" ); +return -EINVAL ; + }if (PRINT_FIELD (DSO ) && !PRINT_FIELD (IP ) && !PRINT_FIELD (ADDR )) {pr_err ("Display of DSO requested but neither sample IP nor " "sample address\nis selected. Hence, no addresses to convert "
@@ -353,7 +360,10 @@ static void print_sample_addr(union perf_event *event,if (PRINT_FIELD (SYM )) {printf (" " ); -symbol__fprintf_symname (al.sym, stdout); +if (PRINT_FIELD (SYMOFFSET )) +symbol__fprintf_symname_offs (al.sym, &al, stdout); +else +symbol__fprintf_symname (al.sym, stdout); }if (PRINT_FIELD (DSO )) {
@@ -378,7 +388,8 @@ static void print_sample_bts(union perf_event *event,else printf ("\n" );perf_event__print_ip (event, sample, machine, evsel, -PRINT_FIELD (SYM ),PRINT_FIELD (DSO )); +PRINT_FIELD (SYM ),PRINT_FIELD (DSO ), +PRINT_FIELD (SYMOFFSET )); }printf (" => " );
@@ -421,7 +432,8 @@ static void process_event(union perf_event *event __unused,else printf ("\n" );perf_event__print_ip (event, sample, machine, evsel, -PRINT_FIELD (SYM ),PRINT_FIELD (DSO )); +PRINT_FIELD (SYM ),PRINT_FIELD (DSO ), +PRINT_FIELD (SYMOFFSET )); }printf ("\n" );
@@ -1131,7 +1143,10 @@ static const struct option options[] = {OPT_STRING (0 ,"symfs" , &symbol_conf.symfs,"directory" ,"Look for files with symbols relative to this directory" ),OPT_CALLBACK ('f' ,"fields" ,NULL ,"str" , -"comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr" , +"comma separated output fields prepend with 'type:'. " +"Valid types: hw,sw,trace,raw. " +"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," +"addr,symoff" , parse_output_fields),OPT_BOOLEAN ('a' ,"all-cpus" , &system_wide, "system-wide collection from all CPUs"),
tools/perf/util/session.c +6 -2
@@ -1293,7 +1293,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,void perf_event__print_ip (union perf_event *event,struct perf_sample *sample,struct machine *machine,struct perf_evsel *evsel, -int print_sym,int print_dso) +int print_sym,int print_dso,int print_symoffset) {struct addr_location al;struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
@@ -1340,7 +1340,11 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,printf ("%16" PRIx64, sample->ip);if (print_sym) {printf (" " ); -symbol__fprintf_symname (al.sym, stdout); +if (print_symoffset) +symbol__fprintf_symname_offs (al.sym, &al, + stdout); +else +symbol__fprintf_symname (al.sym, stdout); }if (print_dso) {
tools/perf/util/session.h +1 -1
@@ -147,7 +147,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,void perf_event__print_ip (union perf_event *event,struct perf_sample *sample,struct machine *machine,struct perf_evsel *evsel, -int print_sym,int print_dso); +int print_sym,int print_dso,int print_symoffset);int perf_session__cpu_bitmap (struct perf_session *session,const char *cpu_list,unsigned long *cpu_bitmap);
tools/perf/util/symbol.c +17 -7
@@ -264,16 +264,26 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp) sym->name); } -size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp) +size_t symbol__fprintf_symname_offs (const struct symbol *sym, +const struct addr_location *al,FILE *fp) { -const char *symname; +unsigned long offset; +size_t length; -if (sym && sym->name) - symname = sym->name; -else - symname ="[unknown]" ; +if (sym && sym->name) { + length =fprintf (fp,"%s" , sym->name); +if (al) { + offset = al->addr - sym->start; + length +=fprintf (fp,"+0x%lx" , offset); + } +return length; + }else +return fprintf (fp,"[unknown]" ); +} -return fprintf (fp,"%s" , symname); +size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp) +{ +return symbol__fprintf_symname_offs (sym,NULL , fp); }void dso__set_long_name (struct dso *dso,char *name)
tools/perf/util/symbol.h +2 -0
@@ -241,6 +241,8 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);int symbol__init (void );void symbol__exit (void ); +size_t symbol__fprintf_symname_offs (const struct symbol *sym, +const struct addr_location *al,FILE *fp);size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp);bool symbol_type__is_a (char symbol_type,enum map_type map_type);
[tip:perf/core] perf script: Add the offset field specifier
Commit-ID: a978f2ab4166a84c77d0f846f59690f2a892d058 Gitweb: http://git.kernel.org/tip/a978f2ab4166a84c77d0f846f59690f2a892d058 Author: Akihiro Nagai <[email protected]> AuthorDate: Mon, 30 Jan 2012 13:43:15 +0900 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Mon, 30 Jan 2012 18:09:21 -0200
perf script: Add the offset field specifier
Add the offset field specifier 'symoff' to show the offset from the symbols in the output of perf-script. We can get the more detailed address information.
Output sample:ffffffff81467612 irq_return+0x0 => 301ec016b0 _start+0x0 ffffffff81467612 irq_return+0x0 => 301ec016b0 _start+0x0
301ec016b3 _start+0x3 => 301ec04b70 _dl_start+0x0
ffffffff81467612 irq_return+0x0 => 301ec04b70 _dl_start+0x0
ffffffff81467612 irq_return+0x0 => 301ec04b96 _dl_start+0x26
ffffffff81467612 irq_return+0x0 => 301ec04b9d _dl_start+0x2d
301ec04beb _dl_start+0x7b => 301ec04c0d _dl_start+0x9d
301ec04c11 _dl_start+0xa1 => 301ec04bf0 _dl_start+0x80[snip]
--- tools/perf/Documentation/perf-script.txt | 2 +- tools/perf/builtin-script.c | 23 +++++++++++++++++++---- tools/perf/util/session.c | 8 ++++++-- tools/perf/util/session.h | 2 +- tools/perf/util/symbol.c | 26 ++++++++++++++++++-------- tools/perf/util/symbol.h | 2 ++ 6 files changed, 47 insertions(+), 16 deletions(-)
tools/perf/Documentation/perf-script.txt +1 -1
@@ -115,7 +115,7 @@ OPTIONS -f:: --fields:: Comma separated list of fields to print. Options are: - comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr. + comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff. Field list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
tools/perf/builtin-script.c +19 -4
@@ -40,6 +40,7 @@ enum perf_output_field {PERF_OUTPUT_SYM =1U <<8 ,PERF_OUTPUT_DSO =1U <<9 ,PERF_OUTPUT_ADDR =1U <<10 , + PERF_OUTPUT_SYMOFFSET = 1U << 11, }; struct output_option {
@@ -57,6 +58,7 @@ struct output_option { {.str = "sym", .field = PERF_OUTPUT_SYM}, {.str = "dso", .field = PERF_OUTPUT_DSO}, {.str = "addr", .field = PERF_OUTPUT_ADDR}, + {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, };/* default set to maintain compatibility with current format */
@@ -193,6 +195,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, "to symbols.\n");return -EINVAL ; } +if (PRINT_FIELD (SYMOFFSET ) && !PRINT_FIELD (SYM )) { +pr_err ("Display of offsets requested but symbol is not" +"selected.\n" ); +return -EINVAL ; + }if (PRINT_FIELD (DSO ) && !PRINT_FIELD (IP ) && !PRINT_FIELD (ADDR )) {pr_err ("Display of DSO requested but neither sample IP nor " "sample address\nis selected. Hence, no addresses to convert "
@@ -353,7 +360,10 @@ static void print_sample_addr(union perf_event *event,if (PRINT_FIELD (SYM )) {printf (" " ); -symbol__fprintf_symname (al.sym, stdout); +if (PRINT_FIELD (SYMOFFSET )) +symbol__fprintf_symname_offs (al.sym, &al, stdout); +else +symbol__fprintf_symname (al.sym, stdout); }if (PRINT_FIELD (DSO )) {
@@ -378,7 +388,8 @@ static void print_sample_bts(union perf_event *event,else printf ("\n" );perf_event__print_ip (event, sample, machine, evsel, -PRINT_FIELD (SYM ),PRINT_FIELD (DSO )); +PRINT_FIELD (SYM ),PRINT_FIELD (DSO ), +PRINT_FIELD (SYMOFFSET )); }printf (" => " );
@@ -421,7 +432,8 @@ static void process_event(union perf_event *event __unused,else printf ("\n" );perf_event__print_ip (event, sample, machine, evsel, -PRINT_FIELD (SYM ),PRINT_FIELD (DSO )); +PRINT_FIELD (SYM ),PRINT_FIELD (DSO ), +PRINT_FIELD (SYMOFFSET )); }printf ("\n" );
@@ -1131,7 +1143,10 @@ static const struct option options[] = {OPT_STRING (0 ,"symfs" , &symbol_conf.symfs,"directory" ,"Look for files with symbols relative to this directory" ),OPT_CALLBACK ('f' ,"fields" ,NULL ,"str" , -"comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr" , +"comma separated output fields prepend with 'type:'. " +"Valid types: hw,sw,trace,raw. " +"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," +"addr,symoff" , parse_output_fields),OPT_BOOLEAN ('a' ,"all-cpus" , &system_wide, "system-wide collection from all CPUs"),
tools/perf/util/session.c +6 -2
@@ -1293,7 +1293,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,void perf_event__print_ip (union perf_event *event,struct perf_sample *sample,struct machine *machine,struct perf_evsel *evsel, -int print_sym,int print_dso) +int print_sym,int print_dso,int print_symoffset) {struct addr_location al;struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
@@ -1340,7 +1340,11 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,printf ("%16" PRIx64, sample->ip);if (print_sym) {printf (" " ); -symbol__fprintf_symname (al.sym, stdout); +if (print_symoffset) +symbol__fprintf_symname_offs (al.sym, &al, + stdout); +else +symbol__fprintf_symname (al.sym, stdout); }if (print_dso) {
tools/perf/util/session.h +1 -1
@@ -147,7 +147,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,void perf_event__print_ip (union perf_event *event,struct perf_sample *sample,struct machine *machine,struct perf_evsel *evsel, -int print_sym,int print_dso); +int print_sym,int print_dso,int print_symoffset);int perf_session__cpu_bitmap (struct perf_session *session,const char *cpu_list,unsigned long *cpu_bitmap);
tools/perf/util/symbol.c +17 -7
@@ -263,16 +263,26 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp) sym->name); } -size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp) +size_t symbol__fprintf_symname_offs (const struct symbol *sym, +const struct addr_location *al,FILE *fp) { -const char *symname; +unsigned long offset; +size_t length; -if (sym && sym->name) - symname = sym->name; -else - symname ="[unknown]" ; +if (sym && sym->name) { + length =fprintf (fp,"%s" , sym->name); +if (al) { + offset = al->addr - sym->start; + length +=fprintf (fp,"+0x%lx" , offset); + } +return length; + }else +return fprintf (fp,"[unknown]" ); +} -return fprintf (fp,"%s" , symname); +size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp) +{ +return symbol__fprintf_symname_offs (sym,NULL , fp); }void dso__set_long_name (struct dso *dso,char *name)
tools/perf/util/symbol.h +2 -0
@@ -241,6 +241,8 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);int symbol__init (void );void symbol__exit (void ); +size_t symbol__fprintf_symname_offs (const struct symbol *sym, +const struct addr_location *al,FILE *fp);size_t symbol__fprintf_symname (const struct symbol *sym,FILE *fp);bool symbol_type__is_a (char symbol_type,enum map_type map_type);
PATCH v5 5/5 perf script: add option resolving vmlinux path
In reply to Akihiro NagaiAdd the option get the path of [kernel.kallsyms]. Specify '--show-kernel-path' option to use this function. This patch enables other applications to use this output easily.
Without --show-kernel-path option
# perf script -f ip,dso
ffffffff81467612 irq_return ([kernel.kallsyms])
ffffffff81467612 irq_return ([kernel.kallsyms])
7f24fc02a6b3 _start (/lib64/ld-2.14.so)
[snip]With --show-kernel-path option
# perf script -f ip,dso --show-kernel-path
ffffffff81467612 irq_return (/lib/modules/3.2.0+/build/vmlinux)
ffffffff81467612 irq_return (/lib/modules/3.2.0+/build/vmlinux)
7f24fc02a6b3 _start (/lib64/ld-2.14.so)
[snip]---
tools/perf/Documentation/perf-script.txt | 3 +++ tools/perf/builtin-script.c | 3 +++ tools/perf/util/map.c | 9 ++++++--- tools/perf/util/symbol.h | 1 + 4 files changed, 13 insertions(+), 3 deletions(-)
tools/perf/Documentation/perf-script.txt +3 -0
@@ -200,6 +200,9 @@ OPTIONS It currently includes: cpu and numa topology of the host system. It can only be used with the perf script report mode. +--show-kernel-path:: + Try to resolve the path of [kernel.kallsyms] + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-script-perl[1],
tools/perf/builtin-script.c +3 -0
@@ -1155,6 +1155,9 @@ static const struct option options[] = { "only display events for these comms"),OPT_BOOLEAN ('I' ,"show-info" , &show_full_info,"display extended information from perf.data file" ), +OPT_BOOLEAN ('\0' ,"show-kernel-path" , &symbol_conf.show_kernel_path, +"Show the path of [kernel.kallsyms]" ), + OPT_END() };
tools/perf/util/map.c +6 -3
@@ -216,9 +216,12 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) {const char *dsoname; -if (map && map->dso && map->dso->name) - dsoname = map->dso->name; -else +if (map && map->dso && (map->dso->name || map->dso->long_name)) { +if (symbol_conf.show_kernel_path && map->dso->long_name) + dsoname = map->dso->long_name; +else if (map->dso->name) + dsoname = map->dso->name; + }else dsoname ="[unknown]" ;return fprintf (fp,"%s" , dsoname);
tools/perf/util/symbol.h +1 -0
@@ -70,6 +70,7 @@ struct symbol_conf {unsigned short priv_size;unsigned short nr_events;bool try_vmlinux_path, + show_kernel_path, use_modules, sort_by_name, show_nr_samples,
[tip:perf/core] perf script: Add option resolving vmlinux path
Commit-ID: 0bc8d20580af74c9a8a39c200e269261e5cded05 Gitweb: http://git.kernel.org/tip/0bc8d20580af74c9a8a39c200e269261e5cded05 Author: Akihiro Nagai <[email protected]> AuthorDate: Mon, 30 Jan 2012 13:43:20 +0900 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Mon, 30 Jan 2012 18:13:07 -0200
perf script: Add option resolving vmlinux path
Add the option get the path of [kernel.kallsyms]. Specify '--show-kernel-path' option to use this function. This patch enables other applications to use this output easily.
Without --show-kernel-path option
ffffffff81467612 irq_return ([kernel.kallsyms])ffffffff81467612 irq_return ([kernel.kallsyms])
7f24fc02a6b3 _start (/lib64/ld-2.14.so)
[snip]
With --show-kernel-path option
ffffffff81467612 irq_return (/lib/modules/3.2.0+/build/vmlinux) ffffffff81467612 irq_return (/lib/modules/3.2.0+/build/vmlinux)
7f24fc02a6b3 _start (/lib64/ld-2.14.so)
[snip]
--- tools/perf/Documentation/perf-script.txt | 3 +++ tools/perf/builtin-script.c | 3 +++ tools/perf/util/map.c | 9 ++++++--- tools/perf/util/symbol.h | 1 + 4 files changed, 13 insertions(+), 3 deletions(-)
tools/perf/Documentation/perf-script.txt +3 -0
@@ -200,6 +200,9 @@ OPTIONS It currently includes: cpu and numa topology of the host system. It can only be used with the perf script report mode. +--show-kernel-path:: + Try to resolve the path of [kernel.kallsyms] + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-script-perl[1],
tools/perf/builtin-script.c +3 -0
@@ -1155,6 +1155,9 @@ static const struct option options[] = { "only display events for these comms"),OPT_BOOLEAN ('I' ,"show-info" , &show_full_info,"display extended information from perf.data file" ), +OPT_BOOLEAN ('\0' ,"show-kernel-path" , &symbol_conf.show_kernel_path, +"Show the path of [kernel.kallsyms]" ), + OPT_END() };
tools/perf/util/map.c +6 -3
@@ -216,9 +216,12 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) {const char *dsoname; -if (map && map->dso && map->dso->name) - dsoname = map->dso->name; -else +if (map && map->dso && (map->dso->name || map->dso->long_name)) { +if (symbol_conf.show_kernel_path && map->dso->long_name) + dsoname = map->dso->long_name; +else if (map->dso->name) + dsoname = map->dso->name; + }else dsoname ="[unknown]" ;return fprintf (fp,"%s" , dsoname);
tools/perf/util/symbol.h +1 -0
@@ -70,6 +70,7 @@ struct symbol_conf {unsigned short priv_size;unsigned short nr_events;bool try_vmlinux_path, + show_kernel_path, use_modules, sort_by_name, show_nr_samples,