Skip to contentSkip to conversation

perf, tools: Support srccode output

PATCH In review Andi Kleen 5 participants 8 messages Dec 4, 2018 – Dec 18, 2018 perf events

lore
Share & tools
lore

Andi Kleen

author
#0 lore raw

PATCH 1/1 perf, tools: Support srccode output

From: Andi Kleen <[email protected]>

When looking at PT or brstackinsn traces with perf script it can be very useful to see the source code. This adds a simple facility to print them with perf script, if the information is available through dwarf

% perf record ...
% perf script -F insn,ip,sym,srccode
...

          4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004b3 main

6 v++;

% perf record -b ...
% perf script -F insn,ip,sym,srccode,brstackinsn

...

       main+22:
        0000000000400543        insn: e8 ca ff ff ff            # PRED
|18                     f1();
        f1:
        0000000000400512        insn: 55
|10       {
        0000000000400513        insn: 48 89 e5
        0000000000400516        insn: b8 00 00 00 00
|11             f2();
        000000000040051b        insn: e8 d6 ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00
|6              c = a / b;
        0000000000400500        insn: 8b 0d 2a 0b 20 00
        0000000000400506        insn: 99
        0000000000400507        insn: f7 f9
        0000000000400509        insn: 89 05 29 0b 20 00
        000000000040050f        insn: 90
|7        }
        0000000000400510        insn: 5d
        0000000000400511        insn: c3                        # PRED
        f1+14:
        0000000000400520        insn: b8 00 00 00 00
|12             f2();
        0000000000400525        insn: e8 cc ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00

|6 c = a / b;

Not supported for callchains currently, would need some layout changes there.

---
 tools/perf/Documentation/perf-script.txt |   2 +-
 tools/perf/builtin-script.c              |  47 +++++-
 tools/perf/util/Build                    |   1 +
 tools/perf/util/evsel_fprintf.c          |   1 +
 tools/perf/util/map.c                    |  49 ++++++
 tools/perf/util/map.h                    |  16 ++
 tools/perf/util/srccode.c                | 186 +++++++++++++++++++++++
 tools/perf/util/srccode.h                |   7 +
 tools/perf/util/srcline.c                |  28 ++++
 tools/perf/util/srcline.h                |   1 +
 tools/perf/util/thread.c                 |   2 +
 tools/perf/util/thread.h                 |   2 +
 12 files changed, 339 insertions(+), 3 deletions(-)
 create mode 100644 tools/perf/util/srccode.c
 create mode 100644 tools/perf/util/srccode.h
tools/perf/Documentation/perf-script.txt +1 -1
index a2b37ce48094..9e4def08d569 100644
@@ -117,7 +117,7 @@ OPTIONS
         Comma separated list of fields to print. Options are:
         comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
         srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, brstackinsn,
-        brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc.
+        brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc, srccode.
         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 +45 -2

113 lines not on this page · raw message

tools/perf/util/Build +1 -0
index b7bf201fe8a8..af72be7f5b3b 100644
@@ -77,6 +77,7 @@ libperf-y += stat-shadow.o
 libperf-y += stat-display.o
 libperf-y += record.o
 libperf-y += srcline.o
+libperf-y += srccode.o
 libperf-y += data.o
 libperf-y += tsc.o
 libperf-y += cloexec.o
tools/perf/util/evsel_fprintf.c +1 -0
index 0d0a4c6f368b..95ea147f9e18 100644
@@ -173,6 +173,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
 			if (!print_oneline)
 				printed += fprintf(fp, "\n");
 
+			/* Add srccode here too? */
 			if (symbol_conf.bt_stop_list &&
 			    node->sym &&
 			    strlist__has_entry(symbol_conf.bt_stop_list,
tools/perf/util/map.c +49 -0

61 lines not on this page · raw message

tools/perf/util/map.h +16 -0
index 5c792c90fc4c..09282aa45c80 100644
@@ -174,6 +174,22 @@ char *map__srcline(struct map *map, u64 addr, struct symbol *sym);
 int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
 			 FILE *fp);
 
+struct srccode_state {
+	char *srcfile;
+	unsigned line;
+};
+
+static inline void srccode_state_init(struct srccode_state *state)
+{
+	state->srcfile = NULL;
+	state->line = 0;
+}
+
+void srccode_state_free(struct srccode_state *state);
+
+int map__fprintf_srccode(struct map *map, u64 addr,
+			 FILE *fp, struct srccode_state *state);
+
 int map__load(struct map *map);
 struct symbol *map__find_symbol(struct map *map, u64 addr);
 struct symbol *map__find_symbol_by_name(struct map *map, const char *name);
tools/perf/util/srccode.c new file +186 -0

186 lines not on this page · raw message

tools/perf/util/srccode.h new file +7 -0
new file mode 100644
index 000000000000..e500a746d5f1
@@ -0,0 +1,7 @@
+#ifndef SRCCODE_H
+#define SRCCODE_H 1
+
+/* Result is not 0 terminated */
+char *find_sourceline(char *fn, unsigned line, int *lenp);
+
+#endif
tools/perf/util/srcline.c +28 -0
index e767c4a9d4d2..dc86597d0cc4 100644
@@ -548,6 +548,34 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 	return srcline;
 }
 
+/* Returns filename and fills in line number in line */
+char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
+{
+	char *file = NULL;
+	const char *dso_name;
+
+	if (!dso->has_srcline)
+		goto out;
+
+	dso_name = dso__name(dso);
+	if (dso_name == NULL)
+		goto out;
+
+	if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL))
+		goto out;
+
+	dso->a2l_fails = 0;
+	return file;
+
+out:
+	if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
+		dso->has_srcline = 0;
+		dso__free_a2l(dso);
+	}
+
+	return NULL;
+}
+
 void free_srcline(char *srcline)
 {
 	if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
tools/perf/util/srcline.h +1 -0
index b2bb5502fd62..5762212dc342 100644
@@ -16,6 +16,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 		  bool show_sym, bool show_addr, bool unwind_inlines,
 		  u64 ip);
 void free_srcline(char *srcline);
+char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line);
 
 /* insert the srcline into the DSO, which will take ownership */
 void srcline__tree_insert(struct rb_root *tree, u64 addr, char *srcline);
tools/perf/util/thread.c +2 -0
index 3d9ed7d0e281..c83372329f89 100644
@@ -64,6 +64,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		RB_CLEAR_NODE(&thread->rb_node);
 		/* Thread holds first ref to nsdata. */
 		thread->nsinfo = nsinfo__new(pid);
+		srccode_state_init(&thread->srccode_state);
 	}
 
 	return thread;
@@ -103,6 +104,7 @@ void thread__delete(struct thread *thread)
 
 	unwind__finish_access(thread);
 	nsinfo__zput(thread->nsinfo);
+	srccode_state_free(&thread->srccode_state);
 
 	exit_rwsem(&thread->namespaces_lock);
 	exit_rwsem(&thread->comm_lock);
tools/perf/util/thread.h +2 -0
index 30e2b4c165fe..a4a56d5e98c7 100644
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include "symbol.h"
+#include "map.h"
 #include <strlist.h>
 #include <intlist.h>
 #include "rwsem.h"
@@ -38,6 +39,7 @@ struct thread {
 	void			*priv;
 	struct thread_stack	*ts;
 	struct nsinfo		*nsinfo;
+	struct srccode_state	srccode_state;
 #ifdef HAVE_LIBUNWIND_SUPPORT
 	void				*addr_space;
 	struct unwind_libunwind_ops	*unwind_libunwind_ops;
Signature · 1 line
2.17.2
Acked-by on v1 1/1
#1 lore raw
Quoted 67 lines · Andi Kleen

From: Andi Kleen <[email protected]>

When looking at PT or brstackinsn traces with perf script it can be very useful to see the source code. This adds a simple facility to print them with perf script, if the information is available through dwarf

% perf record ...
% perf script -F insn,ip,sym,srccode
...

          4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004b3 main

6 v++;

% perf record -b ...
% perf script -F insn,ip,sym,srccode,brstackinsn

...

       main+22:
        0000000000400543        insn: e8 ca ff ff ff            # PRED
|18                     f1();
        f1:
        0000000000400512        insn: 55
|10       {
        0000000000400513        insn: 48 89 e5
        0000000000400516        insn: b8 00 00 00 00
|11             f2();
        000000000040051b        insn: e8 d6 ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00
|6              c = a / b;
        0000000000400500        insn: 8b 0d 2a 0b 20 00
        0000000000400506        insn: 99
        0000000000400507        insn: f7 f9
        0000000000400509        insn: 89 05 29 0b 20 00
        000000000040050f        insn: 90
|7        }
        0000000000400510        insn: 5d
        0000000000400511        insn: c3                        # PRED
        f1+14:
        0000000000400520        insn: b8 00 00 00 00
|12             f2();
        0000000000400525        insn: e8 cc ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00
Quoted 4 lines

|6 c = a / b;

Not supported for callchains currently, would need some layout changes there.

nice, works nicely, especialy with --xed

I need to check, but is there a way to make this work with perf-with-kcore script? looks like we endup with kcore and won't allow vmlinux lookups for debug info

thanks,
jirka

#2 lore raw

Em Wed, Dec 05, 2018 at 01:28:38PM +0100, Jiri Olsa escreveu:

Quoted 70 lines · Andi Kleen
Quoted 69 lines

From: Andi Kleen <[email protected]>

When looking at PT or brstackinsn traces with perf script it can be very useful to see the source code. This adds a simple facility to print them with perf script, if the information is available through dwarf

% perf record ...
% perf script -F insn,ip,sym,srccode
...

          4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004b3 main

6 v++;

% perf record -b ...
% perf script -F insn,ip,sym,srccode,brstackinsn

...

       main+22:
        0000000000400543        insn: e8 ca ff ff ff            # PRED
|18                     f1();
        f1:
        0000000000400512        insn: 55
|10       {
        0000000000400513        insn: 48 89 e5
        0000000000400516        insn: b8 00 00 00 00
|11             f2();
        000000000040051b        insn: e8 d6 ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00
|6              c = a / b;
        0000000000400500        insn: 8b 0d 2a 0b 20 00
        0000000000400506        insn: 99
        0000000000400507        insn: f7 f9
        0000000000400509        insn: 89 05 29 0b 20 00
        000000000040050f        insn: 90
|7        }
        0000000000400510        insn: 5d
        0000000000400511        insn: c3                        # PRED
        f1+14:
        0000000000400520        insn: b8 00 00 00 00
|12             f2();
        0000000000400525        insn: e8 cc ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00

|6 c = a / b;

Quoted 4 lines
Quoted 2 lines

Not supported for callchains currently, would need some layout changes there.

nice, works nicely, especialy with --xed

The above seems to imply you actually tested it, was that the case? Can you please provide me the exact 'perf record' line you used, that is lacking in Andi's original commit log message?

- Arnaldo

Quoted 1 line
#3 lore raw
Quoted 71 lines · Arnaldo Carvalho de Melo

Em Wed, Dec 05, 2018 at 01:28:38PM +0100, Jiri Olsa escreveu:

Quoted 70 lines · Andi Kleen
Quoted 69 lines

From: Andi Kleen <[email protected]>

When looking at PT or brstackinsn traces with perf script it can be very useful to see the source code. This adds a simple facility to print them with perf script, if the information is available through dwarf

% perf record ...
% perf script -F insn,ip,sym,srccode
...

          4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004b3 main

6 v++;

% perf record -b ...
% perf script -F insn,ip,sym,srccode,brstackinsn

...

       main+22:
        0000000000400543        insn: e8 ca ff ff ff            # PRED
|18                     f1();
        f1:
        0000000000400512        insn: 55
|10       {
        0000000000400513        insn: 48 89 e5
        0000000000400516        insn: b8 00 00 00 00
|11             f2();
        000000000040051b        insn: e8 d6 ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00
|6              c = a / b;
        0000000000400500        insn: 8b 0d 2a 0b 20 00
        0000000000400506        insn: 99
        0000000000400507        insn: f7 f9
        0000000000400509        insn: 89 05 29 0b 20 00
        000000000040050f        insn: 90
|7        }
        0000000000400510        insn: 5d
        0000000000400511        insn: c3                        # PRED
        f1+14:
        0000000000400520        insn: b8 00 00 00 00
|12             f2();
        0000000000400525        insn: e8 cc ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00

|6 c = a / b;

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Not supported for callchains currently, would need some layout changes there.

nice, works nicely, especialy with --xed

The above seems to imply you actually tested it, was that the case? Can you please provide me the exact 'perf record' line you used, that is lacking in Andi's original commit log message?

yep..

  # ./perf record -e intel_pt//u -- ./perf

jirka

#4 lore raw
In reply to Jiri Olsa
Quoted 73 lines · Jiri Olsa
Quoted 67 lines · Andi Kleen

From: Andi Kleen <[email protected]>

When looking at PT or brstackinsn traces with perf script it can be very useful to see the source code. This adds a simple facility to print them with perf script, if the information is available through dwarf

% perf record ...
% perf script -F insn,ip,sym,srccode
...

          4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004b3 main

6 v++;

% perf record -b ...
% perf script -F insn,ip,sym,srccode,brstackinsn

...

       main+22:
        0000000000400543        insn: e8 ca ff ff ff            # PRED
|18                     f1();
        f1:
        0000000000400512        insn: 55
|10       {
        0000000000400513        insn: 48 89 e5
        0000000000400516        insn: b8 00 00 00 00
|11             f2();
        000000000040051b        insn: e8 d6 ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00
|6              c = a / b;
        0000000000400500        insn: 8b 0d 2a 0b 20 00
        0000000000400506        insn: 99
        0000000000400507        insn: f7 f9
        0000000000400509        insn: 89 05 29 0b 20 00
        000000000040050f        insn: 90
|7        }
        0000000000400510        insn: 5d
        0000000000400511        insn: c3                        # PRED
        f1+14:
        0000000000400520        insn: b8 00 00 00 00
|12             f2();
        0000000000400525        insn: e8 cc ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00
Quoted 4 lines

|6 c = a / b;

Not supported for callchains currently, would need some layout changes there.

Quoted 7 lines

nice, works nicely, especialy with --xed

I need to check, but is there a way to make this work with perf-with-kcore script? looks like we endup with kcore and won't allow vmlinux lookups for debug info

Hmm, probably not currently. Would somehow need to point to the debuginfo. Perhaps if /proc/kcore was fixed to report the debugid, and then could find it this way.

Or we could add an option to perf report to add a vmlinux only for debug info that is not used for reading the code.

-andi

#5 lore raw
In reply to Jiri Olsa

Em Wed, Dec 05, 2018 at 01:28:38PM +0100, Jiri Olsa escreveu:

Quoted 70 lines · Andi Kleen
Quoted 69 lines

From: Andi Kleen <[email protected]>

When looking at PT or brstackinsn traces with perf script it can be very useful to see the source code. This adds a simple facility to print them with perf script, if the information is available through dwarf

% perf record ...
% perf script -F insn,ip,sym,srccode
...

          4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004c6 main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004cd main
5               for (i = 0; i < 10000000; i++)
           4004b3 main

6 v++;

% perf record -b ...
% perf script -F insn,ip,sym,srccode,brstackinsn

...

       main+22:
        0000000000400543        insn: e8 ca ff ff ff            # PRED
|18                     f1();
        f1:
        0000000000400512        insn: 55
|10       {
        0000000000400513        insn: 48 89 e5
        0000000000400516        insn: b8 00 00 00 00
|11             f2();
        000000000040051b        insn: e8 d6 ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00
|6              c = a / b;
        0000000000400500        insn: 8b 0d 2a 0b 20 00
        0000000000400506        insn: 99
        0000000000400507        insn: f7 f9
        0000000000400509        insn: 89 05 29 0b 20 00
        000000000040050f        insn: 90
|7        }
        0000000000400510        insn: 5d
        0000000000400511        insn: c3                        # PRED
        f1+14:
        0000000000400520        insn: b8 00 00 00 00
|12             f2();
        0000000000400525        insn: e8 cc ff ff ff            # PRED
        f2:
        00000000004004f6        insn: 55
|5        {
        00000000004004f7        insn: 48 89 e5
        00000000004004fa        insn: 8b 05 2c 0b 20 00

|6 c = a / b;

Quoted 6 lines
Quoted 2 lines

Not supported for callchains currently, would need some layout changes there.

nice, works nicely, especialy with --xed

Trying to fix this:

alpine:3.4
Downloading http://x.x.x.x/perf/perf-4.20.0-rc3.tar.xz...

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 1426k 100 1426k 0 0 232M 0 --:--:-- --:--:-- --:--:-- 232M
8932875925270caf72895c32013a678e9c19aa0d
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-alpine-linux-musl/5.3.0/lto-wrapper
Target: x86_64-alpine-linux-musl
Configured with: /home/buildozer/aports/main/gcc/src/gcc-5.3.0/configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --build=x86_64-alpine-linux-musl --host=x86_64-alpine-linux-musl --target=x86_64-alpine-linux-musl --with-pkgversion='Alpine 5.3.0' --enable-checking=release --disable-fixed-point --disable-libstdcxx-pch --disable-multilib --disable-nls --disable-werror --disable-symvers --enable-__cxa_atexit --enable-esp --enable-cloog-backend --enable-languages=c,c++,objc,java,fortran,ada --disable-libssp --disable-libmudflap --disable-libsanitizer --enable-shared --enable-threads --enable-tls --with-system-zlib Thread model: posix
gcc version 5.3.0 (Alpine 5.3.0)
CC /tmp/build/perf/util/srccode.o
In file included from util/srccode.c:19:0:
/usr/include/sys/fcntl.h:1:2: error: #warning redirecting incorrect #include <sys/fcntl.h> to <fcntl.h> [-Werror=cpp]
#warning redirecting incorrect #include <sys/fcntl.h> to <fcntl.h>
^
CC /tmp/build/perf/util/data.o
cc1: all warnings being treated as errors
mv: can't rename '/tmp/build/perf/util/.srccode.o.tmp': No such file or directory
/git/linux/tools/build/Makefile.build:96: recipe for target '/tmp/build/perf/util/srccode.o' failed
make[4]: *** [/tmp/build/perf/util/srccode.o] Error 1
make[4]: *** Waiting for unfinished jobs....
CC /tmp/build/perf/tests/attr.o

#6 lore raw

[tip:perf/core] perf tools: Support 'srccode' output

In reply to Andi Kleen
perf tools: Support 'srccode' output
Commit-ID:  6024b7a51a19256df871d148925b2f0e4fc18436
Gitweb:     https://git.kernel.org/tip/6024b7a51a19256df871d148925b2f0e4fc18436
Author:     Andi Kleen <[email protected]>
AuthorDate: Mon, 3 Dec 2018 16:18:48 -0800
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 6 Dec 2018 14:12:32 -0300

perf tools: Support 'srccode' output

When looking at PT or brstackinsn traces with 'perf script' it can be very useful to see the source code. This adds a simple facility to print them with 'perf script', if the information is available through dwarf

% perf record ...
% perf script -F insn,ip,sym,srccode
...

            4004c6 main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004c6 main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004b3 main

6 v++;

% perf record -b ...
% perf script -F insn,ip,sym,srccode,brstackinsn

  ...
         main+22:
          0000000000400543        insn: e8 ca ff ff ff            # PRED
  |18                     f1();
          f1:
          0000000000400512        insn: 55
  |10       {
          0000000000400513        insn: 48 89 e5
          0000000000400516        insn: b8 00 00 00 00
  |11             f2();
          000000000040051b        insn: e8 d6 ff ff ff            # PRED
          f2:
          00000000004004f6        insn: 55
  |5        {
          00000000004004f7        insn: 48 89 e5
          00000000004004fa        insn: 8b 05 2c 0b 20 00
  |6              c = a / b;
          0000000000400500        insn: 8b 0d 2a 0b 20 00
          0000000000400506        insn: 99
          0000000000400507        insn: f7 f9
          0000000000400509        insn: 89 05 29 0b 20 00
          000000000040050f        insn: 90
  |7        }
          0000000000400510        insn: 5d
          0000000000400511        insn: c3                        # PRED
          f1+14:
          0000000000400520        insn: b8 00 00 00 00
  |12             f2();
          0000000000400525        insn: e8 cc ff ff ff            # PRED
          f2:
          00000000004004f6        insn: 55
  |5        {
          00000000004004f7        insn: 48 89 e5
          00000000004004fa        insn: 8b 05 2c 0b 20 00
  |6              c = a / b;

Not supported for callchains currently, would need some layout changes there.

Committer notes:

Fixed the build on Alpine Linux (3.4 .. 3.8) by addressing this warning:

In file included from util/srccode.c:19:0:
/usr/include/sys/fcntl.h:1:2: error: #warning redirecting incorrect #include <sys/fcntl.h> to <fcntl.h> [-Werror=cpp]
#warning redirecting incorrect #include <sys/fcntl.h> to <fcntl.h>

    ^~~~~~~

cc1: all warnings being treated as errors

---
 tools/perf/Documentation/perf-script.txt |   2 +-
 tools/perf/builtin-script.c              |  47 +++++++-
 tools/perf/util/Build                    |   1 +
 tools/perf/util/evsel_fprintf.c          |   1 +
 tools/perf/util/map.c                    |  49 ++++++++
 tools/perf/util/map.h                    |  16 +++
 tools/perf/util/srccode.c                | 186 +++++++++++++++++++++++++++++++
 tools/perf/util/srccode.h                |   7 ++
 tools/perf/util/srcline.c                |  28 +++++
 tools/perf/util/srcline.h                |   1 +
 tools/perf/util/thread.c                 |   2 +
 tools/perf/util/thread.h                 |   2 +
 12 files changed, 339 insertions(+), 3 deletions(-)
tools/perf/Documentation/perf-script.txt +1 -1
index a2b37ce48094..9e4def08d569 100644
@@ -117,7 +117,7 @@ OPTIONS
         Comma separated list of fields to print. Options are:
         comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
         srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, brstackinsn,
-        brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc.
+        brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc, srccode.
         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 +45 -2

113 lines not on this page · raw message

tools/perf/util/Build +1 -0
index b7bf201fe8a8..af72be7f5b3b 100644
@@ -77,6 +77,7 @@ libperf-y += stat-shadow.o
 libperf-y += stat-display.o
 libperf-y += record.o
 libperf-y += srcline.o
+libperf-y += srccode.o
 libperf-y += data.o
 libperf-y += tsc.o
 libperf-y += cloexec.o
tools/perf/util/evsel_fprintf.c +1 -0
index 0d0a4c6f368b..95ea147f9e18 100644
@@ -173,6 +173,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
 			if (!print_oneline)
 				printed += fprintf(fp, "\n");
 
+			/* Add srccode here too? */
 			if (symbol_conf.bt_stop_list &&
 			    node->sym &&
 			    strlist__has_entry(symbol_conf.bt_stop_list,
tools/perf/util/map.c +49 -0

61 lines not on this page · raw message

tools/perf/util/map.h +16 -0
index 5c792c90fc4c..09282aa45c80 100644
@@ -174,6 +174,22 @@ char *map__srcline(struct map *map, u64 addr, struct symbol *sym);
 int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
 			 FILE *fp);
 
+struct srccode_state {
+	char *srcfile;
+	unsigned line;
+};
+
+static inline void srccode_state_init(struct srccode_state *state)
+{
+	state->srcfile = NULL;
+	state->line = 0;
+}
+
+void srccode_state_free(struct srccode_state *state);
+
+int map__fprintf_srccode(struct map *map, u64 addr,
+			 FILE *fp, struct srccode_state *state);
+
 int map__load(struct map *map);
 struct symbol *map__find_symbol(struct map *map, u64 addr);
 struct symbol *map__find_symbol_by_name(struct map *map, const char *name);
tools/perf/util/srccode.c new file +186 -0

186 lines not on this page · raw message

tools/perf/util/srccode.h new file +7 -0
new file mode 100644
index 000000000000..e500a746d5f1
@@ -0,0 +1,7 @@
+#ifndef SRCCODE_H
+#define SRCCODE_H 1
+
+/* Result is not 0 terminated */
+char *find_sourceline(char *fn, unsigned line, int *lenp);
+
+#endif
tools/perf/util/srcline.c +28 -0
index e767c4a9d4d2..dc86597d0cc4 100644
@@ -548,6 +548,34 @@ out:
 	return srcline;
 }
 
+/* Returns filename and fills in line number in line */
+char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
+{
+	char *file = NULL;
+	const char *dso_name;
+
+	if (!dso->has_srcline)
+		goto out;
+
+	dso_name = dso__name(dso);
+	if (dso_name == NULL)
+		goto out;
+
+	if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL))
+		goto out;
+
+	dso->a2l_fails = 0;
+	return file;
+
+out:
+	if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
+		dso->has_srcline = 0;
+		dso__free_a2l(dso);
+	}
+
+	return NULL;
+}
+
 void free_srcline(char *srcline)
 {
 	if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
tools/perf/util/srcline.h +1 -0
index b2bb5502fd62..5762212dc342 100644
@@ -16,6 +16,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 		  bool show_sym, bool show_addr, bool unwind_inlines,
 		  u64 ip);
 void free_srcline(char *srcline);
+char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line);
 
 /* insert the srcline into the DSO, which will take ownership */
 void srcline__tree_insert(struct rb_root *tree, u64 addr, char *srcline);
tools/perf/util/thread.c +2 -0
index 3d9ed7d0e281..c83372329f89 100644
@@ -64,6 +64,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		RB_CLEAR_NODE(&thread->rb_node);
 		/* Thread holds first ref to nsdata. */
 		thread->nsinfo = nsinfo__new(pid);
+		srccode_state_init(&thread->srccode_state);
 	}
 
 	return thread;
@@ -103,6 +104,7 @@ void thread__delete(struct thread *thread)
 
 	unwind__finish_access(thread);
 	nsinfo__zput(thread->nsinfo);
+	srccode_state_free(&thread->srccode_state);
 
 	exit_rwsem(&thread->namespaces_lock);
 	exit_rwsem(&thread->comm_lock);
tools/perf/util/thread.h +2 -0
index 5920c3bb8ffe..712dd48cc0ca 100644
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include "symbol.h"
+#include "map.h"
 #include <strlist.h>
 #include <intlist.h>
 #include "rwsem.h"
@@ -38,6 +39,7 @@ struct thread {
 	void			*priv;
 	struct thread_stack	*ts;
 	struct nsinfo		*nsinfo;
+	struct srccode_state	srccode_state;
 #ifdef HAVE_LIBUNWIND_SUPPORT
 	void				*addr_space;
 	struct unwind_libunwind_ops	*unwind_libunwind_ops;
#7 lore raw

[tip:perf/core] perf tools: Support 'srccode' output

In reply to Andi Kleen
perf tools: Support 'srccode' output
Commit-ID:  dd2e18e9ac20e3ffc27cabf318e83b43ed5ddb92
Gitweb:     https://git.kernel.org/tip/dd2e18e9ac20e3ffc27cabf318e83b43ed5ddb92
Author:     Andi Kleen <[email protected]>
AuthorDate: Mon, 3 Dec 2018 16:18:48 -0800
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 17 Dec 2018 14:57:07 -0300

perf tools: Support 'srccode' output

When looking at PT or brstackinsn traces with 'perf script' it can be very useful to see the source code. This adds a simple facility to print them with 'perf script', if the information is available through dwarf

% perf record ...
% perf script -F insn,ip,sym,srccode
...

            4004c6 main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004c6 main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004cd main
  5               for (i = 0; i < 10000000; i++)
             4004b3 main

6 v++;

% perf record -b ...
% perf script -F insn,ip,sym,srccode,brstackinsn

  ...
         main+22:
          0000000000400543        insn: e8 ca ff ff ff            # PRED
  |18                     f1();
          f1:
          0000000000400512        insn: 55
  |10       {
          0000000000400513        insn: 48 89 e5
          0000000000400516        insn: b8 00 00 00 00
  |11             f2();
          000000000040051b        insn: e8 d6 ff ff ff            # PRED
          f2:
          00000000004004f6        insn: 55
  |5        {
          00000000004004f7        insn: 48 89 e5
          00000000004004fa        insn: 8b 05 2c 0b 20 00
  |6              c = a / b;
          0000000000400500        insn: 8b 0d 2a 0b 20 00
          0000000000400506        insn: 99
          0000000000400507        insn: f7 f9
          0000000000400509        insn: 89 05 29 0b 20 00
          000000000040050f        insn: 90
  |7        }
          0000000000400510        insn: 5d
          0000000000400511        insn: c3                        # PRED
          f1+14:
          0000000000400520        insn: b8 00 00 00 00
  |12             f2();
          0000000000400525        insn: e8 cc ff ff ff            # PRED
          f2:
          00000000004004f6        insn: 55
  |5        {
          00000000004004f7        insn: 48 89 e5
          00000000004004fa        insn: 8b 05 2c 0b 20 00
  |6              c = a / b;

Not supported for callchains currently, would need some layout changes there.

Committer notes:

Fixed the build on Alpine Linux (3.4 .. 3.8) by addressing this warning:

In file included from util/srccode.c:19:0:
/usr/include/sys/fcntl.h:1:2: error: #warning redirecting incorrect #include <sys/fcntl.h> to <fcntl.h> [-Werror=cpp]
#warning redirecting incorrect #include <sys/fcntl.h> to <fcntl.h>

    ^~~~~~~

cc1: all warnings being treated as errors

---
 tools/perf/Documentation/perf-script.txt |   2 +-
 tools/perf/builtin-script.c              |  47 +++++++-
 tools/perf/util/Build                    |   1 +
 tools/perf/util/evsel_fprintf.c          |   1 +
 tools/perf/util/map.c                    |  49 ++++++++
 tools/perf/util/map.h                    |  16 +++
 tools/perf/util/srccode.c                | 186 +++++++++++++++++++++++++++++++
 tools/perf/util/srccode.h                |   7 ++
 tools/perf/util/srcline.c                |  28 +++++
 tools/perf/util/srcline.h                |   1 +
 tools/perf/util/thread.c                 |   2 +
 tools/perf/util/thread.h                 |   2 +
 12 files changed, 339 insertions(+), 3 deletions(-)
tools/perf/Documentation/perf-script.txt +1 -1
index a2b37ce48094..9e4def08d569 100644
@@ -117,7 +117,7 @@ OPTIONS
         Comma separated list of fields to print. Options are:
         comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
         srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, brstackinsn,
-        brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc.
+        brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc, srccode.
         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 +45 -2

113 lines not on this page · raw message

tools/perf/util/Build +1 -0
index b7bf201fe8a8..af72be7f5b3b 100644
@@ -77,6 +77,7 @@ libperf-y += stat-shadow.o
 libperf-y += stat-display.o
 libperf-y += record.o
 libperf-y += srcline.o
+libperf-y += srccode.o
 libperf-y += data.o
 libperf-y += tsc.o
 libperf-y += cloexec.o
tools/perf/util/evsel_fprintf.c +1 -0
index 0d0a4c6f368b..95ea147f9e18 100644
@@ -173,6 +173,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
 			if (!print_oneline)
 				printed += fprintf(fp, "\n");
 
+			/* Add srccode here too? */
 			if (symbol_conf.bt_stop_list &&
 			    node->sym &&
 			    strlist__has_entry(symbol_conf.bt_stop_list,
tools/perf/util/map.c +49 -0

61 lines not on this page · raw message

tools/perf/util/map.h +16 -0
index 5c792c90fc4c..09282aa45c80 100644
@@ -174,6 +174,22 @@ char *map__srcline(struct map *map, u64 addr, struct symbol *sym);
 int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
 			 FILE *fp);
 
+struct srccode_state {
+	char *srcfile;
+	unsigned line;
+};
+
+static inline void srccode_state_init(struct srccode_state *state)
+{
+	state->srcfile = NULL;
+	state->line = 0;
+}
+
+void srccode_state_free(struct srccode_state *state);
+
+int map__fprintf_srccode(struct map *map, u64 addr,
+			 FILE *fp, struct srccode_state *state);
+
 int map__load(struct map *map);
 struct symbol *map__find_symbol(struct map *map, u64 addr);
 struct symbol *map__find_symbol_by_name(struct map *map, const char *name);
tools/perf/util/srccode.c new file +186 -0

186 lines not on this page · raw message

tools/perf/util/srccode.h new file +7 -0
new file mode 100644
index 000000000000..e500a746d5f1
@@ -0,0 +1,7 @@
+#ifndef SRCCODE_H
+#define SRCCODE_H 1
+
+/* Result is not 0 terminated */
+char *find_sourceline(char *fn, unsigned line, int *lenp);
+
+#endif
tools/perf/util/srcline.c +28 -0
index e767c4a9d4d2..dc86597d0cc4 100644
@@ -548,6 +548,34 @@ out:
 	return srcline;
 }
 
+/* Returns filename and fills in line number in line */
+char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
+{
+	char *file = NULL;
+	const char *dso_name;
+
+	if (!dso->has_srcline)
+		goto out;
+
+	dso_name = dso__name(dso);
+	if (dso_name == NULL)
+		goto out;
+
+	if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL))
+		goto out;
+
+	dso->a2l_fails = 0;
+	return file;
+
+out:
+	if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
+		dso->has_srcline = 0;
+		dso__free_a2l(dso);
+	}
+
+	return NULL;
+}
+
 void free_srcline(char *srcline)
 {
 	if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
tools/perf/util/srcline.h +1 -0
index b2bb5502fd62..5762212dc342 100644
@@ -16,6 +16,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
 		  bool show_sym, bool show_addr, bool unwind_inlines,
 		  u64 ip);
 void free_srcline(char *srcline);
+char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line);
 
 /* insert the srcline into the DSO, which will take ownership */
 void srcline__tree_insert(struct rb_root *tree, u64 addr, char *srcline);
tools/perf/util/thread.c +2 -0
index 3d9ed7d0e281..c83372329f89 100644
@@ -64,6 +64,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		RB_CLEAR_NODE(&thread->rb_node);
 		/* Thread holds first ref to nsdata. */
 		thread->nsinfo = nsinfo__new(pid);
+		srccode_state_init(&thread->srccode_state);
 	}
 
 	return thread;
@@ -103,6 +104,7 @@ void thread__delete(struct thread *thread)
 
 	unwind__finish_access(thread);
 	nsinfo__zput(thread->nsinfo);
+	srccode_state_free(&thread->srccode_state);
 
 	exit_rwsem(&thread->namespaces_lock);
 	exit_rwsem(&thread->comm_lock);
tools/perf/util/thread.h +2 -0
index 5920c3bb8ffe..712dd48cc0ca 100644
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include "symbol.h"
+#include "map.h"
 #include <strlist.h>
 #include <intlist.h>
 #include "rwsem.h"
@@ -38,6 +39,7 @@ struct thread {
 	void			*priv;
 	struct thread_stack	*ts;
 	struct nsinfo		*nsinfo;
+	struct srccode_state	srccode_state;
 #ifdef HAVE_LIBUNWIND_SUPPORT
 	void				*addr_space;
 	struct unwind_libunwind_ops	*unwind_libunwind_ops;