Skip to contentSkip to conversation

perf script: add BTS analysis features

PATCH In review Akihiro Nagai 2 participants 14 messages Jan 30, 2012 – Mar 16, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

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])
#1 lore raw

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

Cc Peter Zijlstra <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc David Ahern <[email protected]>
Cc Masami Hiramatsu <[email protected]>

---

 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
index bb68ddf..add13ec 100644
@@ -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
index 316aa0a..1107960 100644
@@ -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
index 2b8017f..b100c20 100644
@@ -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
index b5ca255..e5334a9 100644
@@ -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
index 215d50f..2d04290 100644
@@ -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
index 123c2e1..d349c7a 100644
@@ -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);
#2 lore raw

[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
index bb68ddf..add13ec 100644
@@ -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
index 316aa0a..1107960 100644
@@ -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
index 2b8017f..b100c20 100644
@@ -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
index b5ca255..e5334a9 100644
@@ -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
index 0975438..b580fa8 100644
@@ -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
index 123c2e1..d349c7a 100644
@@ -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);
#3 lore raw

PATCH v5 2/5 perf: set correct value to perf_event_header.misc for BTS

In reply to Akihiro Nagai

Set 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

Cc Peter Zijlstra <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc David Ahern <[email protected]>
Cc Masami Hiramatsu <[email protected]>

---

 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
index 73da6b6..2f99597 100644
@@ -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);
maintainer
#4 lore raw

Re: [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?

#5 lore raw

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 -0
         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;

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,

maintainer
#6 lore raw

Re: [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 -0
         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;

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 one perf_sample on branches from kernel to user.

Sorry, I don't get this.

Quoted 1 line

Current perf sets PERF_RECORD_MISC_KERNEL to 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);
 	}
 
#7 lore raw

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 -0
          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;

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 one perf_sample on branches from kernel to user.

Quoted 8 lines

Sorry, I don't get this.

Quoted 1 line

Current perf sets PERF_RECORD_MISC_KERNEL to 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
index d6bd49f..81e788c 100644
@@ -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,

#8 lore raw

PATCH v5 3/5 perf script: print branch_from and branch_to of BTS events

In reply to Akihiro Nagai

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:

# 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>"

Cc Peter Zijlstra <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc David Ahern <[email protected]>
Cc Masami Hiramatsu <[email protected]>

---

 tools/perf/builtin-script.c |   42 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 42 insertions(+), 0 deletions(-)
tools/perf/builtin-script.c +42 -0
index add13ec..414d49a 100644
@@ -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);
#9 lore raw

[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
index add13ec..414d49a 100644
@@ -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);
#10 lore raw

PATCH v5 4/5 perf script: add the offset field specifier

In reply to Akihiro Nagai

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:

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

Cc Peter Zijlstra <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc David Ahern <[email protected]>
Cc Masami Hiramatsu <[email protected]>

---

 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
index 2f6cef4..228c7bb 100644
@@ -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
index 414d49a..752d401 100644
@@ -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
index e5334a9..552c1c5 100644
@@ -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
index 37bc383..c8d9017 100644
@@ -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
index 2d04290..7cfbd69 100644
@@ -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
index d349c7a..ba909c9 100644
@@ -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);
 
#11 lore raw

[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
index 2f6cef4..228c7bb 100644
@@ -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
index 414d49a..752d401 100644
@@ -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
index e5334a9..552c1c5 100644
@@ -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
index 37bc383..c8d9017 100644
@@ -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
index b580fa8..fc6e12f 100644
@@ -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
index d349c7a..ba909c9 100644
@@ -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);
 
#12 lore raw

PATCH v5 5/5 perf script: add option resolving vmlinux path

In reply to Akihiro Nagai

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

# 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]
Cc Peter Zijlstra <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc David Ahern <[email protected]>
Cc Masami Hiramatsu <[email protected]>

---

 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
index 228c7bb..e9cbfcd 100644
@@ -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
index 752d401..d4ce733 100644
@@ -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
index 1107960..dea6d1c 100644
@@ -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
index ba909c9..2a683d4 100644
@@ -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,
#13 lore raw

[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
index 228c7bb..e9cbfcd 100644
@@ -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
index 752d401..d4ce733 100644
@@ -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
index 1107960..dea6d1c 100644
@@ -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
index ba909c9..2a683d4 100644
@@ -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,