Skip to contentSkip to conversation

perf script: add BTS analysis features

PATCH Superseded Akihiro Nagai 4 participants 15 messages Jan 16, 2012 – Jan 20, 2012

Subsystems (2)

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v4 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 4.
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 'offs' 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,offs,dso [--show-kernel-path]
This command's output format is:
<branch_to addr> <branch_to function+offset> <branch_to DSO> <branch_from addr> <branch_from function+offset> <branch_from DSO>

Output sample:

# perf record -e branches:u -c 1 -d ls
[snip]
# perf script -f ip,addr,sym,dso,offs --show-kernel-path
[snip]
402c1c main+0x0             (/root/bin/ls)       3430c21399 __libc_start_main+0xe9 (/lib64/libc-2.14.so)
40b390 set_program_name+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)
401e20 strrchr@plt+0x0      (/root/bin/ls)           40b39e set_program_name+0xe   (/root/bin/ls)
401e26 strrchr@plt+0x6      (/root/bin/ls)           401e20 strrchr@plt+0x0        (/root/bin/ls)
401b80 _init+0x18           (/root/bin/ls)           401e2b strrchr@plt+0xb        (/root/bin/ls)
3430813850 _dl_runtime_resolve+0x0 (/lib64/ld-2.14.so) 401b86 _init+0x1e           (/root/bin/ls)
[snip]

It shows the tracee application's execution path.

TODO:
- 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 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: enhance IP and ADDR correlate detection for BTS
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               |   45 +++++++++++++++++++----------
 tools/perf/util/map.c                     |   15 ++++++++++
 tools/perf/util/map.h                     |    1 +
 tools/perf/util/session.c                 |   38 ++++++++----------------
 tools/perf/util/session.h                 |    2 +
 tools/perf/util/symbol.c                  |   20 +++++++++++++
 tools/perf/util/symbol.h                  |    4 +++
 9 files changed, 108 insertions(+), 53 deletions(-)
Signature · 1 line
Akihiro Nagai ([email protected])
#1 lore raw

PATCH v4 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 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..11859eb 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__print_symname(al.sym);
 	}
 
 	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__print_dsoname(al.map);
+		printf(")");
 	}
 }
 
tools/perf/util/map.c +12 -0
index 316aa0a..4c95fac 100644
@@ -212,6 +212,18 @@ size_t map__fprintf(struct map *self, FILE *fp)
 		       self->start, self->end, self->pgoff, self->dso->name);
 }
 
+void map__print_dsoname(struct map *self)
+{
+	const char *dsoname;
+
+	if (self && self->dso && self->dso->name)
+		dsoname = self->dso->name;
+	else
+		dsoname = "[unknown]";
+
+	printf("%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..53fb713 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);
+void map__print_dsoname(struct map *self);
 
 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..aad26b3 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__print_symname(node->sym);
 			}
 			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__print_dsoname(al.map);
+				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__print_symname(al.sym);
 		}
 
 		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__print_dsoname(al.map);
+			printf(")");
 		}
 	}
 }
tools/perf/util/symbol.c +12 -0
index 215d50f..7d1fb3a 100644
@@ -264,6 +264,18 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
 		       sym->name);
 }
 
+void symbol__print_symname(const struct symbol *sym)
+{
+	const char *symname;
+
+	if (sym && sym->name)
+		symname = sym->name;
+	else
+		symname = "[unknown]";
+
+	printf("%s", symname);
+}
+
 void dso__set_long_name(struct dso *dso, char *name)
 {
 	if (name == NULL)
tools/perf/util/symbol.h +1 -0
index 123c2e1..26be235 100644
@@ -241,6 +241,7 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);
 
 int symbol__init(void);
 void symbol__exit(void);
+void symbol__print_symname(const struct symbol *sym);
 bool symbol_type__is_a(char symbol_type, enum map_type map_type);
 
 size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
Reviewed-by on v4 1/5
#2 lore raw

Re: [PATCH -tip v4 1/5] perf-script: unify the expressions indicate "unknown"

Quoted 10 lines · Akihiro Nagai

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 v3:
- unify all expressions to [unknown]

Changes in v2:
- add this patch

#3 lore raw

Re: [PATCH -tip v4 1/5] perf-script: unify the expressions indicate "unknown"

In reply to Akihiro Nagai

Em Mon, Jan 16, 2012 at 02:22:10PM +0900, Akihiro Nagai escreveu:

tools/perf/util/map.h void map__delete(struct map *self); · line 119

Quoted 8 lines

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]".

tools/perf/util/map.h +1 -0
@@ -118,6 +118,7 @@ void map__delete(struct map *self);
 size_t map__fprintf(struct map *self, FILE *fp);
+void map__print_dsoname(struct map *self);

See map__fprintf(), everything that is for printing to a file like output has that form: last paramenter is a FILE pointer, then users do:

   map__fprintf_dsoname(map, stdout);

or to stderr, or to something else, like in cases where tools have a 'strace -o FILENAME' like switch, like 'perf stat --log-fd N':

OPT_INTEGER(0, "log-fd", &output_fd,
"log output to fd, instead of stderr"),

That uses fdreopen(output_fd), etc.

So please convert these new __print_something methods to __fprintf_something(..., FILE *fp).

Also please don't use 'self' anymore, that was a bad decision I made in perf's early ages and that Thomas Gleixner suggested we use more descriptive names such as, in the above case, 'map', i.e.:

void map__fprintf_dsoname(struct map *map, FILE *fp);

Quoted 1 line

From time to time I convert these 'self' leftovers in areas where I

notice that are not having too much coding activity, to avoid clashing with pending patches, so lets not add more in new code :)

Thanks,

- Arnaldo

#4 lore raw

Re: [PATCH -tip v4 1/5] perf-script: unify the expressions indicate "unknown"

Quoted 30 lines · Arnaldo Carvalho de Melo

Em Mon, Jan 16, 2012 at 02:22:10PM +0900, Akihiro Nagai escreveu:

tools/perf/util/map.h void map__delete(struct map *self); · line 119

Quoted 8 lines

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]".

tools/perf/util/map.h +1 -0
@@ -118,6 +118,7 @@ void map__delete(struct map *self);
  size_t map__fprintf(struct map *self, FILE *fp);
+void map__print_dsoname(struct map *self);

See map__fprintf(), everything that is for printing to a file like output has that form: last paramenter is a FILE pointer, then users do:

    map__fprintf_dsoname(map, stdout);

or to stderr, or to something else, like in cases where tools have a 'strace -o FILENAME' like switch, like 'perf stat --log-fd N':

OPT_INTEGER(0, "log-fd",&output_fd,
"log output to fd, instead of stderr"),

That uses fdreopen(output_fd), etc.

So please convert these new __print_something methods to __fprintf_something(..., FILE *fp).

Also please don't use 'self' anymore, that was a bad decision I made in perf's early ages and that Thomas Gleixner suggested we use more descriptive names such as, in the above case, 'map', i.e.:

Quoted 5 lines
  void map__fprintf_dsoname(struct map *map, FILE *fp);
Quoted 1 line

From time to time I convert these 'self' leftovers in areas where I

notice that are not having too much coding activity, to avoid clashing with pending patches, so lets not add more in new code :)

I see. I'm going to fix and resend my patches,
e.g. map__print_dsoname(self) => map__fprintf_dsoname(map, fp)

Thank you.

Quoted 4 lines

Thanks,

- Arnaldo

#5 lore raw

Re: [PATCH -tip v4 1/5] perf-script: unify the expressions indicate "unknown"

Quoted 2 lines · Akihiro Nagai

I see. I'm going to fix and resend my patches,
e.g. map__print_dsoname(self) => map__fprintf_dsoname(map, fp)

If you are going to redo the patch set I have one request: change the name of the offset field (currently offs in your patch) to symoff to mean offset for the symbol name versus offset in the DSO. It's the latter that I use locally, so symoff would allow both to coexist.

Thanks,

David

#6 lore raw

Re: [PATCH -tip v4 1/5] perf-script: unify the expressions indicate "unknown"

Quoted 8 lines · David Ahern
Quoted 2 lines · Akihiro Nagai

I see. I'm going to fix and resend my patches,
e.g. map__print_dsoname(self) => map__fprintf_dsoname(map, fp)

If you are going to redo the patch set I have one request: change the name of the offset field (currently offs in your patch) to symoff to mean offset for the symbol name versus offset in the DSO. It's the latter that I use locally, so symoff would allow both to coexist.

OK, I'm going to rename 'offs' to 'symoff'.

Thank you.

Quoted 4 lines

Thanks,

David

#7 lore raw

PATCH v4 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);
#8 lore raw

PATCH v4 3/5 perf script: enhance IP and ADDR correlate detection for BTS

In reply to Akihiro Nagai

BTS records branch_from_addr and branch_to_addr in IP and ADDR field in perf_sample. This patch detects this correlation in perf-script.

# perf script -f ip,addr,dso,sym
3f03e016b0    _start (/lib64/ld-2.14.so) ffffffff814675d2 irq_return ([kernel.kallsyms])
3f03e016b0    _start (/lib64/ld-2.14.so) ffffffff814675d2 irq_return ([kernel.kallsyms])
3f03e04b80 _dl_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])
3f03e04ba6 _dl_start (/lib64/ld-2.14.so) ffffffff814675d2 irq_return ([kernel.kallsyms])
3f03e04bad _dl_start (/lib64/ld-2.14.so) ffffffff814675d2 irq_return ([kernel.kallsyms])
3f03e04c1d _dl_start (/lib64/ld-2.14.so)       3f03e04bfb  _dl_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/builtin-script.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
tools/perf/builtin-script.c +6 -0
index 11859eb..360a4da 100644
@@ -312,6 +312,12 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
 	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
 		return true;
 
+	/* BTS Events */
+	if ((attr->type == PERF_TYPE_HARDWARE) &&
+	    (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
+	    (attr->sample_period == 1))
+		return true;
+
 	return false;
 }
 
#9 lore raw

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

In reply to Akihiro Nagai

Add the offset field specifier 'offs' 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,offs
301ec016b0            _start+0x0 ffffffff81467612 irq_return+0x0
301ec016b0            _start+0x0 ffffffff81467612 irq_return+0x0
301ec04b70         _dl_start+0x0       301ec016b3 _start+0x3
301ec04b70         _dl_start+0x0 ffffffff81467612 irq_return+0x0
301ec04b96        _dl_start+0x26 ffffffff81467612 irq_return+0x0
301ec04b9d        _dl_start+0x2d ffffffff81467612 irq_return+0x0
301ec04c0d        _dl_start+0x9d       301ec04beb _dl_start+0x7b
301ec04bf0        _dl_start+0x80       301ec04c11 _dl_start+0xa1
[snip]

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              |   20 +++++++++++++++++---
 tools/perf/util/session.c                |    7 +++++--
 tools/perf/util/session.h                |    2 +-
 tools/perf/util/symbol.c                 |   22 +++++++++++++++-------
 tools/perf/util/symbol.h                 |    2 ++
 6 files changed, 41 insertions(+), 14 deletions(-)
tools/perf/Documentation/perf-script.txt +1 -1
index 2f6cef4..477638a 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, offs.
         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 +17 -3
index 360a4da..e79ec7d 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_OFFSET          = 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 = "offs",  .field = PERF_OUTPUT_OFFSET},
 };
 
 /* 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(OFFSET) && !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 "
@@ -349,7 +356,10 @@ static void print_sample_addr(union perf_event *event,
 
 	if (PRINT_FIELD(SYM)) {
 		printf(" ");
-		symbol__print_symname(al.sym);
+		if (PRINT_FIELD(OFFSET))
+			symbol__print_symname_offs(al.sym, &al);
+		else
+			symbol__print_symname(al.sym);
 	}
 
 	if (PRINT_FIELD(DSO)) {
@@ -385,7 +395,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(OFFSET));
 	}
 
 	printf("\n");
@@ -1095,7 +1106,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,offs",
 		     parse_output_fields),
 	OPT_BOOLEAN('a', "all-cpus", &system_wide,
 		     "system-wide collection from all CPUs"),
tools/perf/util/session.c +5 -2
index aad26b3..c4d1e8b 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_offset)
 {
 	struct addr_location al;
 	struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
@@ -1340,7 +1340,10 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
 		printf("%16" PRIx64, sample->ip);
 		if (print_sym) {
 			printf(" ");
-			symbol__print_symname(al.sym);
+			if (print_offset)
+				symbol__print_symname_offs(al.sym, &al);
+			else
+				symbol__print_symname(al.sym);
 		}
 
 		if (print_dso) {
tools/perf/util/session.h +1 -1
index 37bc383..12b98bf 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_offset);
 
 int perf_session__cpu_bitmap(struct perf_session *session,
 			     const char *cpu_list, unsigned long *cpu_bitmap);
tools/perf/util/symbol.c +15 -7
index 7d1fb3a..4056d36 100644
@@ -264,16 +264,24 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
 		       sym->name);
 }
 
-void symbol__print_symname(const struct symbol *sym)
+void symbol__print_symname_offs(const struct symbol *sym,
+				const struct addr_location *al)
 {
-	const char *symname;
+	unsigned long offset;
 
-	if (sym && sym->name)
-		symname = sym->name;
-	else
-		symname = "[unknown]";
+	if (sym && sym->name) {
+		printf("%s", sym->name);
+		if (al) {
+			offset = al->addr - sym->start;
+			printf("+0x%lx", offset);
+		}
+	} else
+		printf("[unknown]");
+}
 
-	printf("%s", symname);
+void symbol__print_symname(const struct symbol *sym)
+{
+	symbol__print_symname_offs(sym, NULL);
 }
 
 void dso__set_long_name(struct dso *dso, char *name)
tools/perf/util/symbol.h +2 -0
index 26be235..280f477 100644
@@ -241,6 +241,8 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);
 
 int symbol__init(void);
 void symbol__exit(void);
+void symbol__print_symname_offs(const struct symbol *sym,
+				const struct addr_location *al);
 void symbol__print_symname(const struct symbol *sym);
 bool symbol_type__is_a(char symbol_type, enum map_type map_type);
 
Reviewed-by on v4 4/5
#10 lore raw

Re: [PATCH -tip v4 4/5] perf script: add the offset field specifier

Quoted 16 lines · Akihiro Nagai

Add the offset field specifier 'offs' 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,offs
301ec016b0            _start+0x0 ffffffff81467612 irq_return+0x0
301ec016b0            _start+0x0 ffffffff81467612 irq_return+0x0
301ec04b70         _dl_start+0x0       301ec016b3 _start+0x3
301ec04b70         _dl_start+0x0 ffffffff81467612 irq_return+0x0
301ec04b96        _dl_start+0x26 ffffffff81467612 irq_return+0x0
301ec04b9d        _dl_start+0x2d ffffffff81467612 irq_return+0x0
301ec04c0d        _dl_start+0x9d       301ec04beb _dl_start+0x7b
301ec04bf0        _dl_start+0x80       301ec04c11 _dl_start+0xa1
[snip]
Quoted 5 lines

Changes in v2:
- change the way to output offset from '--show-symbol-offset' to 'offs' field.
- clean up codes.

#11 lore raw

PATCH v4 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 477638a..818f6f7 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 e79ec7d..8e1d632 100644
@@ -1118,6 +1118,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 4c95fac..9e47ba0 100644
@@ -216,9 +216,12 @@ void map__print_dsoname(struct map *self)
 {
 	const char *dsoname;
 
-	if (self && self->dso && self->dso->name)
-		dsoname = self->dso->name;
-	else
+	if (self && self->dso && (self->dso->name || self->dso->long_name)) {
+		if (symbol_conf.show_kernel_path && self->dso->long_name)
+			dsoname = self->dso->long_name;
+		else if (self->dso->name)
+			dsoname = self->dso->name;
+	} else
 		dsoname = "[unknown]";
 
 	printf("%s", dsoname);
tools/perf/util/symbol.h +1 -0
index 280f477..cfb16ce 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,
#12 lore raw
In reply to Akihiro Nagai
Quoted 21 lines · Akihiro Nagai

Hi Frederic, David,

This patch series adds the functions to analyze BTS logs to perf-script and, makes perf-script more informative version 4.
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 'offs' 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,offs,dso [--show-kernel-path]
This command's output format is:
<branch_to addr> <branch_to function+offset> <branch_to DSO> <branch_from addr> <branch_from function+offset> <branch_from DSO>
Quoted 6 lines

Output sample:

# perf record -e branches:u -c 1 -d ls
[snip]
# perf script -f ip,addr,sym,dso,offs --show-kernel-path
[snip]
402c1c main+0x0             (/root/bin/ls)       3430c21399 __libc_start_main+0xe9 (/lib64/libc-2.14.so)

I was confused first, looking for the reason why we have a so strange branch flow until I realized the format is "to from".

Can we have "from to" instead? This will be much more intuitive. "from => to" would be even better.

Thanks!

Quoted 7 lines
40b390 set_program_name+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)
401e20 strrchr@plt+0x0      (/root/bin/ls)           40b39e set_program_name+0xe   (/root/bin/ls)
401e26 strrchr@plt+0x6      (/root/bin/ls)           401e20 strrchr@plt+0x0        (/root/bin/ls)
401b80 _init+0x18           (/root/bin/ls)           401e2b strrchr@plt+0xb        (/root/bin/ls)
3430813850 _dl_runtime_resolve+0x0 (/lib64/ld-2.14.so) 401b86 _init+0x1e           (/root/bin/ls)

[snip]

#13 lore raw
Quoted 29 lines · Frederic Weisbecker
Quoted 21 lines · Akihiro Nagai

Hi Frederic, David,

This patch series adds the functions to analyze BTS logs to perf-script and, makes perf-script more informative version 4.
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 'offs' 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,offs,dso [--show-kernel-path]
This command's output format is:
<branch_to addr>  <branch_to function+offset>  <branch_to DSO>  <branch_from addr>  <branch_from function+offset>  <branch_from DSO>
Quoted 6 lines

Output sample:

# perf record -e branches:u -c 1 -d ls
[snip]
# perf script -f ip,addr,sym,dso,offs --show-kernel-path
[snip]
402c1c main+0x0             (/root/bin/ls)       3430c21399 __libc_start_main+0xe9 (/lib64/libc-2.14.so)
Quoted 4 lines

I was confused first, looking for the reason why we have a so strange branch flow until I realized the format is "to from".

Can we have "from to" instead? This will be much more intuitive. "from => to" would be even better.

Exactly.
perf records branch_to information in perf_sample->addr, and branch_from in perf_sample->ip. And, currently I use the generic function: process_event() in builtin-script.c to print branch information. This function prints perf_sample->addr before it prints perf_sample->ip.

So, I'm going to add the bts specialized codes to process_event().

static void process_event(...)

{
    <snip>
    print_sample_start(sample, thread, attr);

    if (is_bts_event(attr)) {
        print_sample_bts(...);
        return;
    }

    if (PRINT_FIELD(TRACE))
    <snip>
}

Thank you.

Quoted 11 lines

Thanks!

Quoted 7 lines
40b390 set_program_name+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)
401e20 strrchr@plt+0x0      (/root/bin/ls)           40b39e set_program_name+0xe   (/root/bin/ls)
401e26 strrchr@plt+0x6      (/root/bin/ls)           401e20 strrchr@plt+0x0        (/root/bin/ls)
401b80 _init+0x18           (/root/bin/ls)           401e2b strrchr@plt+0xb        (/root/bin/ls)
3430813850 _dl_runtime_resolve+0x0 (/lib64/ld-2.14.so) 401b86 _init+0x1e           (/root/bin/ls)

[snip]

#14 lore raw
Quoted 55 lines · Akihiro Nagai
Quoted 29 lines · Frederic Weisbecker
Quoted 21 lines · Akihiro Nagai

Hi Frederic, David,

This patch series adds the functions to analyze BTS logs to perf-script and, makes perf-script more informative version 4.
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 'offs' 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,offs,dso [--show-kernel-path]
This command's output format is:
<branch_to addr>  <branch_to function+offset>  <branch_to DSO>  <branch_from addr>  <branch_from function+offset>  <branch_from DSO>
Quoted 6 lines

Output sample:

# perf record -e branches:u -c 1 -d ls
[snip]
# perf script -f ip,addr,sym,dso,offs --show-kernel-path
[snip]
402c1c main+0x0             (/root/bin/ls)       3430c21399 __libc_start_main+0xe9 (/lib64/libc-2.14.so)
Quoted 4 lines

I was confused first, looking for the reason why we have a so strange branch flow until I realized the format is "to from".

Can we have "from to" instead? This will be much more intuitive. "from => to" would be even better.

Exactly.
perf records branch_to information in perf_sample->addr, and branch_from in perf_sample->ip. And, currently I use the generic function: process_event() in builtin-script.c to print branch information. This function prints perf_sample->addr before it prints perf_sample->ip.

So, I'm going to add the bts specialized codes to process_event().

static void process_event(...)

{
    <snip>
    print_sample_start(sample, thread, attr);

    if (is_bts_event(attr)) {
        print_sample_bts(...);
        return;
    }

    if (PRINT_FIELD(TRACE))
    <snip>
}
Quoted 1 line

Thank you.

You're right, that's a specialization. We need to support well raw formatting like you did and then we can do the specialization incrementally.

Thanks!

Quoted 11 lines
Quoted 11 lines

Thanks!

Quoted 7 lines
40b390 set_program_name+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)
401e20 strrchr@plt+0x0      (/root/bin/ls)           40b39e set_program_name+0xe   (/root/bin/ls)
401e26 strrchr@plt+0x6      (/root/bin/ls)           401e20 strrchr@plt+0x0        (/root/bin/ls)
401b80 _init+0x18           (/root/bin/ls)           401e2b strrchr@plt+0xb        (/root/bin/ls)
3430813850 _dl_runtime_resolve+0x0 (/lib64/ld-2.14.so) 401b86 _init+0x1e           (/root/bin/ls)

[snip]