Skip to contentSkip to conversation

perf tools: More preparation for call graph from Intel BTS

PATCH In review Adrian Hunter 7 participants 112 messages Jul 22, 2014 – Jul 28, 2014 perf events

lore
Share & tools
lore

Adrian Hunter

author reviewer
#0 lore raw

cover perf tools: More preparation for call graph from Intel BTS

Hi

Here is the next selection of patches based on tip/perf/core.

They can also be found here:

http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/for-acme

Adrian Hunter (52):
perf tools: Fix jump label always changing during tracing
perf tools: Identify which comms are from exec
perf tools: Add machine__thread_exec_comm()
perf tools: Fix missing label symbols
perf tools: Add machine__kernel_ip()
perf script: Improve srcline display for BTS
perf script: Do not print dangling '=>' for BTS
perf tools: Fix incorrect fd error comparison
perf tools: Record whether a dso has data
perf tools: Add dso__data_status_seen()
perf tools: Let a user specify a PMU event without any config terms perf tools: Let default config be defined for a PMU
perf tools: Add perf_pmu__scan_file()
perf tools: Add dsos__hit_all()
perf tools: Add cpu to struct thread
perf tools: Add ability to record the current tid for each cpu
perf evlist: Add perf_evlist__set_tracking_event()
perf evlist: Add 'system_wide' option
perf tools: Add id index
perf pmu: Let pmu's with no events show up on perf list
perf session: Add ability to skip 4GiB or more
perf session: Add perf_session__deliver_synth_event()
perf tools: Move rdtsc() function
perf evlist: Add perf_evlist__enable_event_idx()
perf session: Add perf_session__peek_event()
perf tools: Add dso__data_size()
perf tools: Add a thread stack for synthesizing call chains
perf script: Allow callchains if any event samples them
perf inject: Add --kallsyms parameter
perf tools: Expose 'addr' functions so they can be reused
perf tools: Add facility to export data in database-friendly way
perf tools: Add helpers for calling Python objects
perf tools: Extend Python script interface to export data in a database-friendly way perf tools: Add Python script to export to postgresql
perf tools: Add flags and insn_len to struct sample
perf tools: Add branch type to db export
perf tools: Add branch_type and in_tx to Python export
perf tools: Enhance the thread stack to output call/return data
perf tools: Add call information to the database export API
perf tools: Add call information to Python export
perf tools: Add 'flush' callback to scripting API
perf tools: Defer export of comms that were not 'set'
perf tools: Add perf-with-kcore script
perf tools: Pass machine to vdso__dso_findnew()
perf tools: Group VDSO global variables into a structure
perf tools: Fix the lifetime of the VDSO temporary file
perf tools: Add vdso__new()
perf tools: Separate the VDSO map name from the VDSO dso name
perf tools: Build programs to copy 32-bit compatibility VDSOs
perf tools: Add dso__type()
perf tools: Add thread parameter to vdso__dso_findnew()
perf tools: Add support for 32-bit compatibility VDSOs

 tools/perf/.gitignore                              |   1 +
 tools/perf/Documentation/perf-inject.txt           |   3 +
 tools/perf/Makefile.perf                           |  46 +-
 tools/perf/arch/x86/util/tsc.c                     |   9 +
 tools/perf/builtin-inject.c                        |   3 +
 tools/perf/builtin-script.c                        |  89 ++-
 tools/perf/config/Makefile                         |  21 +
 tools/perf/config/Makefile.arch                    |   8 +
 tools/perf/perf-read-vdso.c                        |  59 ++
 tools/perf/perf-with-kcore.sh                      | 259 ++++++++
 .../scripts/python/bin/export-to-postgresql-record |   8 +
 .../scripts/python/bin/export-to-postgresql-report |  29 +
 tools/perf/scripts/python/export-to-postgresql.py  | 444 +++++++++++++
 tools/perf/tests/perf-time-to-tsc.c                |   9 -
 tools/perf/tests/pmu.c                             |   2 +-
 tools/perf/util/cloexec.c                          |   9 +-
 tools/perf/util/comm.c                             |   7 +-
 tools/perf/util/comm.h                             |   7 +-
 tools/perf/util/db-export.c                        | 426 +++++++++++++
 tools/perf/util/db-export.h                        | 107 ++++
 tools/perf/util/dso.c                              |  70 ++-
 tools/perf/util/dso.h                              |  26 +
 tools/perf/util/event.c                            |  49 +-
 tools/perf/util/event.h                            |  53 ++
 tools/perf/util/evlist.c                           | 138 ++++-
 tools/perf/util/evlist.h                           |   5 +
 tools/perf/util/evsel.c                            |  31 +-
 tools/perf/util/evsel.h                            |   5 +
 tools/perf/util/header.c                           |  51 +-
 tools/perf/util/header.h                           |   2 +
 tools/perf/util/machine.c                          | 109 +++-
 tools/perf/util/machine.h                          |  30 +
 tools/perf/util/map.c                              |   9 +-
 tools/perf/util/map.h                              |   5 +-
 tools/perf/util/parse-events.c                     |  13 +-
 tools/perf/util/parse-events.y                     |  10 +
 tools/perf/util/pmu.c                              |  92 ++-
 tools/perf/util/pmu.h                              |  13 +-
 .../perf/util/scripting-engines/trace-event-perl.c |   6 +
 .../util/scripting-engines/trace-event-python.c    | 511 +++++++++++++--
 tools/perf/util/session.c                          | 237 ++++++-
 tools/perf/util/session.h                          |  20 +
 tools/perf/util/symbol-elf.c                       |  37 +-
 tools/perf/util/symbol-minimal.c                   |  21 +
 tools/perf/util/symbol.h                           |   3 +
 tools/perf/util/thread-stack.c                     | 690 +++++++++++++++++++++
 tools/perf/util/thread-stack.h                     |  79 +++
 tools/perf/util/thread.c                           |  28 +-
 tools/perf/util/thread.h                           |  15 +-
 tools/perf/util/tool.h                             |   3 +-
 tools/perf/util/trace-event-scripting.c            |   7 +
 tools/perf/util/trace-event.h                      |   1 +
 tools/perf/util/tsc.c                              |   5 +
 tools/perf/util/tsc.h                              |   1 +
 tools/perf/util/vdso.c                             | 264 +++++++-
 tools/perf/util/vdso.h                             |  15 +-
 56 files changed, 3961 insertions(+), 239 deletions(-)
 create mode 100644 tools/perf/perf-read-vdso.c
 create mode 100644 tools/perf/perf-with-kcore.sh
 create mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-record
 create mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-report
 create mode 100644 tools/perf/scripts/python/export-to-postgresql.py
 create mode 100644 tools/perf/util/db-export.c
 create mode 100644 tools/perf/util/db-export.h
 create mode 100644 tools/perf/util/thread-stack.c
 create mode 100644 tools/perf/util/thread-stack.h

Regards
Adrian

author reviewer
#1 lore raw

PATCH 1/52 perf tools: Fix jump label always changing during tracing

Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.

The "Enable close-on-exec flag on perf file descriptor" patch caused there to be always a jump label change.

It was found that using a per-cpu context instead of a per-thread context for the probe of the close-on-exec feature, made the problem go away.

---
 tools/perf/util/cloexec.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
tools/perf/util/cloexec.c +7 -2
index c5d05ec..6a37be5 100644
@@ -1,3 +1,4 @@
+#include <sched.h>
 #include "util.h"
 #include "../perf.h"
 #include "cloexec.h"
@@ -14,9 +15,13 @@ static int perf_flag_probe(void)
 	};
 	int fd;
 	int err;
+	int cpu = sched_getcpu();
+
+	if (cpu < 0)
+		cpu = 0;
 
 	/* check cloexec flag */
-	fd = sys_perf_event_open(&attr, 0, -1, -1,
+	fd = sys_perf_event_open(&attr, -1, cpu, -1,
 				 PERF_FLAG_FD_CLOEXEC);
 	err = errno;
 
@@ -30,7 +35,7 @@ static int perf_flag_probe(void)
 		  err, strerror(err));
 
 	/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
+	fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
 	err = errno;
 
 	if (WARN_ONCE(fd < 0,
Signature · 1 line
1.8.3.2
#2 lore raw

Re: [PATCH 01/52] perf tools: Fix jump label always changing during tracing

Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:

Quoted 10 lines

Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.

The "Enable close-on-exec flag on perf file descriptor" patch caused there to be always a jump label change.

It was found that using a per-cpu context instead of a per-thread context for the probe of the close-on-exec feature, made the problem go away.

And it is ok for our purposes, as this code just needs to figure out if PERF_FLAG_FD_CLOEXEC is present, but I wonder when this kind of thing will hit again...

Anyway, I'll take this patch.

- Arnaldo

Quoted 40 lines
---
 tools/perf/util/cloexec.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
tools/perf/util/cloexec.c +7 -2
index c5d05ec..6a37be5 100644
@@ -1,3 +1,4 @@
+#include <sched.h>
 #include "util.h"
 #include "../perf.h"
 #include "cloexec.h"
@@ -14,9 +15,13 @@ static int perf_flag_probe(void)
 	};
 	int fd;
 	int err;
+	int cpu = sched_getcpu();
+
+	if (cpu < 0)
+		cpu = 0;
 
 	/* check cloexec flag */
-	fd = sys_perf_event_open(&attr, 0, -1, -1,
+	fd = sys_perf_event_open(&attr, -1, cpu, -1,
 				 PERF_FLAG_FD_CLOEXEC);
 	err = errno;
 
@@ -30,7 +35,7 @@ static int perf_flag_probe(void)
 		  err, strerror(err));
 
 	/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
+	fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
 	err = errno;
 
 	if (WARN_ONCE(fd < 0,
Signature · 1 line
1.8.3.2
maintainer
#3 lore raw

Re: [PATCH 01/52] perf tools: Fix jump label always changing during tracing

Quoted 4 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:

Quoted 3 lines

Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.

You'd better fix that, jump_labels can change any time and they're all over the frigging place.

author reviewer
#4 lore raw

Re: [PATCH 01/52] perf tools: Fix jump label always changing during tracing

Quoted 9 lines · Peter Zijlstra
Quoted 4 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:

Quoted 3 lines

Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.

You'd better fix that, jump_labels can change any time and they're all over the frigging place.

Perhaps a general method is needed to be able to deal with kernel self-modifying code.

maintainer
#5 lore raw

Re: [PATCH 01/52] perf tools: Fix jump label always changing during tracing

Quoted 7 lines · Adrian Hunter
Quoted 6 lines · Peter Zijlstra
Quoted 4 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:

Quoted 3 lines

Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.

Quoted 6 lines
Quoted 3 lines

You'd better fix that, jump_labels can change any time and they're all over the frigging place.

Perhaps a general method is needed to be able to deal with kernel self-modifying code.

I know people are looking at doing the same to userspace, is that also a problem?

author reviewer
#6 lore raw

Re: [PATCH 01/52] perf tools: Fix jump label always changing during tracing

Quoted 12 lines · Peter Zijlstra
Quoted 11 lines · Adrian Hunter
Quoted 9 lines · Peter Zijlstra
Quoted 4 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:

Quoted 3 lines

Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.

You'd better fix that, jump_labels can change any time and they're all over the frigging place.

Quoted 5 lines
Quoted 2 lines

Perhaps a general method is needed to be able to deal with kernel self-modifying code.

I know people are looking at doing the same to userspace, is that also a problem?

Yes, most significantly JIT-compiled code.

#7 lore raw

Re: [PATCH 01/52] perf tools: Fix jump label always changing during tracing

Em Wed, Jul 23, 2014 at 10:15:45AM +0300, Adrian Hunter escreveu:

Quoted 12 lines · Peter Zijlstra
Quoted 10 lines · Adrian Hunter
Quoted 9 lines · Peter Zijlstra
Quoted 8 lines · Arnaldo Carvalho de Melo
Quoted 4 lines

Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:

Quoted 3 lines

Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.

You'd better fix that, jump_labels can change any time and they're all over the frigging place.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Perhaps a general method is needed to be able to deal with kernel self-modifying code.

I know people are looking at doing the same to userspace, is that also a problem?

Yes, most significantly JIT-compiled code.

It would be great to figure out the parts that were patched, so as to have the original and patched lines disassembled and properly marked as such in the annotation widgets, using a different colour, and allowing to flip to/from original/patched.

I wonder if there is some place with a list of the areas that were patched or that can be patched if enabled, etc, surely there is one for ftrace stuff, etc.

- Arnaldo

author reviewer
#8 lore raw

Re: [PATCH 01/52] perf tools: Fix jump label always changing during tracing

In reply to Arnaldo Carvalho de Melo
Quoted 8 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 22, 2014 at 04:17:10PM +0300, Adrian Hunter escreveu:

Quoted 7 lines

Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.

The "Enable close-on-exec flag on perf file descriptor" patch caused there to be always a jump label change.

Quoted 7 lines
Quoted 3 lines

It was found that using a per-cpu context instead of a per-thread context for the probe of the close-on-exec feature, made the problem go away.

And it is ok for our purposes, as this code just needs to figure out if PERF_FLAG_FD_CLOEXEC is present, but I wonder when this kind of thing will hit again...

Possibly

Quoted 2 lines

Anyway, I'll take this patch.

Thanks!

Quoted 45 lines

- Arnaldo

Quoted 40 lines
---
 tools/perf/util/cloexec.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
tools/perf/util/cloexec.c +7 -2
index c5d05ec..6a37be5 100644
@@ -1,3 +1,4 @@
+#include <sched.h>
 #include "util.h"
 #include "../perf.h"
 #include "cloexec.h"
@@ -14,9 +15,13 @@ static int perf_flag_probe(void)
 	};
 	int fd;
 	int err;
+	int cpu = sched_getcpu();
+
+	if (cpu < 0)
+		cpu = 0;
 
 	/* check cloexec flag */
-	fd = sys_perf_event_open(&attr, 0, -1, -1,
+	fd = sys_perf_event_open(&attr, -1, cpu, -1,
 				 PERF_FLAG_FD_CLOEXEC);
 	err = errno;
 
@@ -30,7 +35,7 @@ static int perf_flag_probe(void)
 		  err, strerror(err));
 
 	/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
+	fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
 	err = errno;
 
 	if (WARN_ONCE(fd < 0,
Signature · 1 line
1.8.3.2
#9 lore raw

[tip:perf/core] perf tools: Fix jump label always changing during tracing

In reply to Adrian Hunter
perf tools: Fix jump label always changing during tracing
Commit-ID:  deaff8b659cf4d34181c087b8cdf74f1eb17b02b
Gitweb:     http://git.kernel.org/tip/deaff8b659cf4d34181c087b8cdf74f1eb17b02b
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:10 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:12:59 -0300

perf tools: Fix jump label always changing during tracing

Intel PT decoding walks the object code to reconstruct the trace. A jump label change during tracing causes decoding errors.

The "Enable close-on-exec flag on perf file descriptor" patch caused there to be always a jump label change.

It was found that using a per-cpu context instead of a per-thread context for the probe of the close-on-exec feature, made the problem go away.

---
 tools/perf/util/cloexec.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
tools/perf/util/cloexec.c +7 -2
index c5d05ec..6a37be5 100644
@@ -1,3 +1,4 @@
+#include <sched.h>
 #include "util.h"
 #include "../perf.h"
 #include "cloexec.h"
@@ -14,9 +15,13 @@ static int perf_flag_probe(void)
 	};
 	int fd;
 	int err;
+	int cpu = sched_getcpu();
+
+	if (cpu < 0)
+		cpu = 0;
 
 	/* check cloexec flag */
-	fd = sys_perf_event_open(&attr, 0, -1, -1,
+	fd = sys_perf_event_open(&attr, -1, cpu, -1,
 				 PERF_FLAG_FD_CLOEXEC);
 	err = errno;
 
@@ -30,7 +35,7 @@ static int perf_flag_probe(void)
 		  err, strerror(err));
 
 	/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-	fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
+	fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
 	err = errno;
 
 	if (WARN_ONCE(fd < 0,
author reviewer
#10 lore raw

PATCH 2/52 perf tools: Identify which comms are from exec

In reply to Adrian Hunter
---
 tools/perf/util/comm.c    |  7 +++++--
 tools/perf/util/comm.h    |  6 ++++--
 tools/perf/util/machine.c |  4 +++-
 tools/perf/util/thread.c  | 24 +++++++++++++++++++-----
 tools/perf/util/thread.h  | 10 +++++++++-
 5 files changed, 40 insertions(+), 11 deletions(-)
tools/perf/util/comm.c +5 -2
index f9e7776..5e1e80e 100644
@@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
 	return new;
 }
 
-struct comm *comm__new(const char *str, u64 timestamp)
+struct comm *comm__new(const char *str, u64 timestamp, bool exec)
 {
 	struct comm *comm = zalloc(sizeof(*comm));
 
@@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
 		return NULL;
 
 	comm->start = timestamp;
+	comm->exec = exec;
 
 	comm->comm_str = comm_str__findnew(str, &comm_str_root);
 	if (!comm->comm_str) {
@@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
 	return comm;
 }
 
-int comm__override(struct comm *comm, const char *str, u64 timestamp)
+int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
 {
 	struct comm_str *new, *old = comm->comm_str;
 
@@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp)
 	comm_str__put(old);
 	comm->comm_str = new;
 	comm->start = timestamp;
+	if (exec && !comm->exec)
+		comm->exec = true;
 
 	return 0;
 }
tools/perf/util/comm.h +4 -2
index fac5bd5..51c10ab 100644
@@ -11,11 +11,13 @@ struct comm {
 	struct comm_str *comm_str;
 	u64 start;
 	struct list_head list;
+	bool exec;
 };
 
 void comm__free(struct comm *comm);
-struct comm *comm__new(const char *str, u64 timestamp);
+struct comm *comm__new(const char *str, u64 timestamp, bool exec);
 const char *comm__str(const struct comm *comm);
-int comm__override(struct comm *comm, const char *str, u64 timestamp);
+int comm__override(struct comm *comm, const char *str, u64 timestamp,
+		   bool exec);
 
 #endif  /* __PERF_COMM_H */
tools/perf/util/machine.c +3 -1
index 93c8b6f..c90f4e3 100644
@@ -397,11 +397,13 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
 	struct thread *thread = machine__findnew_thread(machine,
 							event->comm.pid,
 							event->comm.tid);
+	bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
 
 	if (dump_trace)
 		perf_event__fprintf_comm(event, stdout);
 
-	if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) {
+	if (thread == NULL ||
+	    __thread__set_comm(thread, event->comm.comm, sample->time, exec)) {
 		dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
 		return -1;
 	}
tools/perf/util/thread.c +19 -5
index 9692c06..08f9f8b 100644
@@ -41,7 +41,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 			goto err_thread;
 
 		snprintf(comm_str, 32, ":%d", tid);
-		comm = comm__new(comm_str, 0);
+		comm = comm__new(comm_str, 0, false);
 		free(comm_str);
 		if (!comm)
 			goto err_thread;
@@ -80,19 +80,33 @@ struct comm *thread__comm(const struct thread *thread)
 	return list_first_entry(&thread->comm_list, struct comm, list);
 }
 
+struct comm *thread__exec_comm(const struct thread *thread)
+{
+	struct comm *comm, *last = NULL;
+
+	list_for_each_entry(comm, &thread->comm_list, list) {
+		if (comm->exec)
+			return comm;
+		last = comm;
+	}
+
+	return last;
+}
+
 /* CHECKME: time should always be 0 if event aren't ordered */
-int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
+int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
+		       bool exec)
 {
 	struct comm *new, *curr = thread__comm(thread);
 	int err;
 
 	/* Override latest entry if it had no specific time coverage */
-	if (!curr->start) {
-		err = comm__override(curr, str, timestamp);
+	if (!curr->start && !curr->exec) {
+		err = comm__override(curr, str, timestamp, exec);
 		if (err)
 			return err;
 	} else {
-		new = comm__new(str, timestamp);
+		new = comm__new(str, timestamp, exec);
 		if (!new)
 			return -ENOMEM;
 		list_add(&new->list, &thread->comm_list);
tools/perf/util/thread.h +9 -1
index 3c0c272..9991e21 100644
@@ -37,9 +37,17 @@ static inline void thread__exited(struct thread *thread)
 	thread->dead = true;
 }
 
-int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp);
+int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
+		       bool exec);
+static inline int thread__set_comm(struct thread *thread, const char *comm,
+				   u64 timestamp)
+{
+	return __thread__set_comm(thread, comm, timestamp, false);
+}
+
 int thread__comm_len(struct thread *thread);
 struct comm *thread__comm(const struct thread *thread);
+struct comm *thread__exec_comm(const struct thread *thread);
 const char *thread__comm_str(const struct thread *thread);
 void thread__insert_map(struct thread *thread, struct map *map);
 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
Signature · 1 line
1.8.3.2
author reviewer
#11 lore raw

PATCH 3/52 perf tools: Add machine__thread_exec_comm()

In reply to Adrian Hunter

Add machine__thread_exec_comm() to return the comm that matches the last exec, if the comm_exec flag is present, or the last comm otherwise.

---
 tools/perf/util/machine.c | 26 ++++++++++++++++++++++++++
 tools/perf/util/machine.h |  4 ++++
 tools/perf/util/session.c | 24 +++++++++++++++++++++++-
 3 files changed, 53 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +26 -0
index c90f4e3..f0539aa 100644
@@ -28,6 +28,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 
 	machine->symbol_filter = NULL;
 	machine->id_hdr_size = 0;
+	machine->comm_exec = false;
 
 	machine->root_dir = strdup(root_dir);
 	if (machine->root_dir == NULL)
@@ -172,6 +173,19 @@ void machines__set_symbol_filter(struct machines *machines,
 	}
 }
 
+void machines__set_comm_exec(struct machines *machines, bool comm_exec)
+{
+	struct rb_node *nd;
+
+	machines->host.comm_exec = comm_exec;
+
+	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
+		struct machine *machine = rb_entry(nd, struct machine, rb_node);
+
+		machine->comm_exec = comm_exec;
+	}
+}
+
 struct machine *machines__find(struct machines *machines, pid_t pid)
 {
 	struct rb_node **p = &machines->guests.rb_node;
@@ -391,6 +405,15 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
 	return __machine__findnew_thread(machine, pid, tid, false);
 }
 
+struct comm *machine__thread_exec_comm(struct machine *machine,
+				       struct thread *thread)
+{
+	if (machine->comm_exec)
+		return thread__exec_comm(thread);
+	else
+		return thread__comm(thread);
+}
+
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
 				struct perf_sample *sample)
 {
@@ -399,6 +422,9 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
 							event->comm.tid);
 	bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
 
+	if (exec)
+		machine->comm_exec = true;
+
 	if (dump_trace)
 		perf_event__fprintf_comm(event, stdout);
 
tools/perf/util/machine.h +4 -0
index c8c74a1..383c725 100644
@@ -24,6 +24,7 @@ struct machine {
 	struct rb_node	  rb_node;
 	pid_t		  pid;
 	u16		  id_hdr_size;
+	bool		  comm_exec;
 	char		  *root_dir;
 	struct rb_root	  threads;
 	struct list_head  dead_threads;
@@ -43,6 +44,8 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
 
 struct thread *machine__find_thread(struct machine *machine, pid_t pid,
 				    pid_t tid);
+struct comm *machine__thread_exec_comm(struct machine *machine,
+				       struct thread *thread);
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
 				struct perf_sample *sample);
@@ -84,6 +87,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
 
 void machines__set_symbol_filter(struct machines *machines,
 				 symbol_filter_t symbol_filter);
+void machines__set_comm_exec(struct machines *machines, bool comm_exec);
 
 struct machine *machine__new_host(void);
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
tools/perf/util/session.c +23 -1
index eac14ce..7b0fb03 100644
@@ -67,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session)
 	machines__destroy_kernel_maps(&session->machines);
 }
 
+static bool perf_session__has_comm_exec(struct perf_session *session)
+{
+	struct perf_evsel *evsel;
+
+	evlist__for_each(session->evlist, evsel) {
+		if (evsel->attr.comm_exec)
+			return true;
+	}
+
+	return false;
+}
+
+static void perf_session__set_comm_exec(struct perf_session *session)
+{
+	bool comm_exec = perf_session__has_comm_exec(session);
+
+	machines__set_comm_exec(&session->machines, comm_exec);
+}
+
 struct perf_session *perf_session__new(struct perf_data_file *file,
 				       bool repipe, struct perf_tool *tool)
 {
@@ -92,6 +111,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
 				goto out_close;
 
 			perf_session__set_id_hdr_size(session);
+			perf_session__set_comm_exec(session);
 		}
 	}
 
@@ -1006,8 +1026,10 @@ static int perf_session__process_user_event(struct perf_session *session, union
 	switch (event->header.type) {
 	case PERF_RECORD_HEADER_ATTR:
 		err = tool->attr(tool, event, &session->evlist);
-		if (err == 0)
+		if (err == 0) {
 			perf_session__set_id_hdr_size(session);
+			perf_session__set_comm_exec(session);
+		}
 		return err;
 	case PERF_RECORD_HEADER_EVENT_TYPE:
 		/*
Signature · 1 line
1.8.3.2
author reviewer
#12 lore raw

PATCH 4/52 perf tools: Fix missing label symbols

In reply to Adrian Hunter

label symbols are missing because elf_sec__is_a() fails to find the section because the section strings do not match the section headers because the sections headers are from the 'runtime' object and the sections strings are from the 'symbol source' object.

Fix by getting the section strings from the 'runtime' object so that they match the section headers.

---
 tools/perf/util/symbol-elf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +1 -1
index cef8f42..84f5e2a 100644
@@ -736,7 +736,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
 	if (symstrs == NULL)
 		goto out_elf_end;
 
-	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
+	sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);
 	if (sec_strndx == NULL)
 		goto out_elf_end;
 
Signature · 1 line
1.8.3.2
author reviewer
#13 lore raw

PATCH 5/52 perf tools: Add machine__kernel_ip()

In reply to Adrian Hunter

Add a function to determine if an address is in
the kernel. This is based on the kernel function
kernel_ip().

---
 tools/perf/util/event.c   |  6 +++---
 tools/perf/util/machine.c | 23 +++++++++++++++++++++++
 tools/perf/util/machine.h | 17 +++++++++++++++++
 3 files changed, 43 insertions(+), 3 deletions(-)
tools/perf/util/event.c +3 -3
index 7e0e8ae..d1283cc 100644
@@ -784,9 +784,9 @@ try_again:
 		 * "[vdso]" dso, but for now lets use the old trick of looking
 		 * in the whole kernel symbol list.
 		 */
-		if ((long long)al->addr < 0 &&
-		    cpumode == PERF_RECORD_MISC_USER &&
-		    machine && mg != &machine->kmaps) {
+		if (cpumode == PERF_RECORD_MISC_USER && machine &&
+		    mg != &machine->kmaps &&
+		    machine__kernel_ip(machine, al->addr)) {
 			mg = &machine->kmaps;
 			load_map = true;
 			goto try_again;
tools/perf/util/machine.c +23 -0
index f0539aa..04c17a7 100644
@@ -29,6 +29,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 	machine->symbol_filter = NULL;
 	machine->id_hdr_size = 0;
 	machine->comm_exec = false;
+	machine->kernel_start = 0;
 
 	machine->root_dir = strdup(root_dir);
 	if (machine->root_dir == NULL)
@@ -1509,3 +1510,25 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too
 	/* command specified */
 	return 0;
 }
+
+int machine__get_kernel_start(struct machine *machine)
+{
+	struct map *map = machine__kernel_map(machine, MAP__FUNCTION);
+	int err = 0;
+
+	/*
+	 * The only addresses above 2^63 are kernel addresses of a 64-bit
+	 * kernel.  Note that addresses are unsigned so that on a 32-bit system
+	 * all addresses including kernel addresses are less than 2^32.  In
+	 * that case (32-bit system), if the kernel mapping is unknown, all
+	 * addresses will be assumed to be in user space - see
+	 * machine__kernel_ip().
+	 */
+	machine->kernel_start = 1ULL << 63;
+	if (map) {
+		err = map__load(map, machine->symbol_filter);
+		if (map->start)
+			machine->kernel_start = map->start;
+	}
+	return err;
+}
tools/perf/util/machine.h +17 -0
index 383c725..be97021 100644
@@ -33,6 +33,7 @@ struct machine {
 	struct list_head  kernel_dsos;
 	struct map_groups kmaps;
 	struct map	  *vmlinux_maps[MAP__NR_TYPES];
+	u64		  kernel_start;
 	symbol_filter_t	  symbol_filter;
 };
 
@@ -42,6 +43,22 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
 	return machine->vmlinux_maps[type];
 }
 
+int machine__get_kernel_start(struct machine *machine);
+
+static inline u64 machine__kernel_start(struct machine *machine)
+{
+	if (!machine->kernel_start)
+		machine__get_kernel_start(machine);
+	return machine->kernel_start;
+}
+
+static inline bool machine__kernel_ip(struct machine *machine, u64 ip)
+{
+	u64 kernel_start = machine__kernel_start(machine);
+
+	return ip >= kernel_start;
+}
+
 struct thread *machine__find_thread(struct machine *machine, pid_t pid,
 				    pid_t tid);
 struct comm *machine__thread_exec_comm(struct machine *machine,
Signature · 1 line
1.8.3.2
author reviewer
#14 lore raw

PATCH 6/52 perf script: Improve srcline display for BTS

In reply to Adrian Hunter

Change the order of the output to put the srcline last. e.g. old format:

          4028fc main+0x2c (/bin/ls)

/build/buildd/coreutils-8.20/src/ls.c:1269 => 40d8a0 set_program_name+0x0 (/bin/ls)

new format:

          4028fc main+0x2c (/bin/ls) =>           40d8a0 set_program_name+0x0 (/bin/ls)

/build/buildd/coreutils-8.20/src/ls.c:1269

---
 tools/perf/builtin-script.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/builtin-script.c +15 -5
index 9e9c91f..333b15e 100644
@@ -427,15 +427,22 @@ static void print_sample_bts(union perf_event *event,
 			     struct addr_location *al)
 {
 	struct perf_event_attr *attr = &evsel->attr;
+	bool print_srcline_last = false;
 
 	/* print branch_from information */
 	if (PRINT_FIELD(IP)) {
-		if (!symbol_conf.use_callchain)
-			printf(" ");
-		else
+		unsigned int print_opts = output[attr->type].print_ip_opts;
+
+		if (symbol_conf.use_callchain && sample->callchain) {
 			printf("\n");
-		perf_evsel__print_ip(evsel, sample, al,
-				     output[attr->type].print_ip_opts,
+		} else {
+			printf(" ");
+			if (print_opts & PRINT_IP_OPT_SRCLINE) {
+				print_srcline_last = true;
+				print_opts &= ~PRINT_IP_OPT_SRCLINE;
+			}
+		}
+		perf_evsel__print_ip(evsel, sample, al, print_opts,
 				     PERF_MAX_STACK_DEPTH);
 	}
 
@@ -447,6 +454,9 @@ static void print_sample_bts(union perf_event *event,
 	     !output[attr->type].user_set))
 		print_sample_addr(event, sample, al->machine, thread, attr);
 
+	if (print_srcline_last)
+		map__fprintf_srcline(al->map, al->addr, "\n  ", stdout);
+
 	printf("\n");
 }
 
Signature · 1 line
1.8.3.2
#15 lore raw

[tip:perf/core] perf script: Improve srcline display for BTS

perf script: Improve srcline display for BTS
Commit-ID:  8066be5fe755e95ee6a858bbcf4e6b9e933e1866
Gitweb:     http://git.kernel.org/tip/8066be5fe755e95ee6a858bbcf4e6b9e933e1866
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:15 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:14:40 -0300

perf script: Improve srcline display for BTS

Change the order of the output to put the srcline last.

It puts the branch 'from address' and 'to address' on the same line, which is how it would be without the source line reference.

So it makes it consistent and much easier to read.

E.g. old format:

          4028fc main+0x2c (/bin/ls)

/build/buildd/coreutils-8.20/src/ls.c:1269 => 40d8a0 set_program_name+0x0 (/bin/ls)

new format:

          4028fc main+0x2c (/bin/ls) =>           40d8a0 set_program_name+0x0 (/bin/ls)

/build/buildd/coreutils-8.20/src/ls.c:1269

---
 tools/perf/builtin-script.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/builtin-script.c +15 -5
index 9e9c91f..333b15e 100644
@@ -427,15 +427,22 @@ static void print_sample_bts(union perf_event *event,
 			     struct addr_location *al)
 {
 	struct perf_event_attr *attr = &evsel->attr;
+	bool print_srcline_last = false;
 
 	/* print branch_from information */
 	if (PRINT_FIELD(IP)) {
-		if (!symbol_conf.use_callchain)
-			printf(" ");
-		else
+		unsigned int print_opts = output[attr->type].print_ip_opts;
+
+		if (symbol_conf.use_callchain && sample->callchain) {
 			printf("\n");
-		perf_evsel__print_ip(evsel, sample, al,
-				     output[attr->type].print_ip_opts,
+		} else {
+			printf(" ");
+			if (print_opts & PRINT_IP_OPT_SRCLINE) {
+				print_srcline_last = true;
+				print_opts &= ~PRINT_IP_OPT_SRCLINE;
+			}
+		}
+		perf_evsel__print_ip(evsel, sample, al, print_opts,
 				     PERF_MAX_STACK_DEPTH);
 	}
 
@@ -447,6 +454,9 @@ static void print_sample_bts(union perf_event *event,
 	     !output[attr->type].user_set))
 		print_sample_addr(event, sample, al->machine, thread, attr);
 
+	if (print_srcline_last)
+		map__fprintf_srcline(al->map, al->addr, "\n  ", stdout);
+
 	printf("\n");
 }
 
author reviewer
#16 lore raw

PATCH 7/52 perf script: Do not print dangling '=>' for BTS

In reply to Adrian Hunter

When using:

perf record -e branches:u -c1
perf script -f ip

lines are displayed like:

	ffffffff813b23d5 =>

Change so that the dangling '=>' does not appear.

---
 tools/perf/builtin-script.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-script.c +3 -3
index 333b15e..582da97 100644
@@ -446,13 +446,13 @@ static void print_sample_bts(union perf_event *event,
 				     PERF_MAX_STACK_DEPTH);
 	}
 
-	printf(" => ");
-
 	/* print branch_to information */
 	if (PRINT_FIELD(ADDR) ||
 	    ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
-	     !output[attr->type].user_set))
+	     !output[attr->type].user_set)) {
+		printf(" => ");
 		print_sample_addr(event, sample, al->machine, thread, attr);
+	}
 
 	if (print_srcline_last)
 		map__fprintf_srcline(al->map, al->addr, "\n  ", stdout);
Signature · 1 line
1.8.3.2
#17 lore raw

[tip:perf/core] perf script: Do not print dangling '=>' for BTS

perf script: Do not print dangling '=>' for BTS
Commit-ID:  578bea40058b68f83658827c2b68a596b08419fc
Gitweb:     http://git.kernel.org/tip/578bea40058b68f83658827c2b68a596b08419fc
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:16 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:18:00 -0300

perf script: Do not print dangling '=>' for BTS

When using:

perf record -e branches:u -c1 usleep 1
perf script -f ip

lines are displayed like:

	ffffffff813b23d5 =>

Change so that the dangling '=>' does not appear.

---
 tools/perf/builtin-script.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-script.c +3 -3
index 333b15e..582da97 100644
@@ -446,13 +446,13 @@ static void print_sample_bts(union perf_event *event,
 				     PERF_MAX_STACK_DEPTH);
 	}
 
-	printf(" => ");
-
 	/* print branch_to information */
 	if (PRINT_FIELD(ADDR) ||
 	    ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
-	     !output[attr->type].user_set))
+	     !output[attr->type].user_set)) {
+		printf(" => ");
 		print_sample_addr(event, sample, al->machine, thread, attr);
+	}
 
 	if (print_srcline_last)
 		map__fprintf_srcline(al->map, al->addr, "\n  ", stdout);
author reviewer
#18 lore raw

PATCH 8/52 perf tools: Fix incorrect fd error comparison

In reply to Adrian Hunter

Zero is a valid fd. Error comparison should check for negative fd.

---
 tools/perf/util/dso.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/dso.c +1 -1
index fc006fe..28cf747 100644
@@ -216,7 +216,7 @@ static int open_dso(struct dso *dso, struct machine *machine)
 {
 	int fd = __open_dso(dso, machine);
 
-	if (fd > 0) {
+	if (fd >= 0) {
 		dso__list_add(dso);
 		/*
 		 * Check if we crossed the allowed number
Signature · 1 line
1.8.3.2
author reviewer
#19 lore raw

PATCH 9/52 perf tools: Record whether a dso has data

In reply to Adrian Hunter

Add 'data.status' to record whether a dso has data (i.e. an object file). This is used to avoid repeatedly creating the file name and attempting to open a file that is not present.

---
 tools/perf/util/dso.c | 23 +++++++++++++++--------
 tools/perf/util/dso.h |  7 +++++++
 2 files changed, 22 insertions(+), 8 deletions(-)
tools/perf/util/dso.c +15 -8
index 28cf747..8827db3 100644
@@ -331,26 +331,32 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
 	};
 	int i = 0;
 
+	if (dso->data.status == DSO_DATA_STATUS_ERROR)
+		return -1;
+
 	if (dso->data.fd >= 0)
-		return dso->data.fd;
+		goto out;
 
 	if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
 		dso->data.fd = open_dso(dso, machine);
-		return dso->data.fd;
+		goto out;
 	}
 
 	do {
-		int fd;
-
 		dso->binary_type = binary_type_data[i++];
 
-		fd = open_dso(dso, machine);
-		if (fd >= 0)
-			return dso->data.fd = fd;
+		dso->data.fd = open_dso(dso, machine);
+		if (dso->data.fd >= 0)
+			goto out;
 
 	} while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
+out:
+	if (dso->data.fd >= 0)
+		dso->data.status = DSO_DATA_STATUS_OK;
+	else
+		dso->data.status = DSO_DATA_STATUS_ERROR;
 
-	return -EINVAL;
+	return dso->data.fd;
 }
 
 static void
@@ -701,6 +707,7 @@ struct dso *dso__new(const char *name)
 			dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
 		dso->data.cache = RB_ROOT;
 		dso->data.fd = -1;
+		dso->data.status = DSO_DATA_STATUS_UNKNOWN;
 		dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
 		dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
 		dso->is_64_bit = (sizeof(void *) == 8);
tools/perf/util/dso.h +7 -0
index c239e86..aeb7bcb 100644
@@ -40,6 +40,12 @@ enum dso_swap_type {
 	DSO_SWAP__YES,
 };
 
+enum dso_data_status {
+	DSO_DATA_STATUS_ERROR	= -1,
+	DSO_DATA_STATUS_UNKNOWN	= 0,
+	DSO_DATA_STATUS_OK	= 1,
+};
+
 #define DSO__SWAP(dso, type, val)			\
 ({							\
 	type ____r = val;				\
@@ -104,6 +110,7 @@ struct dso {
 	struct {
 		struct rb_root	 cache;
 		int		 fd;
+		int		 status;
 		size_t		 file_size;
 		struct list_head open_entry;
 	} data;
Signature · 1 line
1.8.3.2
#20 lore raw

[tip:perf/core] perf tools: Record whether a dso has data

perf tools: Record whether a dso has data
Commit-ID:  c27697d6dee02ef2389b6701c792a075bc9873dc
Gitweb:     http://git.kernel.org/tip/c27697d6dee02ef2389b6701c792a075bc9873dc
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:18 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:22:35 -0300

perf tools: Record whether a dso has data

Add 'data.status' to record whether a dso has data (i.e. an object file). This is used to avoid repeatedly creating the file name and attempting to open a file that is not present.

---
 tools/perf/util/dso.c | 23 +++++++++++++++--------
 tools/perf/util/dso.h |  7 +++++++
 2 files changed, 22 insertions(+), 8 deletions(-)
tools/perf/util/dso.c +15 -8
index 28cf747..8827db3 100644
@@ -331,26 +331,32 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
 	};
 	int i = 0;
 
+	if (dso->data.status == DSO_DATA_STATUS_ERROR)
+		return -1;
+
 	if (dso->data.fd >= 0)
-		return dso->data.fd;
+		goto out;
 
 	if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
 		dso->data.fd = open_dso(dso, machine);
-		return dso->data.fd;
+		goto out;
 	}
 
 	do {
-		int fd;
-
 		dso->binary_type = binary_type_data[i++];
 
-		fd = open_dso(dso, machine);
-		if (fd >= 0)
-			return dso->data.fd = fd;
+		dso->data.fd = open_dso(dso, machine);
+		if (dso->data.fd >= 0)
+			goto out;
 
 	} while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
+out:
+	if (dso->data.fd >= 0)
+		dso->data.status = DSO_DATA_STATUS_OK;
+	else
+		dso->data.status = DSO_DATA_STATUS_ERROR;
 
-	return -EINVAL;
+	return dso->data.fd;
 }
 
 static void
@@ -701,6 +707,7 @@ struct dso *dso__new(const char *name)
 			dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
 		dso->data.cache = RB_ROOT;
 		dso->data.fd = -1;
+		dso->data.status = DSO_DATA_STATUS_UNKNOWN;
 		dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
 		dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
 		dso->is_64_bit = (sizeof(void *) == 8);
tools/perf/util/dso.h +7 -0
index c239e86..aeb7bcb 100644
@@ -40,6 +40,12 @@ enum dso_swap_type {
 	DSO_SWAP__YES,
 };
 
+enum dso_data_status {
+	DSO_DATA_STATUS_ERROR	= -1,
+	DSO_DATA_STATUS_UNKNOWN	= 0,
+	DSO_DATA_STATUS_OK	= 1,
+};
+
 #define DSO__SWAP(dso, type, val)			\
 ({							\
 	type ____r = val;				\
@@ -104,6 +110,7 @@ struct dso {
 	struct {
 		struct rb_root	 cache;
 		int		 fd;
+		int		 status;
 		size_t		 file_size;
 		struct list_head open_entry;
 	} data;
author reviewer
#21 lore raw

PATCH 10/52 perf tools: Add dso__data_status_seen()

In reply to Adrian Hunter

Add a function to track whether a caller has seen
the data status of a dso. This is needed to
enable callers to report the error exactly once
only per dso.

---
 tools/perf/util/dso.c | 12 ++++++++++++
 tools/perf/util/dso.h |  6 ++++++
 2 files changed, 18 insertions(+)
tools/perf/util/dso.c +12 -0
index 8827db3..84e4a05 100644
@@ -359,6 +359,18 @@ out:
 	return dso->data.fd;
 }
 
+bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
+{
+	u32 flag = 1 << by;
+
+	if (dso->data.status_seen & flag)
+		return true;
+
+	dso->data.status_seen |= flag;
+
+	return false;
+}
+
 static void
 dso_cache__free(struct rb_root *root)
 {
tools/perf/util/dso.h +6 -0
index aeb7bcb..c805f60 100644
@@ -46,6 +46,10 @@ enum dso_data_status {
 	DSO_DATA_STATUS_OK	= 1,
 };
 
+enum dso_data_status_seen {
+	DSO_DATA_STATUS_SEEN_ITRACE,
+};
+
 #define DSO__SWAP(dso, type, val)			\
 ({							\
 	type ____r = val;				\
@@ -111,6 +115,7 @@ struct dso {
 		struct rb_root	 cache;
 		int		 fd;
 		int		 status;
+		u32		 status_seen;
 		size_t		 file_size;
 		struct list_head open_entry;
 	} data;
@@ -203,6 +208,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
 ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
 			    struct machine *machine, u64 addr,
 			    u8 *data, ssize_t size);
+bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by);
 
 struct map *dso__new_map(const char *name);
 struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
Signature · 1 line
1.8.3.2
#22 lore raw

[tip:perf/core] perf tools: Add dso__data_status_seen()

perf tools: Add dso__data_status_seen()
Commit-ID:  288be943b5024729cd6809b61b62f727960178f3
Gitweb:     http://git.kernel.org/tip/288be943b5024729cd6809b61b62f727960178f3
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:19 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:23:44 -0300

perf tools: Add dso__data_status_seen()

Add a function to track whether a caller has seen the data status of a dso. This is needed to enable callers to report the error exactly once only per dso.

---
 tools/perf/util/dso.c | 12 ++++++++++++
 tools/perf/util/dso.h |  6 ++++++
 2 files changed, 18 insertions(+)
tools/perf/util/dso.c +12 -0
index 8827db3..84e4a05 100644
@@ -359,6 +359,18 @@ out:
 	return dso->data.fd;
 }
 
+bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
+{
+	u32 flag = 1 << by;
+
+	if (dso->data.status_seen & flag)
+		return true;
+
+	dso->data.status_seen |= flag;
+
+	return false;
+}
+
 static void
 dso_cache__free(struct rb_root *root)
 {
tools/perf/util/dso.h +6 -0
index aeb7bcb..c805f60 100644
@@ -46,6 +46,10 @@ enum dso_data_status {
 	DSO_DATA_STATUS_OK	= 1,
 };
 
+enum dso_data_status_seen {
+	DSO_DATA_STATUS_SEEN_ITRACE,
+};
+
 #define DSO__SWAP(dso, type, val)			\
 ({							\
 	type ____r = val;				\
@@ -111,6 +115,7 @@ struct dso {
 		struct rb_root	 cache;
 		int		 fd;
 		int		 status;
+		u32		 status_seen;
 		size_t		 file_size;
 		struct list_head open_entry;
 	} data;
@@ -203,6 +208,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
 ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
 			    struct machine *machine, u64 addr,
 			    u8 *data, ssize_t size);
+bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by);
 
 struct map *dso__new_map(const char *name);
 struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
author reviewer
#23 lore raw

PATCH 11/52 perf tools: Let a user specify a PMU event without any config terms

In reply to Adrian Hunter

This enables a PMU event to be specified in the form:

	pmu//

which is effectively the same as:

	pmu/config=0/

This patch is a precursor to defining
default config for a PMU.

---
 tools/perf/util/parse-events.c |  6 ++++++
 tools/perf/util/parse-events.y | 10 ++++++++++
 2 files changed, 16 insertions(+)
tools/perf/util/parse-events.c +6 -0
index 1e15df1..76fd04b 100644
@@ -644,6 +644,12 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
 
 	memset(&attr, 0, sizeof(attr));
 
+	if (!head_config) {
+		attr.type = pmu->type;
+		evsel = __add_event(list, idx, &attr, NULL, pmu->cpus);
+		return evsel ? 0 : -ENOMEM;
+	}
+
 	if (perf_pmu__check_alias(pmu, head_config, &unit, &scale))
 		return -EINVAL;
 
tools/perf/util/parse-events.y +10 -0
index 0bc87ba..55fab6a 100644
@@ -210,6 +210,16 @@ PE_NAME '/' event_config '/'
 	parse_events__free_terms($3);
 	$$ = list;
 }
+|
+PE_NAME '/' '/'
+{
+	struct parse_events_evlist *data = _data;
+	struct list_head *list;
+
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL));
+	$$ = list;
+}
 
 value_sym:
 PE_VALUE_SYM_HW
Signature · 1 line
1.8.3.2
author reviewer
#24 lore raw

PATCH 12/52 perf tools: Let default config be defined for a PMU

In reply to Adrian Hunter

This allows default config terms to be provided
for a PMU. So, for example, when the Intel PT
PMU is added, it will be possible to specify:

	intel_pt//

which will be the same as:

	intel_pt/tsc=1,noretcomp=0/

meaning that the trace should contain
TSC timestamps and perform 'return
compression'.

An important consideration of this
patch is that it must be possible
to overwrite the default values.
That has meant changing the logic
so that a zero value can replace
a non-zero value.

---
 tools/perf/tests/pmu.c         |  2 +-
 tools/perf/util/parse-events.c |  7 ++++++-
 tools/perf/util/pmu.c          | 42 ++++++++++++++++++++++++++----------------
 tools/perf/util/pmu.h          |  9 ++++++++-
 4 files changed, 41 insertions(+), 19 deletions(-)
tools/perf/tests/pmu.c +1 -1
index 12b322f..eeb68bb1 100644
@@ -152,7 +152,7 @@ int test__pmu(void)
 		if (ret)
 			break;
 
-		ret = perf_pmu__config_terms(&formats, &attr, terms);
+		ret = perf_pmu__config_terms(&formats, &attr, terms, false);
 		if (ret)
 			break;
 
tools/perf/util/parse-events.c +6 -1
index 76fd04b..20d2c1e 100644
@@ -642,7 +642,12 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
 	if (!pmu)
 		return -EINVAL;
 
-	memset(&attr, 0, sizeof(attr));
+	if (pmu->default_config) {
+		memcpy(&attr, pmu->default_config,
+		       sizeof(struct perf_event_attr));
+	} else {
+		memset(&attr, 0, sizeof(attr));
+	}
 
 	if (!head_config) {
 		attr.type = pmu->type;
tools/perf/util/pmu.c +26 -16

105 lines not on this page · raw message

tools/perf/util/pmu.h +8 -1
index c14a543..281d5b1 100644
@@ -13,9 +13,12 @@ enum {
 
 #define PERF_PMU_FORMAT_BITS 64
 
+struct perf_event_attr;
+
 struct perf_pmu {
 	char *name;
 	__u32 type;
+	struct perf_event_attr *default_config;
 	struct cpu_map *cpus;
 	struct list_head format;
 	struct list_head aliases;
@@ -27,7 +30,8 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 		     struct list_head *head_terms);
 int perf_pmu__config_terms(struct list_head *formats,
 			   struct perf_event_attr *attr,
-			   struct list_head *head_terms);
+			   struct list_head *head_terms,
+			   bool zero);
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
 			  const char **unit, double *scale);
 struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
@@ -46,4 +50,7 @@ void print_pmu_events(const char *event_glob, bool name_only);
 bool pmu_have_event(const char *pname, const char *name);
 
 int perf_pmu__test(void);
+
+struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
+
 #endif /* __PMU_H */
Signature · 1 line
1.8.3.2
author reviewer
#25 lore raw

PATCH 13/52 perf tools: Add perf_pmu__scan_file()

In reply to Adrian Hunter

Add a function to scan a sysfs file within the pmu device directory.

This will be used to read capability values from the PMU 'caps' subdirectory.

---
 tools/perf/util/pmu.c | 37 +++++++++++++++++++++++++++++++++++++
 tools/perf/util/pmu.h |  3 +++
 2 files changed, 40 insertions(+)
tools/perf/util/pmu.c +37 -0
index 11ec977..348d1d2 100644
@@ -3,6 +3,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <stdbool.h>
+#include <stdarg.h>
 #include <dirent.h>
 #include <api/fs/fs.h>
 #include <locale.h>
@@ -804,3 +805,39 @@ bool pmu_have_event(const char *pname, const char *name)
 	}
 	return false;
 }
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs__mountpoint();
+	if (!sysfs)
+		return NULL;
+
+	snprintf(path, PATH_MAX,
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	return fopen(path, "r");
+}
+
+int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
+			...)
+{
+	va_list args;
+	FILE *file;
+	int ret = EOF;
+
+	va_start(args, fmt);
+	file = perf_pmu__open_file(pmu, name);
+	if (file) {
+		ret = vfscanf(file, fmt, args);
+		fclose(file);
+	}
+	va_end(args);
+	return ret;
+}
tools/perf/util/pmu.h +3 -0
index 281d5b1..c35f578 100644
@@ -49,6 +49,9 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
 void print_pmu_events(const char *event_glob, bool name_only);
 bool pmu_have_event(const char *pname, const char *name);
 
+int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
+			...) __attribute__((format(scanf, 3, 4)));
+
 int perf_pmu__test(void);
 
 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
Signature · 1 line
1.8.3.2
#26 lore raw

Re: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()

On Tue, Jul 22, 2014 at 04:17:22PM +0300, Adrian Hunter wrote:

SNIP

Quoted 9 lines
tools/perf/util/pmu.c +9 -0
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs__mountpoint();
+	if (!sysfs)

tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826

Quoted 10 lines
tools/perf/util/pmu.c +10 -0
+		return NULL;
+
+	snprintf(path, PATH_MAX,
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	return fopen(path, "r");
+}

looks like this function could be used in pmu_cpumask and pmu_type and maybe others

jirka

author reviewer
#27 lore raw

Re: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()

Quoted 18 lines · Jiri Olsa

On Tue, Jul 22, 2014 at 04:17:22PM +0300, Adrian Hunter wrote:

SNIP

Quoted 14 lines
tools/perf/util/pmu.c +14 -0
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs__mountpoint();
+	if (!sysfs)
+		return NULL;
+
+	snprintf(path, PATH_MAX,
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
Quoted 8 lines

tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826

Quoted 5 lines
tools/perf/util/pmu.c +5 -0
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	return fopen(path, "r");
+}

looks like this function could be used in pmu_cpumask and pmu_type and maybe others

There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.

#28 lore raw

Re: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()

Quoted 28 lines · Adrian Hunter
Quoted 18 lines · Jiri Olsa

On Tue, Jul 22, 2014 at 04:17:22PM +0300, Adrian Hunter wrote:

SNIP

Quoted 14 lines
tools/perf/util/pmu.c +14 -0
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs__mountpoint();
+	if (!sysfs)
+		return NULL;
+
+	snprintf(path, PATH_MAX,
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
Quoted 8 lines

tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826

Quoted 5 lines
tools/perf/util/pmu.c +5 -0
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	return fopen(path, "r");
+}

looks like this function could be used in pmu_cpumask and pmu_type and maybe others

Quoted 2 lines

There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.

ook, jirka

#29 lore raw

Re: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()

Em Wed, Jul 23, 2014 at 11:36:38AM +0200, Jiri Olsa escreveu:

Quoted 29 lines · Adrian Hunter
Quoted 28 lines · Jiri Olsa
Quoted 26 lines · Adrian Hunter

SNIP

Quoted 9 lines
tools/perf/util/pmu.c +9 -0
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs__mountpoint();
+	if (!sysfs)

tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826

Quoted 10 lines
tools/perf/util/pmu.c +10 -0
+		return NULL;
+
+	snprintf(path, PATH_MAX,
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	return fopen(path, "r");
+}

looks like this function could be used in pmu_cpumask and pmu_type and maybe others

Quoted 4 lines
Quoted 2 lines

There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.

ook, jirka

Is this an Acked-by: jirka?

- Arnaldo

#30 lore raw

Re: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()

Quoted 30 lines · Arnaldo Carvalho de Melo

Em Wed, Jul 23, 2014 at 11:36:38AM +0200, Jiri Olsa escreveu:

Quoted 29 lines · Adrian Hunter
Quoted 28 lines · Jiri Olsa
Quoted 26 lines · Adrian Hunter

SNIP

Quoted 9 lines
tools/perf/util/pmu.c +9 -0
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs__mountpoint();
+	if (!sysfs)

tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826

Quoted 10 lines
tools/perf/util/pmu.c +10 -0
+		return NULL;
+
+	snprintf(path, PATH_MAX,
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	return fopen(path, "r");
+}

looks like this function could be used in pmu_cpumask and pmu_type and maybe others

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.

ook, jirka

Is this an Acked-by: jirka?

well, while perf_pmu__open_file would be handy now, perf_pmu__scan_file does now have any callers in the patchset..

I'm not sure whats our current policy one this ;-) as I've seen more functions like this over this patchset, I think we should not introduce new interface without caller

jirka

#31 lore raw

Re: [PATCH 13/52] perf tools: Add perf_pmu__scan_file()

Em Thu, Jul 24, 2014 at 12:06:06PM +0200, Jiri Olsa escreveu:

Quoted 36 lines · Arnaldo Carvalho de Melo
Quoted 35 lines

Em Wed, Jul 23, 2014 at 11:36:38AM +0200, Jiri Olsa escreveu:

Quoted 33 lines · Adrian Hunter
Quoted 28 lines · Jiri Olsa
Quoted 18 lines · Adrian Hunter

SNIP

Quoted 14 lines
tools/perf/util/pmu.c +14 -0
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+	struct stat st;
+	char path[PATH_MAX];
+	const char *sysfs;
+
+	sysfs = sysfs__mountpoint();
+	if (!sysfs)
+		return NULL;
+
+	snprintf(path, PATH_MAX,
+		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
Quoted 8 lines

tools/perf/util/pmu.c bool pmu_have_event(const char *pname, const char *name) · line 826

Quoted 5 lines
tools/perf/util/pmu.c +5 -0
+	if (stat(path, &st) < 0)
+		return NULL;
+
+	return fopen(path, "r");
+}

looks like this function could be used in pmu_cpumask and pmu_type and maybe others

Quoted 2 lines

There is existing code duplication between them. Given the large number of patches I would say it is easier to deal with that separately.

ook, jirka

Quoted 8 lines
Quoted 1 line

Is this an Acked-by: jirka?

well, while perf_pmu__open_file would be handy now, perf_pmu__scan_file does now have any callers in the patchset..

I'm not sure whats our current policy one this ;-) as I've seen more functions like this over this patchset, I think we should not introduce new interface without caller

Its a huge patchkit, with some bits non trivial, reducing it s size so that the most hairy bits can stand out seems like a good approach at this point. :-)

- Arnaldo

author reviewer
#32 lore raw

PATCH 14/52 perf tools: Add dsos__hit_all()

In reply to Adrian Hunter

Add ability to mark all dsos as hit.

This is needed in the case of Instruction Tracing. It takes so long to decode an Instruction Trace that it is not worth doing just to determine which dsos are hit. A later patch takes this into use.

---
 tools/perf/util/header.c | 41 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/header.h |  2 ++
 2 files changed, 43 insertions(+)
tools/perf/util/header.c +41 -0
index 893f8e2..a588a3e 100644
@@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,
 	return write_padded(fd, name, name_len + 1, len);
 }
 
+static int __dsos__hit_all(struct list_head *head)
+{
+	struct dso *pos;
+
+	list_for_each_entry(pos, head, node)
+		pos->hit = true;
+
+	return 0;
+}
+
+static int machine__hit_all_dsos(struct machine *machine)
+{
+	int err;
+
+	err = __dsos__hit_all(&machine->kernel_dsos);
+	if (err)
+		return err;
+
+	return __dsos__hit_all(&machine->user_dsos);
+}
+
+int dsos__hit_all(struct perf_session *session)
+{
+	struct rb_node *nd;
+	int err;
+
+	err = machine__hit_all_dsos(&session->machines.host);
+	if (err)
+		return err;
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+
+		err = machine__hit_all_dsos(pos);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int __dsos__write_buildid_table(struct list_head *head,
 				       struct machine *machine,
 				       pid_t pid, u16 misc, int fd)
tools/perf/util/header.h +2 -0
index d08cfe4..8f5cbae 100644
@@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool,
 				 struct perf_session *session);
 bool is_perf_magic(u64 magic);
 
+int dsos__hit_all(struct perf_session *session);
+
 /*
  * arch specific callback
  */
Signature · 1 line
1.8.3.2
#33 lore raw

[tip:perf/core] perf tools: Add dsos__hit_all()

perf tools: Add dsos__hit_all()
Commit-ID:  1f625b0b3dd641b74ba21640a1fea19a3dd893a2
Gitweb:     http://git.kernel.org/tip/1f625b0b3dd641b74ba21640a1fea19a3dd893a2
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:23 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:25:40 -0300

perf tools: Add dsos__hit_all()

Add ability to mark all dsos as hit.

This is needed in the case of Instruction Tracing. It takes so long to decode an Instruction Trace that it is not worth doing just to determine which dsos are hit. A later patch takes this into use.

---
 tools/perf/util/header.c | 41 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/header.h |  2 ++
 2 files changed, 43 insertions(+)
tools/perf/util/header.c +41 -0
index 893f8e2..a588a3e 100644
@@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,
 	return write_padded(fd, name, name_len + 1, len);
 }
 
+static int __dsos__hit_all(struct list_head *head)
+{
+	struct dso *pos;
+
+	list_for_each_entry(pos, head, node)
+		pos->hit = true;
+
+	return 0;
+}
+
+static int machine__hit_all_dsos(struct machine *machine)
+{
+	int err;
+
+	err = __dsos__hit_all(&machine->kernel_dsos);
+	if (err)
+		return err;
+
+	return __dsos__hit_all(&machine->user_dsos);
+}
+
+int dsos__hit_all(struct perf_session *session)
+{
+	struct rb_node *nd;
+	int err;
+
+	err = machine__hit_all_dsos(&session->machines.host);
+	if (err)
+		return err;
+
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+		struct machine *pos = rb_entry(nd, struct machine, rb_node);
+
+		err = machine__hit_all_dsos(pos);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 static int __dsos__write_buildid_table(struct list_head *head,
 				       struct machine *machine,
 				       pid_t pid, u16 misc, int fd)
tools/perf/util/header.h +2 -0
index d08cfe4..8f5cbae 100644
@@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool,
 				 struct perf_session *session);
 bool is_perf_magic(u64 magic);
 
+int dsos__hit_all(struct perf_session *session);
+
 /*
  * arch specific callback
  */
author reviewer
#34 lore raw

PATCH 15/52 perf tools: Add cpu to struct thread

In reply to Adrian Hunter

Tools may wish to track on which cpu a thread
is running. Add 'cpu' to struct thread for
that purpose.

This will be used to determine the cpu when
decoding a per-thread Instruction Trace.

---
 tools/perf/util/thread.c | 1 +
 tools/perf/util/thread.h | 1 +
 2 files changed, 2 insertions(+)
tools/perf/util/thread.c +1 -0
index 08f9f8b..a9df7f2 100644
@@ -34,6 +34,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		thread->pid_ = pid;
 		thread->tid = tid;
 		thread->ppid = -1;
+		thread->cpu = -1;
 		INIT_LIST_HEAD(&thread->comm_list);
 
 		comm_str = malloc(32);
tools/perf/util/thread.h +1 -0
index 9991e21..8c75fa7 100644
@@ -17,6 +17,7 @@ struct thread {
 	pid_t			pid_; /* Not all tools update this */
 	pid_t			tid;
 	pid_t			ppid;
+	int			cpu;
 	char			shortname[3];
 	bool			comm_set;
 	bool			dead; /* if set thread has exited */
Signature · 1 line
1.8.3.2
#35 lore raw

[tip:perf/core] perf tools: Add cpu to struct thread

perf tools: Add cpu to struct thread
Commit-ID:  bf49c35f630452d85c9cd7205a72df841e8d99b9
Gitweb:     http://git.kernel.org/tip/bf49c35f630452d85c9cd7205a72df841e8d99b9
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:24 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:27:50 -0300

perf tools: Add cpu to struct thread

Tools may wish to track on which cpu a thread is running. Add 'cpu' to struct thread for that purpose.

This will be used to determine the cpu when decoding a per-thread Instruction Trace.

E.g: Intel PT decoding uses sched_switch events to determine which task is running on which cpu. The Intel PT data comes straight from the hardware which doesn't know about linux threads.

---
 tools/perf/util/thread.c | 1 +
 tools/perf/util/thread.h | 1 +
 2 files changed, 2 insertions(+)
tools/perf/util/thread.c +1 -0
index 9692c06..12c7a25 100644
@@ -34,6 +34,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 		thread->pid_ = pid;
 		thread->tid = tid;
 		thread->ppid = -1;
+		thread->cpu = -1;
 		INIT_LIST_HEAD(&thread->comm_list);
 
 		comm_str = malloc(32);
tools/perf/util/thread.h +1 -0
index 3c0c272..716b772 100644
@@ -17,6 +17,7 @@ struct thread {
 	pid_t			pid_; /* Not all tools update this */
 	pid_t			tid;
 	pid_t			ppid;
+	int			cpu;
 	char			shortname[3];
 	bool			comm_set;
 	bool			dead; /* if set thread has exited */
author reviewer
#36 lore raw

PATCH 16/52 perf tools: Add ability to record the current tid for each cpu

In reply to Adrian Hunter

Add an array to struct machine to store the current tid running on each cpu. Add machine functions to get / set the tid for a cpu.

This will be used to determine the tid when decoding a per-cpu Instruction Trace.

---
 tools/perf/util/machine.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/machine.h |  5 +++++
 2 files changed, 51 insertions(+)
tools/perf/util/machine.c +46 -0
index 04c17a7..34dd63f 100644
@@ -47,6 +47,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 		thread__set_comm(thread, comm, 0);
 	}
 
+	machine->current_tid = NULL;
+
 	return 0;
 }
 
@@ -106,6 +108,7 @@ void machine__exit(struct machine *machine)
 	dsos__delete(&machine->user_dsos);
 	dsos__delete(&machine->kernel_dsos);
 	zfree(&machine->root_dir);
+	zfree(&machine->current_tid);
 }
 
 void machine__delete(struct machine *machine)
@@ -1532,3 +1535,46 @@ int machine__get_kernel_start(struct machine *machine)
 	}
 	return err;
 }
+
+pid_t machine__get_current_tid(struct machine *machine, int cpu)
+{
+	if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid)
+		return -1;
+
+	return machine->current_tid[cpu];
+}
+
+int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
+			     pid_t tid)
+{
+	struct thread *thread;
+
+	if (cpu < 0)
+		return -EINVAL;
+
+	if (!machine->current_tid) {
+		int i;
+
+		machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t));
+		if (!machine->current_tid)
+			return -ENOMEM;
+		for (i = 0; i < MAX_NR_CPUS; i++)
+			machine->current_tid[i] = -1;
+	}
+
+	if (cpu >= MAX_NR_CPUS) {
+		pr_err("Requested CPU %d too large. ", cpu);
+		pr_err("Consider raising MAX_NR_CPUS\n");
+		return -EINVAL;
+	}
+
+	machine->current_tid[cpu] = tid;
+
+	thread = machine__findnew_thread(machine, pid, tid);
+	if (!thread)
+		return -ENOMEM;
+
+	thread->cpu = cpu;
+
+	return 0;
+}
tools/perf/util/machine.h +5 -0
index be97021..6442d65 100644
@@ -35,6 +35,7 @@ struct machine {
 	struct map	  *vmlinux_maps[MAP__NR_TYPES];
 	u64		  kernel_start;
 	symbol_filter_t	  symbol_filter;
+	pid_t		  *current_tid;
 };
 
 static inline
@@ -212,4 +213,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target,
 					     perf_event__process, data_mmap);
 }
 
+pid_t machine__get_current_tid(struct machine *machine, int cpu);
+int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
+			     pid_t tid);
+
 #endif /* __PERF_MACHINE_H */
Signature · 1 line
1.8.3.2
#37 lore raw

Re: [PATCH 16/52] perf tools: Add ability to record the current tid for each cpu

Em Tue, Jul 22, 2014 at 04:17:25PM +0300, Adrian Hunter escreveu:

Quoted 7 lines

Add an array to struct machine to store the current tid running on each cpu. Add machine functions to get / set the tid for a cpu.

This will be used to determine the tid when decoding a per-cpu Instruction Trace.

Most machines don't have MAX_NR_CPUS cpus, but then this per-machine struct cost will be suffered only by tools that use this new facility, so it wouldn't be fair at this point to ask you to use a growing array.

See tools/perf/builtin-trace.c trace__set_fd_pathname() to see how it does for a thread fd->pathname table learn't from either reading /proc/PID/fd/ or using 'perf probe' made vfs_getname wannabe-tracepoints.

But in general, try to avoid using these FOO_MAX_BAR things :-\

- Arnaldo

Quoted 97 lines
---
 tools/perf/util/machine.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/machine.h |  5 +++++
 2 files changed, 51 insertions(+)
tools/perf/util/machine.c +46 -0
index 04c17a7..34dd63f 100644
@@ -47,6 +47,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 		thread__set_comm(thread, comm, 0);
 	}
 
+	machine->current_tid = NULL;
+
 	return 0;
 }
 
@@ -106,6 +108,7 @@ void machine__exit(struct machine *machine)
 	dsos__delete(&machine->user_dsos);
 	dsos__delete(&machine->kernel_dsos);
 	zfree(&machine->root_dir);
+	zfree(&machine->current_tid);
 }
 
 void machine__delete(struct machine *machine)
@@ -1532,3 +1535,46 @@ int machine__get_kernel_start(struct machine *machine)
 	}
 	return err;
 }
+
+pid_t machine__get_current_tid(struct machine *machine, int cpu)
+{
+	if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid)
+		return -1;
+
+	return machine->current_tid[cpu];
+}
+
+int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
+			     pid_t tid)
+{
+	struct thread *thread;
+
+	if (cpu < 0)
+		return -EINVAL;
+
+	if (!machine->current_tid) {
+		int i;
+
+		machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t));
+		if (!machine->current_tid)
+			return -ENOMEM;
+		for (i = 0; i < MAX_NR_CPUS; i++)
+			machine->current_tid[i] = -1;
+	}
+
+	if (cpu >= MAX_NR_CPUS) {
+		pr_err("Requested CPU %d too large. ", cpu);
+		pr_err("Consider raising MAX_NR_CPUS\n");
+		return -EINVAL;
+	}
+
+	machine->current_tid[cpu] = tid;
+
+	thread = machine__findnew_thread(machine, pid, tid);
+	if (!thread)
+		return -ENOMEM;
+
+	thread->cpu = cpu;
+
+	return 0;
+}
tools/perf/util/machine.h +5 -0
index be97021..6442d65 100644
@@ -35,6 +35,7 @@ struct machine {
 	struct map	  *vmlinux_maps[MAP__NR_TYPES];
 	u64		  kernel_start;
 	symbol_filter_t	  symbol_filter;
+	pid_t		  *current_tid;
 };
 
 static inline
@@ -212,4 +213,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target,
 					     perf_event__process, data_mmap);
 }
 
+pid_t machine__get_current_tid(struct machine *machine, int cpu);
+int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
+			     pid_t tid);
+
 #endif /* __PERF_MACHINE_H */
Signature · 1 line
1.8.3.2
#38 lore raw

[tip:perf/core] perf machine: Add ability to record the current tid for each cpu

In reply to Adrian Hunter
perf machine: Add ability to record the current tid for each cpu
Commit-ID:  b9d266baac0429f70df3f9cf751b045730d612e3
Gitweb:     http://git.kernel.org/tip/b9d266baac0429f70df3f9cf751b045730d612e3
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:25 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:35:43 -0300

perf machine: Add ability to record the current tid for each cpu

Add an array to struct machine to store the current tid running on each cpu.

Add machine functions to get / set the tid for a cpu.

This will be used to determine the tid when decoding a per-cpu Instruction Trace.

---
 tools/perf/util/machine.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/machine.h |  5 +++++
 2 files changed, 51 insertions(+)
tools/perf/util/machine.c +46 -0
index 93c8b6f..cfc6910 100644
@@ -45,6 +45,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 		thread__set_comm(thread, comm, 0);
 	}
 
+	machine->current_tid = NULL;
+
 	return 0;
 }
 
@@ -104,6 +106,7 @@ void machine__exit(struct machine *machine)
 	dsos__delete(&machine->user_dsos);
 	dsos__delete(&machine->kernel_dsos);
 	zfree(&machine->root_dir);
+	zfree(&machine->current_tid);
 }
 
 void machine__delete(struct machine *machine)
@@ -1481,3 +1484,46 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too
 	/* command specified */
 	return 0;
 }
+
+pid_t machine__get_current_tid(struct machine *machine, int cpu)
+{
+	if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid)
+		return -1;
+
+	return machine->current_tid[cpu];
+}
+
+int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
+			     pid_t tid)
+{
+	struct thread *thread;
+
+	if (cpu < 0)
+		return -EINVAL;
+
+	if (!machine->current_tid) {
+		int i;
+
+		machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t));
+		if (!machine->current_tid)
+			return -ENOMEM;
+		for (i = 0; i < MAX_NR_CPUS; i++)
+			machine->current_tid[i] = -1;
+	}
+
+	if (cpu >= MAX_NR_CPUS) {
+		pr_err("Requested CPU %d too large. ", cpu);
+		pr_err("Consider raising MAX_NR_CPUS\n");
+		return -EINVAL;
+	}
+
+	machine->current_tid[cpu] = tid;
+
+	thread = machine__findnew_thread(machine, pid, tid);
+	if (!thread)
+		return -ENOMEM;
+
+	thread->cpu = cpu;
+
+	return 0;
+}
tools/perf/util/machine.h +5 -0
index c8c74a1..8771d0c 100644
@@ -33,6 +33,7 @@ struct machine {
 	struct map_groups kmaps;
 	struct map	  *vmlinux_maps[MAP__NR_TYPES];
 	symbol_filter_t	  symbol_filter;
+	pid_t		  *current_tid;
 };
 
 static inline
@@ -191,4 +192,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target,
 					     perf_event__process, data_mmap);
 }
 
+pid_t machine__get_current_tid(struct machine *machine, int cpu);
+int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
+			     pid_t tid);
+
 #endif /* __PERF_MACHINE_H */
author reviewer
#39 lore raw

PATCH 17/52 perf evlist: Add perf_evlist__set_tracking_event()

In reply to Adrian Hunter

Add a function to change which event is used to track mmap, comm and task events.

This is needed with Instruction Tracing because the Instruction Tracing event must come first but cannot be used for tracking because it will be disabled under some circumstances.

---
 tools/perf/util/evlist.c | 20 ++++++++++++++++++++
 tools/perf/util/evlist.h |  3 +++
 2 files changed, 23 insertions(+)
tools/perf/util/evlist.c +20 -0
index 814e954..282e83e 100644
@@ -1250,3 +1250,23 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 
 	list_splice(&move, &evlist->entries);
 }
+
+int perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+				    struct perf_evsel *tracking_evsel)
+{
+	struct perf_evsel *evsel;
+
+	if (tracking_evsel->idx == 0)
+		return 0;
+
+	if (tracking_evsel->leader->nr_members > 1)
+		return -EINVAL;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (evsel->idx < tracking_evsel->idx)
+			evsel->idx += 1;
+	}
+	tracking_evsel->idx = 0;
+
+	return 0;
+}
tools/perf/util/evlist.h +3 -0
index f5173cd..657a36c 100644
@@ -262,4 +262,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 #define evlist__for_each_safe(evlist, tmp, evsel) \
 	__evlist__for_each_safe(&(evlist)->entries, tmp, evsel)
 
+int perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+				    struct perf_evsel *tracking_evsel);
+
 #endif /* __PERF_EVLIST_H */
Signature · 1 line
1.8.3.2
#40 lore raw

Re: [PATCH 17/52] perf evlist: Add perf_evlist__set_tracking_event()

On Tue, Jul 22, 2014 at 04:17:26PM +0300, Adrian Hunter wrote:

SNIP

Quoted 11 lines

}

tools/perf/util/evlist.c +10 -0
+
+int perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+				    struct perf_evsel *tracking_evsel)
+{
+	struct perf_evsel *evsel;
+
+	if (tracking_evsel->idx == 0)
+		return 0;
+
+	if (tracking_evsel->leader->nr_members > 1)

tools/perf/util/evlist.c void perf_evlist__to_front(struct perf_evlist *evlist, · line 1272

Quoted 10 lines
tools/perf/util/evlist.c +10 -0
+		return -EINVAL;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (evsel->idx < tracking_evsel->idx)
+			evsel->idx += 1;
+	}
+	tracking_evsel->idx = 0;
+
+	return 0;
+}

wouldnt it be better to add evsel->is_tracking bool for this?

jirka

author reviewer
#41 lore raw

Re: [PATCH 17/52] perf evlist: Add perf_evlist__set_tracking_event()

Quoted 19 lines · Jiri Olsa

On Tue, Jul 22, 2014 at 04:17:26PM +0300, Adrian Hunter wrote:

SNIP

Quoted 15 lines

}

tools/perf/util/evlist.c +14 -0
+
+int perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+				    struct perf_evsel *tracking_evsel)
+{
+	struct perf_evsel *evsel;
+
+	if (tracking_evsel->idx == 0)
+		return 0;
+
+	if (tracking_evsel->leader->nr_members > 1)
+		return -EINVAL;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (evsel->idx < tracking_evsel->idx)
Quoted 8 lines

tools/perf/util/evlist.c void perf_evlist__to_front(struct perf_evlist *evlist, · line 1272

Quoted 6 lines
tools/perf/util/evlist.c +6 -0
+			evsel->idx += 1;
+	}
+	tracking_evsel->idx = 0;
+
+	return 0;
+}

wouldnt it be better to add evsel->is_tracking bool for this?

Yes, I will look at doing that instead.

author reviewer
#42 lore raw

PATCH v2 17/52 perf evlist: Add perf_evlist__set_tracking_event()

Add a function to change which event is used to track mmap, comm and task events.

This is needed with Instruction Tracing because the Instruction Tracing event must come first but cannot be used for tracking because it will be disabled under some circumstances.

---

V2:
Changed to use evsel->tracking as suggested by Jiri

Note this patch now applies after the patch
"perf evlist: Add 'system_wide' option"

The change is reflected in the branch here:

http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/for-acme

 tools/perf/util/evlist.c | 17 +++++++++++++++++
 tools/perf/util/evlist.h |  3 +++
 tools/perf/util/evsel.c  |  3 ++-
 tools/perf/util/evsel.h  |  1 +
 tools/perf/util/record.c |  2 +-
 5 files changed, 24 insertions(+), 2 deletions(-)
tools/perf/util/evlist.c +17 -0
index 7cfc371..e47d724 100644
@@ -122,6 +122,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
 {
 	list_add_tail(&entry->node, &evlist->entries);
 	entry->idx = evlist->nr_entries;
+	entry->tracking = !entry->idx;
 
 	if (!evlist->nr_entries++)
 		perf_evlist__set_id_pos(evlist);
@@ -1279,3 +1280,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 
 	list_splice(&move, &evlist->entries);
 }
+
+void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+				     struct perf_evsel *tracking_evsel)
+{
+	struct perf_evsel *evsel;
+
+	if (tracking_evsel->tracking)
+		return;
+
+	evlist__for_each(evlist, evsel) {
+		if (evsel != tracking_evsel)
+			evsel->tracking = false;
+	}
+
+	tracking_evsel->tracking = true;
+}
tools/perf/util/evlist.h +3 -0
index f5173cd..e0084f9 100644
@@ -262,4 +262,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 #define evlist__for_each_safe(evlist, tmp, evsel) \
 	__evlist__for_each_safe(&(evlist)->entries, tmp, evsel)
 
+void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+				     struct perf_evsel *tracking_evsel);
+
 #endif /* __PERF_EVLIST_H */
tools/perf/util/evsel.c +2 -1
index 7baa06f..fbe0ce4 100644
@@ -162,6 +162,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
 		      struct perf_event_attr *attr, int idx)
 {
 	evsel->idx	   = idx;
+	evsel->tracking	   = !idx;
 	evsel->attr	   = *attr;
 	evsel->leader	   = evsel;
 	evsel->unit	   = "";
@@ -561,7 +562,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 {
 	struct perf_evsel *leader = evsel->leader;
 	struct perf_event_attr *attr = &evsel->attr;
-	int track = !evsel->idx; /* only the first counter needs these */
+	int track = evsel->tracking;
 	bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread;
 
 	attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
tools/perf/util/evsel.h +1 -0
index dbb2a0d..7bc314b 100644
@@ -86,6 +86,7 @@ struct perf_evsel {
 	bool			no_aux_samples;
 	bool			immediate;
 	bool			system_wide;
+	bool			tracking;
 	/* parse modifier helper */
 	int			exclude_GH;
 	int			nr_members;
tools/perf/util/record.c +1 -1
index fe8079e..787b882 100644
@@ -106,7 +106,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 
 	evlist__for_each(evlist, evsel) {
 		perf_evsel__config(evsel, opts);
-		if (!evsel->idx && use_comm_exec)
+		if (evsel->tracking && use_comm_exec)
 			evsel->attr.comm_exec = 1;
 	}
 
Signature · 1 line
1.8.3.2
Acked-by on v2 17/52
#43 lore raw

Re: [PATCH V2 17/52] perf evlist: Add perf_evlist__set_tracking_event()

Quoted 10 lines · Adrian Hunter

Add a function to change which event is used to track mmap, comm and task events.

This is needed with Instruction Tracing because the Instruction Tracing event must come first but cannot be used for tracking because it will be disabled under some circumstances.

thanks,
jirka

author reviewer
#44 lore raw

PATCH 18/52 perf evlist: Add 'system_wide' option

In reply to Adrian Hunter

Add an option to cause a selected event to be opened always without a pid when configured by perf_evsel__config().

This is needed when using the sched_switch tracepoint to follow object code execution. sched_switch occurs before the task switch and so it cannot record it in a context limited to that task. Note that also means that sched_switch is useless when capturing data per-thread, as is the 'context-switches' software event for the same reason.

---
 tools/perf/util/evlist.c | 45 +++++++++++++++++++++++++++++++++++++--------
 tools/perf/util/evsel.c  | 31 ++++++++++++++++++++++++++-----
 tools/perf/util/evsel.h  |  1 +
 3 files changed, 64 insertions(+), 13 deletions(-)
tools/perf/util/evlist.c +37 -8
index 282e83e..c295b7b 100644
@@ -265,17 +265,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
 	return 0;
 }
 
+static int perf_evlist__nr_threads(struct perf_evlist *evlist,
+				   struct perf_evsel *evsel)
+{
+	if (evsel->system_wide)
+		return 1;
+	else
+		return thread_map__nr(evlist->threads);
+}
+
 void perf_evlist__disable(struct perf_evlist *evlist)
 {
 	int cpu, thread;
 	struct perf_evsel *pos;
 	int nr_cpus = cpu_map__nr(evlist->cpus);
-	int nr_threads = thread_map__nr(evlist->threads);
+	int nr_threads;
 
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
 		evlist__for_each(evlist, pos) {
 			if (!perf_evsel__is_group_leader(pos) || !pos->fd)
 				continue;
+			nr_threads = perf_evlist__nr_threads(evlist, pos);
 			for (thread = 0; thread < nr_threads; thread++)
 				ioctl(FD(pos, cpu, thread),
 				      PERF_EVENT_IOC_DISABLE, 0);
@@ -288,12 +298,13 @@ void perf_evlist__enable(struct perf_evlist *evlist)
 	int cpu, thread;
 	struct perf_evsel *pos;
 	int nr_cpus = cpu_map__nr(evlist->cpus);
-	int nr_threads = thread_map__nr(evlist->threads);
+	int nr_threads;
 
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
 		evlist__for_each(evlist, pos) {
 			if (!perf_evsel__is_group_leader(pos) || !pos->fd)
 				continue;
+			nr_threads = perf_evlist__nr_threads(evlist, pos);
 			for (thread = 0; thread < nr_threads; thread++)
 				ioctl(FD(pos, cpu, thread),
 				      PERF_EVENT_IOC_ENABLE, 0);
@@ -305,12 +316,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
 			       struct perf_evsel *evsel)
 {
 	int cpu, thread, err;
+	int nr_cpus = cpu_map__nr(evlist->cpus);
+	int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
 	if (!evsel->fd)
 		return 0;
 
-	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		for (thread = 0; thread < evlist->threads->nr; thread++) {
+	for (cpu = 0; cpu < nr_cpus; cpu++) {
+		for (thread = 0; thread < nr_threads; thread++) {
 			err = ioctl(FD(evsel, cpu, thread),
 				    PERF_EVENT_IOC_DISABLE, 0);
 			if (err)
@@ -324,12 +337,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
 			      struct perf_evsel *evsel)
 {
 	int cpu, thread, err;
+	int nr_cpus = cpu_map__nr(evlist->cpus);
+	int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
 	if (!evsel->fd)
 		return -EINVAL;
 
-	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-		for (thread = 0; thread < evlist->threads->nr; thread++) {
+	for (cpu = 0; cpu < nr_cpus; cpu++) {
+		for (thread = 0; thread < nr_threads; thread++) {
 			err = ioctl(FD(evsel, cpu, thread),
 				    PERF_EVENT_IOC_ENABLE, 0);
 			if (err)
@@ -343,7 +358,16 @@ static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
 	int nr_cpus = cpu_map__nr(evlist->cpus);
 	int nr_threads = thread_map__nr(evlist->threads);
-	int nfds = nr_cpus * nr_threads * evlist->nr_entries;
+	int nfds = 0;
+	struct perf_evsel *evsel;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (evsel->system_wide)
+			nfds += nr_cpus;
+		else
+			nfds += nr_cpus * nr_threads;
+	}
+
 	evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
 	return evlist->pollfd != NULL ? 0 : -ENOMEM;
 }
@@ -636,7 +660,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
 	struct perf_evsel *evsel;
 
 	evlist__for_each(evlist, evsel) {
-		int fd = FD(evsel, cpu, thread);
+		int fd;
+
+		if (evsel->system_wide && thread)
+			continue;
+
+		fd = FD(evsel, cpu, thread);
 
 		if (*output == -1) {
 			*output = fd;
tools/perf/util/evsel.c +26 -5
index 21a373e..7baa06f 100644
@@ -692,6 +692,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
 	int cpu, thread;
+
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
 
 	if (evsel->fd) {
@@ -710,6 +714,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
 {
 	int cpu, thread;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	for (cpu = 0; cpu < ncpus; cpu++) {
 		for (thread = 0; thread < nthreads; thread++) {
 			int fd = FD(evsel, cpu, thread),
@@ -740,6 +747,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
 
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
 	if (evsel->sample_id == NULL)
 		return -ENOMEM;
@@ -784,6 +794,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
 	int cpu, thread;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	for (cpu = 0; cpu < ncpus; cpu++)
 		for (thread = 0; thread < nthreads; ++thread) {
 			close(FD(evsel, cpu, thread));
@@ -872,6 +885,9 @@ int __perf_evsel__read(struct perf_evsel *evsel,
 	int cpu, thread;
 	struct perf_counts_values *aggr = &evsel->counts->aggr, count;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+
 	aggr->val = aggr->ena = aggr->run = 0;
 
 	for (cpu = 0; cpu < ncpus; cpu++) {
@@ -994,13 +1010,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 			      struct thread_map *threads)
 {
-	int cpu, thread;
+	int cpu, thread, nthreads;
 	unsigned long flags = PERF_FLAG_FD_CLOEXEC;
 	int pid = -1, err;
 	enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+	else
+		nthreads = threads->nr;
+
 	if (evsel->fd == NULL &&
-	    perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
+	    perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0)
 		return -ENOMEM;
 
 	if (evsel->cgrp) {
@@ -1024,10 +1045,10 @@ retry_sample_id:
 
 	for (cpu = 0; cpu < cpus->nr; cpu++) {
 
-		for (thread = 0; thread < threads->nr; thread++) {
+		for (thread = 0; thread < nthreads; thread++) {
 			int group_fd;
 
-			if (!evsel->cgrp)
+			if (!evsel->cgrp && !evsel->system_wide)
 				pid = threads->map[thread];
 
 			group_fd = get_group_fd(evsel, cpu, thread);
@@ -1100,7 +1121,7 @@ out_close:
 			close(FD(evsel, cpu, thread));
 			FD(evsel, cpu, thread) = -1;
 		}
-		thread = threads->nr;
+		thread = nthreads;
 	} while (--cpu >= 0);
 	return err;
 }
tools/perf/util/evsel.h +1 -0
index d7f93ce..dbb2a0d 100644
@@ -85,6 +85,7 @@ struct perf_evsel {
 	bool 			needs_swap;
 	bool			no_aux_samples;
 	bool			immediate;
+	bool			system_wide;
 	/* parse modifier helper */
 	int			exclude_GH;
 	int			nr_members;
Signature · 1 line
1.8.3.2
author reviewer
#45 lore raw

PATCH 19/52 perf tools: Add id index

In reply to Adrian Hunter

Add an index of the event identifiers.

This is needed to queue Instruction
Trace samples according to the mmap
buffer from which they were recorded.

---
 tools/perf/builtin-inject.c |   1 +
 tools/perf/util/event.c     |   1 +
 tools/perf/util/event.h     |  15 ++++++
 tools/perf/util/evlist.c    |  26 ++++++++--
 tools/perf/util/evsel.h     |   3 ++
 tools/perf/util/session.c   | 122 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/session.h   |  10 ++++
 tools/perf/util/tool.h      |   3 +-
 8 files changed, 177 insertions(+), 4 deletions(-)
tools/perf/builtin-inject.c +1 -0
index cf6a605..ce691c4 100644
@@ -419,6 +419,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 			.tracing_data	= perf_event__repipe_op2_synth,
 			.finished_round	= perf_event__repipe_op2_synth,
 			.build_id	= perf_event__repipe_op2_synth,
+			.id_index	= perf_event__repipe_op2_synth,
 		},
 		.input_name  = "-",
 		.samples = LIST_HEAD_INIT(inject.samples),
tools/perf/util/event.c +1 -0
index d1283cc..dc32de0 100644
@@ -28,6 +28,7 @@ static const char *perf_event__names[] = {
 	[PERF_RECORD_HEADER_TRACING_DATA]	= "TRACING_DATA",
 	[PERF_RECORD_HEADER_BUILD_ID]		= "BUILD_ID",
 	[PERF_RECORD_FINISHED_ROUND]		= "FINISHED_ROUND",
+	[PERF_RECORD_ID_INDEX]			= "ID_INDEX",
 };
 
 const char *perf_event__name(unsigned int id)
tools/perf/util/event.h +15 -0
index e5dd40a..3fa9ab1 100644
@@ -185,6 +185,7 @@ enum perf_user_event_type { /* above any possible kernel type */
 	PERF_RECORD_HEADER_TRACING_DATA		= 66,
 	PERF_RECORD_HEADER_BUILD_ID		= 67,
 	PERF_RECORD_FINISHED_ROUND		= 68,
+	PERF_RECORD_ID_INDEX			= 69,
 	PERF_RECORD_HEADER_MAX
 };
 
@@ -211,6 +212,19 @@ struct tracing_data_event {
 	u32 size;
 };
 
+struct id_index_entry {
+	u64 id;
+	u64 idx;
+	u64 cpu;
+	u64 tid;
+};
+
+struct id_index_event {
+	struct perf_event_header header;
+	u64 nr;
+	struct id_index_entry entries[0];
+};
+
 union perf_event {
 	struct perf_event_header	header;
 	struct mmap_event		mmap;
@@ -225,6 +239,7 @@ union perf_event {
 	struct event_type_event		event_type;
 	struct tracing_data_event	tracing_data;
 	struct build_id_event		build_id;
+	struct id_index_event		id_index;
 };
 
 void perf_event__print_totals(void);
tools/perf/util/evlist.c +23 -3
index c295b7b..10514f3 100644
@@ -441,6 +441,22 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
 	return 0;
 }
 
+static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
+				     struct perf_evsel *evsel, int idx, int cpu,
+				     int thread)
+{
+	struct perf_sample_id *sid = SID(evsel, cpu, thread);
+	sid->idx = idx;
+	if (evlist->cpus && cpu >= 0)
+		sid->cpu = evlist->cpus->map[cpu];
+	else
+		sid->cpu = -1;
+	if (!evsel->system_wide && evlist->threads && thread >= 0)
+		sid->tid = evlist->threads->map[thread];
+	else
+		sid->tid = -1;
+}
+
 struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id)
 {
 	struct hlist_head *head;
@@ -676,9 +692,13 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
 				return -1;
 		}
 
-		if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
-		    perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
-			return -1;
+		if (evsel->attr.read_format & PERF_FORMAT_ID) {
+			if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread,
+						   fd) < 0)
+				return -1;
+			perf_evlist__set_sid_idx(evlist, evsel, idx, cpu,
+						 thread);
+		}
 	}
 
 	return 0;
tools/perf/util/evsel.h +3 -0
index dbb2a0d..330218a 100644
@@ -38,6 +38,9 @@ struct perf_sample_id {
 	struct hlist_node 	node;
 	u64		 	id;
 	struct perf_evsel	*evsel;
+	int			idx;
+	int			cpu;
+	pid_t			tid;
 
 	/* Holds total ID period value for PERF_SAMPLE_READ processing. */
 	u64			period;
tools/perf/util/session.c +122 -0

149 lines not on this page · raw message

tools/perf/util/session.h +10 -0
index 0321013..39327ca 100644
@@ -129,4 +129,14 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
 extern volatile int session_done;
 
 #define session_done()	(*(volatile int *)(&session_done))
+
+int perf_event__process_id_index(struct perf_tool *tool,
+				 union perf_event *event,
+				 struct perf_session *session);
+
+int perf_event__synthesize_id_index(struct perf_tool *tool,
+				    perf_event__handler_t process,
+				    struct perf_evlist *evlist,
+				    struct machine *machine);
+
 #endif /* __PERF_SESSION_H */
tools/perf/util/tool.h +2 -1
index 4385816..f07d6fe 100644
@@ -39,7 +39,8 @@ struct perf_tool {
 	event_attr_op	attr;
 	event_op2	tracing_data;
 	event_op2	finished_round,
-			build_id;
+			build_id,
+			id_index;
 	bool		ordered_samples;
 	bool		ordering_requires_timestamps;
 };
Signature · 1 line
1.8.3.2
author reviewer
#46 lore raw

PATCH 20/52 perf pmu: Let pmu's with no events show up on perf list

In reply to Adrian Hunter

perf list only lists PMUs with events. Add a
flag to cause a PMU to be also listed separately.

---
 tools/perf/util/pmu.c | 13 +++++++++++--
 tools/perf/util/pmu.h |  1 +
 2 files changed, 12 insertions(+), 2 deletions(-)
tools/perf/util/pmu.c +11 -2
index 348d1d2..ba300d9 100644
@@ -749,15 +749,18 @@ void print_pmu_events(const char *event_glob, bool name_only)
 
 	pmu = NULL;
 	len = 0;
-	while ((pmu = perf_pmu__scan(pmu)) != NULL)
+	while ((pmu = perf_pmu__scan(pmu)) != NULL) {
 		list_for_each_entry(alias, &pmu->aliases, list)
 			len++;
+		if (pmu->selectable)
+			len++;
+	}
 	aliases = malloc(sizeof(char *) * len);
 	if (!aliases)
 		return;
 	pmu = NULL;
 	j = 0;
-	while ((pmu = perf_pmu__scan(pmu)) != NULL)
+	while ((pmu = perf_pmu__scan(pmu)) != NULL) {
 		list_for_each_entry(alias, &pmu->aliases, list) {
 			char *name = format_alias(buf, sizeof(buf), pmu, alias);
 			bool is_cpu = !strcmp(pmu->name, "cpu");
@@ -774,6 +777,12 @@ void print_pmu_events(const char *event_glob, bool name_only)
 			aliases[j] = strdup(aliases[j]);
 			j++;
 		}
+		if (pmu->selectable) {
+			scnprintf(buf, sizeof(buf), "%s//", pmu->name);
+			aliases[j] = strdup(buf);
+			j++;
+		}
+	}
 	len = j;
 	qsort(aliases, len, sizeof(char *), cmp_string);
 	for (j = 0; j < len; j++) {
tools/perf/util/pmu.h +1 -0
index c35f578..8c999b3 100644
@@ -18,6 +18,7 @@ struct perf_event_attr;
 struct perf_pmu {
 	char *name;
 	__u32 type;
+	bool selectable;
 	struct perf_event_attr *default_config;
 	struct cpu_map *cpus;
 	struct list_head format;
Signature · 1 line
1.8.3.2
author reviewer
#47 lore raw

PATCH 21/52 perf session: Add ability to skip 4GiB or more

In reply to Adrian Hunter

A session can be made to skip portions of the input file. Do not limit that size to 32-bits.

---
 tools/perf/util/session.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
tools/perf/util/session.c +13 -7
index 8aa1be1..708e1c1 100644
@@ -1026,8 +1026,10 @@ static int perf_session_deliver_event(struct perf_session *session,
 	}
 }
 
-static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
-					    struct perf_tool *tool, u64 file_offset)
+static s64 perf_session__process_user_event(struct perf_session *session,
+					    union perf_event *event,
+					    struct perf_tool *tool,
+					    u64 file_offset)
 {
 	int fd = perf_data_file__fd(session->file);
 	int err;
@@ -1073,7 +1075,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)
 		swap(event, sample_id_all);
 }
 
-static int perf_session__process_event(struct perf_session *session,
+static s64 perf_session__process_event(struct perf_session *session,
 				       union perf_event *event,
 				       struct perf_tool *tool,
 				       u64 file_offset)
@@ -1184,7 +1186,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
 	union perf_event *event;
 	uint32_t size, cur_size = 0;
 	void *buf = NULL;
-	int skip = 0;
+	s64 skip = 0;
 	u64 head;
 	ssize_t err;
 	void *p;
@@ -1313,13 +1315,13 @@ int __perf_session__process_events(struct perf_session *session,
 				   u64 file_size, struct perf_tool *tool)
 {
 	int fd = perf_data_file__fd(session->file);
-	u64 head, page_offset, file_offset, file_pos;
+	u64 head, page_offset, file_offset, file_pos, size;
 	int err, mmap_prot, mmap_flags, map_idx = 0;
 	size_t	mmap_size;
 	char *buf, *mmaps[NUM_MMAPS];
 	union perf_event *event;
-	uint32_t size;
 	struct ui_progress prog;
+	s64 skip;
 
 	perf_tool__fill_defaults(tool);
 
@@ -1380,7 +1382,8 @@ more:
 	size = event->header.size;
 
 	if (size < sizeof(struct perf_event_header) ||
-	    perf_session__process_event(session, event, tool, file_pos) < 0) {
+	    (skip = perf_session__process_event(session, event, tool, file_pos))
+									< 0) {
 		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
 		       file_offset + head, event->header.size,
 		       event->header.type);
@@ -1388,6 +1391,9 @@ more:
 		goto out_err;
 	}
 
+	if (skip)
+		size += skip;
+
 	head += size;
 	file_pos += size;
 
Signature · 1 line
1.8.3.2
#48 lore raw

Re: [PATCH 21/52] perf session: Add ability to skip 4GiB or more

Em Tue, Jul 22, 2014 at 04:17:30PM +0300, Adrian Hunter escreveu:

Quoted 2 lines

A session can be made to skip portions of the input file. Do not limit that size to 32-bits.

Aren't there two changes here? One that is described in the changelog, another that makes the value returned by perf_session__process_event to be properly used if > 0?

Can you please split and provide relevant changeset comments?

- Arnaldo

Quoted 67 lines
---
 tools/perf/util/session.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
tools/perf/util/session.c +10 -7
index 8aa1be1..708e1c1 100644
@@ -1026,8 +1026,10 @@ static int perf_session_deliver_event(struct perf_session *session,
 	}
 }
 
-static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
-					    struct perf_tool *tool, u64 file_offset)
+static s64 perf_session__process_user_event(struct perf_session *session,
+					    union perf_event *event,
+					    struct perf_tool *tool,
+					    u64 file_offset)
 {
 	int fd = perf_data_file__fd(session->file);
 	int err;
@@ -1073,7 +1075,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)
 		swap(event, sample_id_all);
 }
 
-static int perf_session__process_event(struct perf_session *session,
+static s64 perf_session__process_event(struct perf_session *session,
 				       union perf_event *event,
 				       struct perf_tool *tool,
 				       u64 file_offset)
@@ -1184,7 +1186,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
 	union perf_event *event;
 	uint32_t size, cur_size = 0;
 	void *buf = NULL;
-	int skip = 0;
+	s64 skip = 0;
 	u64 head;
 	ssize_t err;
 	void *p;
@@ -1313,13 +1315,13 @@ int __perf_session__process_events(struct perf_session *session,
 				   u64 file_size, struct perf_tool *tool)
 {
 	int fd = perf_data_file__fd(session->file);
-	u64 head, page_offset, file_offset, file_pos;
+	u64 head, page_offset, file_offset, file_pos, size;
 	int err, mmap_prot, mmap_flags, map_idx = 0;
 	size_t	mmap_size;
 	char *buf, *mmaps[NUM_MMAPS];
 	union perf_event *event;
-	uint32_t size;
 	struct ui_progress prog;
+	s64 skip;
 
 	perf_tool__fill_defaults(tool);
 
@@ -1380,7 +1382,8 @@ more:
 	size = event->header.size;
 
 	if (size < sizeof(struct perf_event_header) ||
-	    perf_session__process_event(session, event, tool, file_pos) < 0) {
+	    (skip = perf_session__process_event(session, event, tool, file_pos))
+									< 0) {
 		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
 		       file_offset + head, event->header.size,
 		       event->header.type);

tools/perf/util/session.c more: · line 1396

Quoted 6 lines
tools/perf/util/session.c +3 -0
@@ -1388,6 +1391,9 @@ more:
 		goto out_err;
 	}
 
+	if (skip)
+		size += skip;
+

I.e. the above

Quoted 5 lines
tools/perf/util/session.c +0 -0
 	head += size;
 	file_pos += size;
 
Signature · 1 line
1.8.3.2
author reviewer
#49 lore raw

PATCH 1/2 perf session: Add ability to 'skip' a non-piped event stream

A piped event stream may contain arbitary sized tracepoint information following a PERF_RECORD_HEADER_TRACING_DATA event. The position in the stream has to be 'skipped' to match the start of the next event.

Provide the same ability to a non-piped event stream to allow for Instruction Trace data that may also be in a non-piped event stream.

---
 tools/perf/util/session.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
tools/perf/util/session.c +6 -1
index 8aa1be1..9d468e6 100644
@@ -1320,6 +1320,7 @@ int __perf_session__process_events(struct perf_session *session,
 	union perf_event *event;
 	uint32_t size;
 	struct ui_progress prog;
+	int skip;
 
 	perf_tool__fill_defaults(tool);
 
@@ -1380,7 +1381,8 @@ more:
 	size = event->header.size;
 
 	if (size < sizeof(struct perf_event_header) ||
-	    perf_session__process_event(session, event, tool, file_pos) < 0) {
+	    (skip = perf_session__process_event(session, event, tool, file_pos))
+									< 0) {
 		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
 		       file_offset + head, event->header.size,
 		       event->header.type);
@@ -1388,6 +1390,9 @@ more:
 		goto out_err;
 	}
 
+	if (skip)
+		size += skip;
+
 	head += size;
 	file_pos += size;
 
Signature · 1 line
1.8.3.2
author reviewer
#50 lore raw

PATCH 2/2 perf session: Add ability to skip 4GiB or more

A session can be made to skip portions of the input file. Do not limit that size to 32-bits.

---
 tools/perf/util/session.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)
tools/perf/util/session.c +8 -7
index 9d468e6..708e1c1 100644
@@ -1026,8 +1026,10 @@ static int perf_session_deliver_event(struct perf_session *session,
 	}
 }
 
-static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
-					    struct perf_tool *tool, u64 file_offset)
+static s64 perf_session__process_user_event(struct perf_session *session,
+					    union perf_event *event,
+					    struct perf_tool *tool,
+					    u64 file_offset)
 {
 	int fd = perf_data_file__fd(session->file);
 	int err;
@@ -1073,7 +1075,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)
 		swap(event, sample_id_all);
 }
 
-static int perf_session__process_event(struct perf_session *session,
+static s64 perf_session__process_event(struct perf_session *session,
 				       union perf_event *event,
 				       struct perf_tool *tool,
 				       u64 file_offset)
@@ -1184,7 +1186,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
 	union perf_event *event;
 	uint32_t size, cur_size = 0;
 	void *buf = NULL;
-	int skip = 0;
+	s64 skip = 0;
 	u64 head;
 	ssize_t err;
 	void *p;
@@ -1313,14 +1315,13 @@ int __perf_session__process_events(struct perf_session *session,
 				   u64 file_size, struct perf_tool *tool)
 {
 	int fd = perf_data_file__fd(session->file);
-	u64 head, page_offset, file_offset, file_pos;
+	u64 head, page_offset, file_offset, file_pos, size;
 	int err, mmap_prot, mmap_flags, map_idx = 0;
 	size_t	mmap_size;
 	char *buf, *mmaps[NUM_MMAPS];
 	union perf_event *event;
-	uint32_t size;
 	struct ui_progress prog;
-	int skip;
+	s64 skip;
 
 	perf_tool__fill_defaults(tool);
 
Signature · 1 line
1.8.3.2
#51 lore raw

[tip:perf/core] perf session: Add ability to skip 4GiB or more

perf session: Add ability to skip 4GiB or more
Commit-ID:  d5652d865ea734a13a16cf563937291a84d4364d
Gitweb:     http://git.kernel.org/tip/d5652d865ea734a13a16cf563937291a84d4364d
Author:     Adrian Hunter <[email protected]>
AuthorDate: Wed, 23 Jul 2014 22:19:58 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 17:07:14 -0300

perf session: Add ability to skip 4GiB or more

A session can be made to skip portions of the input file. Do not limit that size to 32-bits.

---
 tools/perf/util/session.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)
tools/perf/util/session.c +8 -7
index f4399b2..d3da105 100644
@@ -994,8 +994,10 @@ static int perf_session_deliver_event(struct perf_session *session,
 	}
 }
 
-static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
-					    struct perf_tool *tool, u64 file_offset)
+static s64 perf_session__process_user_event(struct perf_session *session,
+					    union perf_event *event,
+					    struct perf_tool *tool,
+					    u64 file_offset)
 {
 	int fd = perf_data_file__fd(session->file);
 	int err;
@@ -1037,7 +1039,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)
 		swap(event, sample_id_all);
 }
 
-static int perf_session__process_event(struct perf_session *session,
+static s64 perf_session__process_event(struct perf_session *session,
 				       union perf_event *event,
 				       struct perf_tool *tool,
 				       u64 file_offset)
@@ -1148,7 +1150,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
 	union perf_event *event;
 	uint32_t size, cur_size = 0;
 	void *buf = NULL;
-	int skip = 0;
+	s64 skip = 0;
 	u64 head;
 	ssize_t err;
 	void *p;
@@ -1277,14 +1279,13 @@ int __perf_session__process_events(struct perf_session *session,
 				   u64 file_size, struct perf_tool *tool)
 {
 	int fd = perf_data_file__fd(session->file);
-	u64 head, page_offset, file_offset, file_pos;
+	u64 head, page_offset, file_offset, file_pos, size;
 	int err, mmap_prot, mmap_flags, map_idx = 0;
 	size_t	mmap_size;
 	char *buf, *mmaps[NUM_MMAPS];
 	union perf_event *event;
-	uint32_t size;
 	struct ui_progress prog;
-	int skip;
+	s64 skip;
 
 	perf_tool__fill_defaults(tool);
 
#52 lore raw

[tip:perf/core] perf session: Add ability to 'skip' a non-piped event stream

In reply to Adrian Hunter
perf session: Add ability to 'skip' a non-piped event stream
Commit-ID:  6f917c70998d22bda6d06cb168665068c6066cd4
Gitweb:     http://git.kernel.org/tip/6f917c70998d22bda6d06cb168665068c6066cd4
Author:     Adrian Hunter <[email protected]>
AuthorDate: Wed, 23 Jul 2014 22:19:57 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 17:00:46 -0300

perf session: Add ability to 'skip' a non-piped event stream

A piped event stream may contain arbitary sized tracepoint information following a PERF_RECORD_HEADER_TRACING_DATA event. The position in the stream has to be 'skipped' to match the start of the next event.

Provide the same ability to a non-piped event stream to allow for Instruction Trace data that may also be in a non-piped event stream.

---
 tools/perf/util/session.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
tools/perf/util/session.c +6 -1
index eac14ce..f4399b2 100644
@@ -1284,6 +1284,7 @@ int __perf_session__process_events(struct perf_session *session,
 	union perf_event *event;
 	uint32_t size;
 	struct ui_progress prog;
+	int skip;
 
 	perf_tool__fill_defaults(tool);
 
@@ -1344,7 +1345,8 @@ more:
 	size = event->header.size;
 
 	if (size < sizeof(struct perf_event_header) ||
-	    perf_session__process_event(session, event, tool, file_pos) < 0) {
+	    (skip = perf_session__process_event(session, event, tool, file_pos))
+									< 0) {
 		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
 		       file_offset + head, event->header.size,
 		       event->header.type);
@@ -1352,6 +1354,9 @@ more:
 		goto out_err;
 	}
 
+	if (skip)
+		size += skip;
+
 	head += size;
 	file_pos += size;
 
author reviewer
#53 lore raw

PATCH 22/52 perf session: Add perf_session__deliver_synth_event()

In reply to Adrian Hunter

Add a function to deliver synthesized events from
within a session.

---
 tools/perf/util/session.c | 14 ++++++++++++++
 tools/perf/util/session.h |  5 +++++
 2 files changed, 19 insertions(+)
tools/perf/util/session.c +14 -0
index 708e1c1..433884c 100644
@@ -1066,6 +1066,20 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 	}
 }
 
+int perf_session__deliver_synth_event(struct perf_session *session,
+				      union perf_event *event,
+				      struct perf_sample *sample,
+				      struct perf_tool *tool)
+{
+	events_stats__inc(&session->stats, event->header.type);
+
+	if (event->header.type >= PERF_RECORD_USER_TYPE_START)
+		return perf_session__process_user_event(session, event, tool,
+							0);
+
+	return perf_session_deliver_event(session, event, sample, tool, 0);
+}
+
 static void event_swap(union perf_event *event, bool sample_id_all)
 {
 	perf_event__swap_op swap;
tools/perf/util/session.h +5 -0
index 39327ca..86f1bb4 100644
@@ -130,6 +130,11 @@ extern volatile int session_done;
 
 #define session_done()	(*(volatile int *)(&session_done))
 
+int perf_session__deliver_synth_event(struct perf_session *session,
+				      union perf_event *event,
+				      struct perf_sample *sample,
+				      struct perf_tool *tool);
+
 int perf_event__process_id_index(struct perf_tool *tool,
 				 union perf_event *event,
 				 struct perf_session *session);
Signature · 1 line
1.8.3.2
author reviewer
#54 lore raw

PATCH 23/52 perf tools: Move rdtsc() function

In reply to Adrian Hunter

Move the rdtsc() function so it can
be reusued.

---
 tools/perf/arch/x86/util/tsc.c      | 9 +++++++++
 tools/perf/tests/perf-time-to-tsc.c | 9 ---------
 tools/perf/util/tsc.c               | 5 +++++
 tools/perf/util/tsc.h               | 1 +
 4 files changed, 15 insertions(+), 9 deletions(-)
tools/perf/arch/x86/util/tsc.c +9 -0
index 3655f24..fd28684 100644
@@ -37,3 +37,12 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 
 	return 0;
 }
+
+u64 rdtsc(void)
+{
+	unsigned int low, high;
+
+	asm volatile("rdtsc" : "=a" (low), "=d" (high));
+
+	return low | ((u64)high) << 32;
+}
tools/perf/tests/perf-time-to-tsc.c +0 -9
index 0372f6e..f238442 100644
@@ -25,15 +25,6 @@
 	}					\
 }
 
-static u64 rdtsc(void)
-{
-	unsigned int low, high;
-
-	asm volatile("rdtsc" : "=a" (low), "=d" (high));
-
-	return low | ((u64)high) << 32;
-}
-
 /**
  * test__perf_time_to_tsc - test converting perf time to TSC.
  *
tools/perf/util/tsc.c +5 -0
index ef4749836..4d4210d 100644
@@ -23,3 +23,8 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
 	return tc->time_zero + quot * tc->time_mult +
 	       ((rem * tc->time_mult) >> tc->time_shift);
 }
+
+u64 __weak rdtsc(void)
+{
+	return 0;
+}
tools/perf/util/tsc.h +1 -0
index 4eca848..a8b78f1 100644
@@ -7,5 +7,6 @@
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
+u64 rdtsc(void);
 
 #endif
Signature · 1 line
1.8.3.2
#55 lore raw

[tip:perf/core] perf tools: Move rdtsc() function

perf tools: Move rdtsc() function
Commit-ID:  a6a69db4b686e51045771945669bba6578af67c1
Gitweb:     http://git.kernel.org/tip/a6a69db4b686e51045771945669bba6578af67c1
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:32 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:48:11 -0300

perf tools: Move rdtsc() function

Move the rdtsc() function so it can be reusued.

---
 tools/perf/arch/x86/util/tsc.c      | 9 +++++++++
 tools/perf/tests/perf-time-to-tsc.c | 9 ---------
 tools/perf/util/tsc.c               | 5 +++++
 tools/perf/util/tsc.h               | 1 +
 4 files changed, 15 insertions(+), 9 deletions(-)
tools/perf/arch/x86/util/tsc.c +9 -0
index 3655f24..fd28684 100644
@@ -37,3 +37,12 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 
 	return 0;
 }
+
+u64 rdtsc(void)
+{
+	unsigned int low, high;
+
+	asm volatile("rdtsc" : "=a" (low), "=d" (high));
+
+	return low | ((u64)high) << 32;
+}
tools/perf/tests/perf-time-to-tsc.c +0 -9
index 0372f6e..f238442 100644
@@ -25,15 +25,6 @@
 	}					\
 }
 
-static u64 rdtsc(void)
-{
-	unsigned int low, high;
-
-	asm volatile("rdtsc" : "=a" (low), "=d" (high));
-
-	return low | ((u64)high) << 32;
-}
-
 /**
  * test__perf_time_to_tsc - test converting perf time to TSC.
  *
tools/perf/util/tsc.c +5 -0
index ef4749836..4d4210d 100644
@@ -23,3 +23,8 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
 	return tc->time_zero + quot * tc->time_mult +
 	       ((rem * tc->time_mult) >> tc->time_shift);
 }
+
+u64 __weak rdtsc(void)
+{
+	return 0;
+}
tools/perf/util/tsc.h +1 -0
index 4eca848..a8b78f1 100644
@@ -7,5 +7,6 @@
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
+u64 rdtsc(void);
 
 #endif
author reviewer
#56 lore raw

PATCH 24/52 perf evlist: Add perf_evlist__enable_event_idx()

In reply to Adrian Hunter

Add a function to enable a specific event
within a specific perf event buffer.

---
 tools/perf/util/evlist.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h |  2 ++
 2 files changed, 49 insertions(+)
tools/perf/util/evlist.c +47 -0
index 10514f3..8eb6e72 100644
@@ -354,6 +354,53 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
 	return 0;
 }
 
+static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
+					 struct perf_evsel *evsel, int cpu)
+{
+	int thread, err;
+	int nr_threads = perf_evlist__nr_threads(evlist, evsel);
+
+	if (!evsel->fd)
+		return -EINVAL;
+
+	for (thread = 0; thread < nr_threads; thread++) {
+		err = ioctl(FD(evsel, cpu, thread),
+			    PERF_EVENT_IOC_ENABLE, 0);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
+					    struct perf_evsel *evsel,
+					    int thread)
+{
+	int cpu, err;
+	int nr_cpus = cpu_map__nr(evlist->cpus);
+
+	if (!evsel->fd)
+		return -EINVAL;
+
+	for (cpu = 0; cpu < nr_cpus; cpu++) {
+		err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
+				  struct perf_evsel *evsel, int idx)
+{
+	bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus);
+
+	if (per_cpu_mmaps)
+		return perf_evlist__enable_event_cpu(evlist, evsel, idx);
+	else
+		return perf_evlist__enable_event_thread(evlist, evsel, idx);
+}
+
 static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
 	int nr_cpus = cpu_map__nr(evlist->cpus);
tools/perf/util/evlist.h +2 -0
index 657a36c..70f2676 100644
@@ -122,6 +122,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
 			       struct perf_evsel *evsel);
 int perf_evlist__enable_event(struct perf_evlist *evlist,
 			      struct perf_evsel *evsel);
+int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
+				  struct perf_evsel *evsel, int idx);
 
 void perf_evlist__set_selected(struct perf_evlist *evlist,
 			       struct perf_evsel *evsel);
Signature · 1 line
1.8.3.2
author reviewer
#57 lore raw

PATCH 25/52 perf session: Add perf_session__peek_event()

In reply to Adrian Hunter

Add a function to peek at other events in the
event stream.

---
 tools/perf/util/session.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/session.h |  5 +++++
 2 files changed, 60 insertions(+)
tools/perf/util/session.c +55 -0
index 433884c..ca3cd1f 100644
@@ -1089,6 +1089,61 @@ static void event_swap(union perf_event *event, bool sample_id_all)
 		swap(event, sample_id_all);
 }
 
+int perf_session__peek_event(struct perf_session *session, off_t file_offset,
+			     void *buf, size_t buf_sz,
+			     union perf_event **event_ptr,
+			     struct perf_sample *sample)
+{
+	union perf_event *event;
+	size_t hdr_sz, rest;
+	int fd;
+
+	if (session->one_mmap && !session->header.needs_swap) {
+		event = file_offset - session->one_mmap_offset +
+			session->one_mmap_addr;
+		goto out_parse_sample;
+	}
+
+	if (perf_data_file__is_pipe(session->file))
+		return -1;
+
+	fd = perf_data_file__fd(session->file);
+	hdr_sz = sizeof(struct perf_event_header);
+
+	if (buf_sz < hdr_sz)
+		return -1;
+
+	if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 ||
+	    readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz)
+		return -1;
+
+	event = (union perf_event *)buf;
+
+	if (session->header.needs_swap)
+		perf_event_header__bswap(&event->header);
+
+	if (event->header.size < hdr_sz)
+		return -1;
+
+	rest = event->header.size - hdr_sz;
+
+	if (readn(fd, &buf, rest) != (ssize_t)rest)
+		return -1;
+
+	if (session->header.needs_swap)
+		event_swap(event, perf_evlist__sample_id_all(session->evlist));
+
+out_parse_sample:
+
+	if (sample && event->header.type < PERF_RECORD_USER_TYPE_START &&
+	    perf_evlist__parse_sample(session->evlist, event, sample))
+		return -1;
+
+	*event_ptr = event;
+
+	return 0;
+}
+
 static s64 perf_session__process_event(struct perf_session *session,
 				       union perf_event *event,
 				       struct perf_tool *tool,
tools/perf/util/session.h +5 -0
index 86f1bb4..e4ea0cf5 100644
@@ -58,6 +58,11 @@ void perf_session__delete(struct perf_session *session);
 
 void perf_event_header__bswap(struct perf_event_header *hdr);
 
+int perf_session__peek_event(struct perf_session *session, off_t file_offset,
+			     void *buf, size_t buf_sz,
+			     union perf_event **event_ptr,
+			     struct perf_sample *sample);
+
 int __perf_session__process_events(struct perf_session *session,
 				   u64 data_offset, u64 data_size, u64 size,
 				   struct perf_tool *tool);
Signature · 1 line
1.8.3.2
author reviewer
#58 lore raw

PATCH 26/52 perf tools: Add dso__data_size()

In reply to Adrian Hunter

Add a function to return the dso data size, for use in estimating the size an instruction cache.

---
 tools/perf/util/dso.c | 22 ++++++++++++++++++++++
 tools/perf/util/dso.h |  2 ++
 2 files changed, 24 insertions(+)
tools/perf/util/dso.c +22 -0
index 84e4a05..e657d86 100644
@@ -544,6 +544,28 @@ static int data_file_size(struct dso *dso)
 	return 0;
 }
 
+/**
+ * dso__data_size - Return dso data size
+ * @dso: dso object
+ * @machine: machine object
+ *
+ * Return: dso data size
+ */
+off_t dso__data_size(struct dso *dso, struct machine *machine)
+{
+	int fd;
+
+	fd = dso__data_fd(dso, machine);
+	if (fd < 0)
+		return fd;
+
+	if (data_file_size(dso))
+		return -1;
+
+	/* For now just estimate dso data size is close to file size */
+	return dso->data.file_size;
+}
+
 static ssize_t data_read_offset(struct dso *dso, u64 offset,
 				u8 *data, ssize_t size)
 {
tools/perf/util/dso.h +2 -0
index c805f60..af1c256 100644
@@ -166,6 +166,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
  * The dso__data_* external interface provides following functions:
  *   dso__data_fd
  *   dso__data_close
+ *   dso__data_size
  *   dso__data_read_offset
  *   dso__data_read_addr
  *
@@ -203,6 +204,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
 int dso__data_fd(struct dso *dso, struct machine *machine);
 void dso__data_close(struct dso *dso);
 
+off_t dso__data_size(struct dso *dso, struct machine *machine);
 ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
 			      u64 offset, u8 *data, ssize_t size);
 ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
Signature · 1 line
1.8.3.2
#59 lore raw

[tip:perf/core] perf tools: Add dso__data_size()

perf tools: Add dso__data_size()
Commit-ID:  6d363459d7e6e05f0afeb8e36e6de262a4964694
Gitweb:     http://git.kernel.org/tip/6d363459d7e6e05f0afeb8e36e6de262a4964694
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:35 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 11:57:27 -0300

perf tools: Add dso__data_size()

Add a function to return the dso data size, for use in estimating the size an instruction cache.

---
 tools/perf/util/dso.c | 22 ++++++++++++++++++++++
 tools/perf/util/dso.h |  2 ++
 2 files changed, 24 insertions(+)
tools/perf/util/dso.c +22 -0
index 84e4a05..e657d86 100644
@@ -544,6 +544,28 @@ static int data_file_size(struct dso *dso)
 	return 0;
 }
 
+/**
+ * dso__data_size - Return dso data size
+ * @dso: dso object
+ * @machine: machine object
+ *
+ * Return: dso data size
+ */
+off_t dso__data_size(struct dso *dso, struct machine *machine)
+{
+	int fd;
+
+	fd = dso__data_fd(dso, machine);
+	if (fd < 0)
+		return fd;
+
+	if (data_file_size(dso))
+		return -1;
+
+	/* For now just estimate dso data size is close to file size */
+	return dso->data.file_size;
+}
+
 static ssize_t data_read_offset(struct dso *dso, u64 offset,
 				u8 *data, ssize_t size)
 {
tools/perf/util/dso.h +2 -0
index c805f60..af1c256 100644
@@ -166,6 +166,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
  * The dso__data_* external interface provides following functions:
  *   dso__data_fd
  *   dso__data_close
+ *   dso__data_size
  *   dso__data_read_offset
  *   dso__data_read_addr
  *
@@ -203,6 +204,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
 int dso__data_fd(struct dso *dso, struct machine *machine);
 void dso__data_close(struct dso *dso);
 
+off_t dso__data_size(struct dso *dso, struct machine *machine);
 ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
 			      u64 offset, u8 *data, ssize_t size);
 ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
author reviewer
#60 lore raw

PATCH 27/52 perf tools: Add a thread stack for synthesizing call chains

In reply to Adrian Hunter

Add a thread stack for synthesizing call chains from call and return events.

---
 tools/perf/Makefile.perf       |   2 +
 tools/perf/util/event.h        |  26 +++++++
 tools/perf/util/thread-stack.c | 151 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/thread-stack.h |  32 +++++++++
 tools/perf/util/thread.c       |   3 +
 tools/perf/util/thread.h       |   3 +
 6 files changed, 217 insertions(+)
 create mode 100644 tools/perf/util/thread-stack.c
 create mode 100644 tools/perf/util/thread-stack.h
tools/perf/Makefile.perf +2 -0
index 2240974..f4333b5 100644
@@ -302,6 +302,7 @@ LIB_H += ui/util.h
 LIB_H += ui/ui.h
 LIB_H += util/data.h
 LIB_H += util/kvm-stat.h
+LIB_H += util/thread-stack.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -377,6 +378,7 @@ LIB_OBJS += $(OUTPUT)util/srcline.o
 LIB_OBJS += $(OUTPUT)util/data.o
 LIB_OBJS += $(OUTPUT)util/tsc.o
 LIB_OBJS += $(OUTPUT)util/cloexec.o
+LIB_OBJS += $(OUTPUT)util/thread-stack.o
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/util/event.h +26 -0
index 3fa9ab1..ae75b48 100644
@@ -143,6 +143,32 @@ struct branch_stack {
 	struct branch_entry	entries[0];
 };
 
+enum {
+	PERF_FLAG_BRANCH		= 1ULL << 0,
+	PERF_FLAG_CALL			= 1ULL << 1,
+	PERF_FLAG_RETURN		= 1ULL << 2,
+	PERF_FLAG_CONDITIONAL		= 1ULL << 3,
+	PERF_FLAG_SYSCALLRET		= 1ULL << 4,
+	PERF_FLAG_ASYNC			= 1ULL << 5,
+	PERF_FLAG_INTERRUPT		= 1ULL << 6,
+	PERF_FLAG_TX_ABORT		= 1ULL << 7,
+	PERF_FLAG_TRACE_BEGIN		= 1ULL << 8,
+	PERF_FLAG_TRACE_END		= 1ULL << 9,
+	PERF_FLAG_IN_TX			= 1ULL << 10,
+};
+
+#define PERF_BRANCH_MASK	(\
+	PERF_FLAG_BRANCH	|\
+	PERF_FLAG_CALL		|\
+	PERF_FLAG_RETURN	|\
+	PERF_FLAG_CONDITIONAL	|\
+	PERF_FLAG_SYSCALLRET	|\
+	PERF_FLAG_ASYNC		|\
+	PERF_FLAG_INTERRUPT	|\
+	PERF_FLAG_TX_ABORT	|\
+	PERF_FLAG_TRACE_BEGIN	|\
+	PERF_FLAG_TRACE_END)
+
 struct perf_sample {
 	u64 ip;
 	u32 pid, tid;
tools/perf/util/thread-stack.c new file +151 -0

151 lines not on this page · raw message

tools/perf/util/thread-stack.h new file +32 -0
new file mode 100644
index 0000000..c0ba4cf
@@ -0,0 +1,32 @@
+/*
+ * thread-stack.h: Synthesize a thread's stack using call / return events
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __PERF_THREAD_STACK_H
+#define __PERF_THREAD_STACK_H
+
+#include <sys/types.h>
+
+#include <linux/types.h>
+
+struct thread;
+struct ip_callchain;
+
+void thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
+			 u64 to_ip, u16 insn_len, u64 trace_nr);
+void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
+			  size_t sz, u64 ip);
+void thread_stack__free(struct thread *thread);
+
+#endif
tools/perf/util/thread.c +3 -0
index a9df7f2..088c036 100644
@@ -4,6 +4,7 @@
 #include <string.h>
 #include "session.h"
 #include "thread.h"
+#include "thread-stack.h"
 #include "util.h"
 #include "debug.h"
 #include "comm.h"
@@ -61,6 +62,8 @@ void thread__delete(struct thread *thread)
 {
 	struct comm *comm, *tmp;
 
+	thread_stack__free(thread);
+
 	if (thread->mg) {
 		map_groups__put(thread->mg);
 		thread->mg = NULL;
tools/perf/util/thread.h +3 -0
index 8c75fa7..a057820 100644
@@ -8,6 +8,8 @@
 #include "symbol.h"
 #include <strlist.h>
 
+struct thread_stack;
+
 struct thread {
 	union {
 		struct rb_node	 rb_node;
@@ -25,6 +27,7 @@ struct thread {
 	int			comm_len;
 
 	void			*priv;
+	struct thread_stack	*ts;
 };
 
 struct machine;
Signature · 1 line
1.8.3.2
author reviewer
#61 lore raw

PATCH 28/52 perf script: Allow callchains if any event samples them

In reply to Adrian Hunter

perf script was not displaying callchains if any selected event did not have PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not have PERF_SAMPLE_CALLCHAIN.

---
 tools/perf/builtin-script.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
tools/perf/builtin-script.c +13 -4
index 582da97..c1a56f2 100644
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
 		if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
 					    PERF_OUTPUT_IP))
 			return -EINVAL;
-
-		if (!no_callchain &&
-		    !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
-			symbol_conf.use_callchain = false;
 	}
 
 	if (PRINT_FIELD(ADDR) &&
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)
 		set_print_ip_opts(&evsel->attr);
 	}
 
+	if (!no_callchain) {
+		bool use_callchain = false;
+
+		evlist__for_each(session->evlist, evsel) {
+			if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
+				use_callchain = true;
+				break;
+			}
+		}
+		if (!use_callchain)
+			symbol_conf.use_callchain = false;
+	}
+
 	/*
 	 * set default for tracepoints to print symbols only
 	 * if callchains are present
Signature · 1 line
1.8.3.2
#62 lore raw

Re: [PATCH 28/52] perf script: Allow callchains if any event samples them

Em Tue, Jul 22, 2014 at 04:17:37PM +0300, Adrian Hunter escreveu:

Quoted 4 lines

perf script was not displaying callchains if any selected event did not have PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not have PERF_SAMPLE_CALLCHAIN.

I wonder if some other tool gets this wrong as well, report maybe?

Perhaps we need to have this check in some perf_evlist method?

Wonder how report/top, i.e. the hists browser will react with some events having callchains while some don't, specially with this new children stuff, Namhyung, can you please check that?

Adrian, can you, in a case like that, provide a command line that creates such combo? I.e. how to create a perf.data file with multiple events with some having callchains while some don't.

As a rule, it is better to ease reproducing behaviour you mention when fixing stuff, so that quickly others can try and go on trying to fix it.

Thanks,

- Arnaldo

Quoted 42 lines
---
 tools/perf/builtin-script.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
tools/perf/builtin-script.c +13 -4
index 582da97..c1a56f2 100644
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
 		if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
 					    PERF_OUTPUT_IP))
 			return -EINVAL;
-
-		if (!no_callchain &&
-		    !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
-			symbol_conf.use_callchain = false;
 	}
 
 	if (PRINT_FIELD(ADDR) &&
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)
 		set_print_ip_opts(&evsel->attr);
 	}
 
+	if (!no_callchain) {
+		bool use_callchain = false;
+
+		evlist__for_each(session->evlist, evsel) {
+			if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
+				use_callchain = true;
+				break;
+			}
+		}
+		if (!use_callchain)
+			symbol_conf.use_callchain = false;
+	}
+
 	/*
 	 * set default for tracepoints to print symbols only
 	 * if callchains are present
Signature · 1 line
1.8.3.2
#63 lore raw

Re: [PATCH 28/52] perf script: Allow callchains if any event samples them

Quoted 8 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 22, 2014 at 04:17:37PM +0300, Adrian Hunter escreveu:

Quoted 4 lines

perf script was not displaying callchains if any selected event did not have PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not have PERF_SAMPLE_CALLCHAIN.

I wonder if some other tool gets this wrong as well, report maybe?

perf only handles 1 sample_type so if callchains are enabled for 1 event they are enabled for all.

Perhaps Adrian's patch set changes that -- prior patch sets attempted to. I have not had time to go through the list.

David

author reviewer
#64 lore raw

Re: [PATCH 28/52] perf script: Allow callchains if any event samples them

In reply to Arnaldo Carvalho de Melo
Quoted 7 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 22, 2014 at 04:17:37PM +0300, Adrian Hunter escreveu:

Quoted 4 lines

perf script was not displaying callchains if any selected event did not have PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not have PERF_SAMPLE_CALLCHAIN.

I wonder if some other tool gets this wrong as well, report maybe?

perf report was ok

Quoted 2 lines

Perhaps we need to have this check in some perf_evlist method?

Possibly

Quoted 8 lines

Wonder how report/top, i.e. the hists browser will react with some events having callchains while some don't, specially with this new children stuff, Namhyung, can you please check that?

Adrian, can you, in a case like that, provide a command line that creates such combo? I.e. how to create a perf.data file with multiple events with some having callchains while some don't.

For now, it looks like this is something that only Intel PT will do. Intel PT decoding can create "instructions" samples that look like they came from the "instructions" hardware event, and then Intel PT will optionally synthesize call chains on them as well.

Quoted 50 lines

As a rule, it is better to ease reproducing behaviour you mention when fixing stuff, so that quickly others can try and go on trying to fix it.

Thanks,

- Arnaldo

Quoted 42 lines
---
  tools/perf/builtin-script.c | 17 +++++++++++++----
  1 file changed, 13 insertions(+), 4 deletions(-)
tools/perf/builtin-script.c +13 -5
index 582da97..c1a56f2 100644
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
  		if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
  					    PERF_OUTPUT_IP))
  			return -EINVAL;
-
-		if (!no_callchain &&
-		    !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
-			symbol_conf.use_callchain = false;
  	}
 
  	if (PRINT_FIELD(ADDR) &&
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)
  		set_print_ip_opts(&evsel->attr);
  	}
 
+	if (!no_callchain) {
+		bool use_callchain = false;
+
+		evlist__for_each(session->evlist, evsel) {
+			if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
+				use_callchain = true;
+				break;
+			}
+		}
+		if (!use_callchain)
+			symbol_conf.use_callchain = false;
+	}
+
  	/*
  	 * set default for tracepoints to print symbols only
  	 * if callchains are present
--

1.8.3.2

maintainer
#65 lore raw

Re: [PATCH 28/52] perf script: Allow callchains if any event samples them

In reply to Arnaldo Carvalho de Melo

Hi Arnaldo,

Quoted 6 lines · Arnaldo Carvalho de Melo

Em Tue, Jul 22, 2014 at 04:17:37PM +0300, Adrian Hunter escreveu:

Quoted 4 lines

perf script was not displaying callchains if any selected event did not have PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not have PERF_SAMPLE_CALLCHAIN.

Quoted 7 lines

I wonder if some other tool gets this wrong as well, report maybe?

Perhaps we need to have this check in some perf_evlist method?

Wonder how report/top, i.e. the hists browser will react with some events having callchains while some don't, specially with this new children stuff, Namhyung, can you please check that?

The children/cumulate stuff is enabled if a combined sample type contains PERF_SAMPLE_CALLCHAIN and works only a sample actually contains callchain.

So I guess if some have it and some don't, events don't have callchain just prints real entries/samples with same children overhead value.

Thanks,
Namhyung

author reviewer
#66 lore raw

PATCH 29/52 perf inject: Add --kallsyms parameter

In reply to Adrian Hunter

Let perf inject take --kallsyms parameter the same as perf script and perf report do. That is needed for decoding Instruction Trace data using a copy of /proc/kcore for the kernel object because the kallsyms path is used to locate that copy.

---
 tools/perf/Documentation/perf-inject.txt | 3 +++
 tools/perf/builtin-inject.c              | 2 ++
 2 files changed, 5 insertions(+)
tools/perf/Documentation/perf-inject.txt +3 -0
index a00a342..dc7442c 100644
@@ -41,6 +41,9 @@ OPTIONS
 	tasks slept. sched_switch contains a callchain where a task slept and
 	sched_stat contains a timeslice how long a task slept.
 
+--kallsyms=<file>::
+	kallsyms pathname
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
tools/perf/builtin-inject.c +2 -0
index ce691c4..af17800 100644
@@ -440,6 +440,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 			    "where and how long tasks slept"),
 		OPT_INCR('v', "verbose", &verbose,
 			 "be more verbose (show build ids, etc)"),
+		OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
+			   "kallsyms pathname"),
 		OPT_END()
 	};
 	const char * const inject_usage[] = {
Signature · 1 line
1.8.3.2
#67 lore raw

[tip:perf/core] perf inject: Add --kallsyms parameter

perf inject: Add --kallsyms parameter
Commit-ID:  a7a2b8b4ce9e0bfd085c5797d535487594a71882
Gitweb:     http://git.kernel.org/tip/a7a2b8b4ce9e0bfd085c5797d535487594a71882
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:38 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 25 Jul 2014 12:08:34 -0300

perf inject: Add --kallsyms parameter

Let perf inject take --kallsyms parameter the same as perf script and perf report do.

That is needed for decoding Instruction Trace data using a copy of /proc/kcore for the kernel object because the kallsyms path is used to locate that copy.

---
 tools/perf/Documentation/perf-inject.txt | 3 +++
 tools/perf/builtin-inject.c              | 2 ++
 2 files changed, 5 insertions(+)
tools/perf/Documentation/perf-inject.txt +3 -0
index a00a342..dc7442c 100644
@@ -41,6 +41,9 @@ OPTIONS
 	tasks slept. sched_switch contains a callchain where a task slept and
 	sched_stat contains a timeslice how long a task slept.
 
+--kallsyms=<file>::
+	kallsyms pathname
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
tools/perf/builtin-inject.c +2 -0
index cf6a605..9a02807 100644
@@ -439,6 +439,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 			    "where and how long tasks slept"),
 		OPT_INCR('v', "verbose", &verbose,
 			 "be more verbose (show build ids, etc)"),
+		OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
+			   "kallsyms pathname"),
 		OPT_END()
 	};
 	const char * const inject_usage[] = {
author reviewer
#68 lore raw

PATCH 30/52 perf tools: Expose 'addr' functions so they can be reused

In reply to Adrian Hunter

Move some functions and functionality related to the use of 'addr' out of builtin-script so they can be reused. The moved functions are: is_bts_event() and sample_addr_correlates_sym() and a new function perf_event__preprocess_sample_addr() is created from bits of print_sample_addr(). perf_event__preprocess_sample_addr() is the equivalent of perf_event__preprocess_sample() but for 'addr' instead of 'ip'.

---
 tools/perf/builtin-script.c | 34 +---------------------------------
 tools/perf/util/event.c     | 42 ++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/event.h     | 10 ++++++++++
 3 files changed, 53 insertions(+), 33 deletions(-)
tools/perf/builtin-script.c +1 -33
index c1a56f2..163d12b 100644
@@ -367,27 +367,6 @@ 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) &&
-	    ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
-	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
-	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
-		return true;
-
-	if (is_bts_event(attr))
-		return true;
-
-	return false;
-}
-
 static void print_sample_addr(union perf_event *event,
 			  struct perf_sample *sample,
 			  struct machine *machine,
@@ -395,24 +374,13 @@ static void print_sample_addr(union perf_event *event,
 			  struct perf_event_attr *attr)
 {
 	struct addr_location al;
-	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
 	printf("%16" PRIx64, sample->addr);
 
 	if (!sample_addr_correlates_sym(attr))
 		return;
 
-	thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
-			      sample->addr, &al);
-	if (!al.map)
-		thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
-				      sample->addr, &al);
-
-	al.cpu = sample->cpu;
-	al.sym = NULL;
-
-	if (al.map)
-		al.sym = map__find_symbol(al.map, al.addr, NULL);
+	perf_event__preprocess_sample_addr(event, sample, machine, thread, &al);
 
 	if (PRINT_FIELD(SYM)) {
 		printf(" ");
tools/perf/util/event.c +42 -0

45 lines not on this page · raw message

tools/perf/util/event.h +10 -0
index ae75b48..b8e5d1a 100644
@@ -329,6 +329,16 @@ int perf_event__preprocess_sample(const union perf_event *event,
 				  struct addr_location *al,
 				  struct perf_sample *sample);
 
+struct thread;
+
+bool is_bts_event(struct perf_event_attr *attr);
+bool sample_addr_correlates_sym(struct perf_event_attr *attr);
+void perf_event__preprocess_sample_addr(union perf_event *event,
+					struct perf_sample *sample,
+					struct machine *machine,
+					struct thread *thread,
+					struct addr_location *al);
+
 const char *perf_event__name(unsigned int id);
 
 size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
Signature · 1 line
1.8.3.2
#69 lore raw

[tip:perf/core] perf tools: Expose 'addr' functions so they can be reused

perf tools: Expose 'addr' functions so they can be reused
Commit-ID:  9b0d2d875d57d85fdfb35ac27f89951520a8b473
Gitweb:     http://git.kernel.org/tip/9b0d2d875d57d85fdfb35ac27f89951520a8b473
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:39 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 25 Jul 2014 12:08:34 -0300

perf tools: Expose 'addr' functions so they can be reused

Move some functions and functionality related to the use of 'addr' out of builtin-script so they can be reused.

The moved functions are: is_bts_event() and sample_addr_correlates_sym() and a new function perf_event__preprocess_sample_addr() is created from bits of print_sample_addr().

perf_event__preprocess_sample_addr() is the equivalent of perf_event__preprocess_sample() but for 'addr' instead of 'ip'.

---
 tools/perf/builtin-script.c | 34 +---------------------------------
 tools/perf/util/event.c     | 42 ++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/event.h     | 10 ++++++++++
 3 files changed, 53 insertions(+), 33 deletions(-)
tools/perf/builtin-script.c +1 -33
index 582da97..f57035b 100644
@@ -358,27 +358,6 @@ 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) &&
-	    ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
-	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
-	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
-		return true;
-
-	if (is_bts_event(attr))
-		return true;
-
-	return false;
-}
-
 static void print_sample_addr(union perf_event *event,
 			  struct perf_sample *sample,
 			  struct machine *machine,
@@ -386,24 +365,13 @@ static void print_sample_addr(union perf_event *event,
 			  struct perf_event_attr *attr)
 {
 	struct addr_location al;
-	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
 	printf("%16" PRIx64, sample->addr);
 
 	if (!sample_addr_correlates_sym(attr))
 		return;
 
-	thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
-			      sample->addr, &al);
-	if (!al.map)
-		thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
-				      sample->addr, &al);
-
-	al.cpu = sample->cpu;
-	al.sym = NULL;
-
-	if (al.map)
-		al.sym = map__find_symbol(al.map, al.addr, NULL);
+	perf_event__preprocess_sample_addr(event, sample, machine, thread, &al);
 
 	if (PRINT_FIELD(SYM)) {
 		printf(" ");
tools/perf/util/event.c +42 -0

45 lines not on this page · raw message

tools/perf/util/event.h +10 -0
index e5dd40a..94d6976 100644
@@ -288,6 +288,16 @@ int perf_event__preprocess_sample(const union perf_event *event,
 				  struct addr_location *al,
 				  struct perf_sample *sample);
 
+struct thread;
+
+bool is_bts_event(struct perf_event_attr *attr);
+bool sample_addr_correlates_sym(struct perf_event_attr *attr);
+void perf_event__preprocess_sample_addr(union perf_event *event,
+					struct perf_sample *sample,
+					struct machine *machine,
+					struct thread *thread,
+					struct addr_location *al);
+
 const char *perf_event__name(unsigned int id);
 
 size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
author reviewer
#70 lore raw

PATCH 31/52 perf tools: Add facility to export data in database-friendly way

In reply to Adrian Hunter

This patch introduces an abstraction for exporting sample data in a database-friendly way. The abstraction does not implement the actual output. A subsequent patch takes this facility into use for extending the script interface.

The abstraction is needed because static data like symbols, dsos, comms etc need to be exported only once. That means allocating them a unique identifier and recording it on each structure. The member 'db_id' is used for that. 'db_id' is just a 64-bit sequence number.

Exporting centres around the db_export__sample() function which exports the associated data structures if they have not yet been allocated a db_id.

---
 tools/perf/Makefile.perf    |   2 +
 tools/perf/util/comm.h      |   1 +
 tools/perf/util/db-export.c | 268 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/db-export.h |  86 ++++++++++++++
 tools/perf/util/dso.h       |   1 +
 tools/perf/util/evsel.h     |   1 +
 tools/perf/util/machine.h   |   1 +
 tools/perf/util/symbol.h    |   1 +
 tools/perf/util/thread.h    |   1 +
 9 files changed, 362 insertions(+)
 create mode 100644 tools/perf/util/db-export.c
 create mode 100644 tools/perf/util/db-export.h
tools/perf/Makefile.perf +2 -0
index f4333b5..f7bb2b4 100644
@@ -303,6 +303,7 @@ LIB_H += ui/ui.h
 LIB_H += util/data.h
 LIB_H += util/kvm-stat.h
 LIB_H += util/thread-stack.h
+LIB_H += util/db-export.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -379,6 +380,7 @@ LIB_OBJS += $(OUTPUT)util/data.o
 LIB_OBJS += $(OUTPUT)util/tsc.o
 LIB_OBJS += $(OUTPUT)util/cloexec.o
 LIB_OBJS += $(OUTPUT)util/thread-stack.o
+LIB_OBJS += $(OUTPUT)util/db-export.o
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/util/comm.h +1 -0
index 51c10ab..99e7021 100644
@@ -10,6 +10,7 @@ struct comm_str;
 struct comm {
 	struct comm_str *comm_str;
 	u64 start;
+	u64 db_id;
 	struct list_head list;
 	bool exec;
 };
tools/perf/util/db-export.c new file +268 -0

268 lines not on this page · raw message

tools/perf/util/db-export.h new file +86 -0

86 lines not on this page · raw message

tools/perf/util/dso.h +1 -0
index af1c256..d03720b 100644
@@ -93,6 +93,7 @@ struct dso {
 	enum dso_swap_type	needs_swap;
 	enum dso_binary_type	symtab_type;
 	enum dso_binary_type	binary_type;
+	u64		 db_id;
 	u8		 adjust_symbols:1;
 	u8		 has_build_id:1;
 	u8		 has_srcline:1;
tools/perf/util/evsel.h +1 -0
index 330218a..b94987e 100644
@@ -95,6 +95,7 @@ struct perf_evsel {
 	int			sample_read;
 	struct perf_evsel	*leader;
 	char			*group_name;
+	u64			db_id;
 };
 
 union u64_swap {
tools/perf/util/machine.h +1 -0
index 6442d65..f91a7e1 100644
@@ -36,6 +36,7 @@ struct machine {
 	u64		  kernel_start;
 	symbol_filter_t	  symbol_filter;
 	pid_t		  *current_tid;
+	u64		  db_id;
 };
 
 static inline
tools/perf/util/symbol.h +1 -0
index ee2d3cc..31e5400 100644
@@ -71,6 +71,7 @@ struct symbol {
 	struct rb_node	rb_node;
 	u64		start;
 	u64		end;
+	u64		db_id;
 	u16		namelen;
 	u8		binding;
 	bool		ignore;
tools/perf/util/thread.h +1 -0
index a057820..a3ebb21 100644
@@ -25,6 +25,7 @@ struct thread {
 	bool			dead; /* if set thread has exited */
 	struct list_head	comm_list;
 	int			comm_len;
+	u64			db_id;
 
 	void			*priv;
 	struct thread_stack	*ts;
Signature · 1 line
1.8.3.2
author reviewer
#71 lore raw

PATCH 32/52 perf tools: Add helpers for calling Python objects

In reply to Adrian Hunter

The Python script API repeatedly uses the same lines of code to get and call objects. Make that into helper functions instead. A side-effect is that some reference counting bugs disappear because the new call_object() function always decrements the reference count of 'retval'.

---
 .../util/scripting-engines/trace-event-python.c    | 114 +++++++++------------
 1 file changed, 47 insertions(+), 67 deletions(-)
tools/perf/util/scripting-engines/trace-event-python.c +47 -67
index cbce254..26e5f14 100644
@@ -73,6 +73,35 @@ static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObj
 	Py_DECREF(val);
 }
 
+static PyObject *get_handler(const char *handler_name)
+{
+	PyObject *handler;
+
+	handler = PyDict_GetItemString(main_dict, handler_name);
+	if (handler && !PyCallable_Check(handler))
+		return NULL;
+	return handler;
+}
+
+static void call_object(PyObject *handler, PyObject *args, const char *die_msg)
+{
+	PyObject *retval;
+
+	retval = PyObject_CallObject(handler, args);
+	if (retval == NULL)
+		handler_call_die(die_msg);
+	Py_DECREF(retval);
+}
+
+static void try_call_object(const char *handler_name, PyObject *args)
+{
+	PyObject *handler;
+
+	handler = get_handler(handler_name);
+	if (handler)
+		call_object(handler, args, handler_name);
+}
+
 static void define_value(enum print_arg_type field_type,
 			 const char *ev_name,
 			 const char *field_name,
@@ -80,7 +109,7 @@ static void define_value(enum print_arg_type field_type,
 			 const char *field_str)
 {
 	const char *handler_name = "define_flag_value";
-	PyObject *handler, *t, *retval;
+	PyObject *t;
 	unsigned long long value;
 	unsigned n = 0;
 
@@ -98,13 +127,7 @@ static void define_value(enum print_arg_type field_type,
 	PyTuple_SetItem(t, n++, PyInt_FromLong(value));
 	PyTuple_SetItem(t, n++, PyString_FromString(field_str));
 
-	handler = PyDict_GetItemString(main_dict, handler_name);
-	if (handler && PyCallable_Check(handler)) {
-		retval = PyObject_CallObject(handler, t);
-		if (retval == NULL)
-			handler_call_die(handler_name);
-		Py_DECREF(retval);
-	}
+	try_call_object(handler_name, t);
 
 	Py_DECREF(t);
 }
@@ -127,7 +150,7 @@ static void define_field(enum print_arg_type field_type,
 			 const char *delim)
 {
 	const char *handler_name = "define_flag_field";
-	PyObject *handler, *t, *retval;
+	PyObject *t;
 	unsigned n = 0;
 
 	if (field_type == PRINT_SYMBOL)
@@ -145,13 +168,7 @@ static void define_field(enum print_arg_type field_type,
 	if (field_type == PRINT_FLAGS)
 		PyTuple_SetItem(t, n++, PyString_FromString(delim));
 
-	handler = PyDict_GetItemString(main_dict, handler_name);
-	if (handler && PyCallable_Check(handler)) {
-		retval = PyObject_CallObject(handler, t);
-		if (retval == NULL)
-			handler_call_die(handler_name);
-		Py_DECREF(retval);
-	}
+	try_call_object(handler_name, t);
 
 	Py_DECREF(t);
 }
@@ -362,7 +379,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
 				      struct thread *thread,
 				      struct addr_location *al)
 {
-	PyObject *handler, *retval, *context, *t, *obj, *callchain;
+	PyObject *handler, *context, *t, *obj, *callchain;
 	PyObject *dict = NULL;
 	static char handler_name[256];
 	struct format_field *field;
@@ -387,9 +404,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
 
 	sprintf(handler_name, "%s__%s", event->system, event->name);
 
-	handler = PyDict_GetItemString(main_dict, handler_name);
-	if (handler && !PyCallable_Check(handler))
-		handler = NULL;
+	handler = get_handler(handler_name);
 	if (!handler) {
 		dict = PyDict_New();
 		if (!dict)
@@ -450,19 +465,9 @@ static void python_process_tracepoint(struct perf_sample *sample,
 		Py_FatalError("error resizing Python tuple");
 
 	if (handler) {
-		retval = PyObject_CallObject(handler, t);
-		if (retval == NULL)
-			handler_call_die(handler_name);
-		Py_DECREF(retval);
+		call_object(handler, t, handler_name);
 	} else {
-		handler = PyDict_GetItemString(main_dict, "trace_unhandled");
-		if (handler && PyCallable_Check(handler)) {
-
-			retval = PyObject_CallObject(handler, t);
-			if (retval == NULL)
-				handler_call_die("trace_unhandled");
-			Py_DECREF(retval);
-		}
+		try_call_object("trace_unhandled", t);
 		Py_DECREF(dict);
 	}
 
@@ -474,7 +479,7 @@ static void python_process_general_event(struct perf_sample *sample,
 					 struct thread *thread,
 					 struct addr_location *al)
 {
-	PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample;
+	PyObject *handler, *t, *dict, *callchain, *dict_sample;
 	static char handler_name[64];
 	unsigned n = 0;
 
@@ -496,8 +501,8 @@ static void python_process_general_event(struct perf_sample *sample,
 
 	snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
 
-	handler = PyDict_GetItemString(main_dict, handler_name);
-	if (!handler || !PyCallable_Check(handler))
+	handler = get_handler(handler_name);
+	if (!handler)
 		goto exit;
 
 	pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
@@ -539,10 +544,7 @@ static void python_process_general_event(struct perf_sample *sample,
 	if (_PyTuple_Resize(&t, n) == -1)
 		Py_FatalError("error resizing Python tuple");
 
-	retval = PyObject_CallObject(handler, t);
-	if (retval == NULL)
-		handler_call_die(handler_name);
-	Py_DECREF(retval);
+	call_object(handler, t, handler_name);
 exit:
 	Py_DECREF(dict);
 	Py_DECREF(t);
@@ -566,36 +568,24 @@ static void python_process_event(union perf_event *event __maybe_unused,
 
 static int run_start_sub(void)
 {
-	PyObject *handler, *retval;
-	int err = 0;
-
 	main_module = PyImport_AddModule("__main__");
 	if (main_module == NULL)
 		return -1;
 	Py_INCREF(main_module);
 
 	main_dict = PyModule_GetDict(main_module);
-	if (main_dict == NULL) {
-		err = -1;
+	if (main_dict == NULL)
 		goto error;
-	}
 	Py_INCREF(main_dict);
 
-	handler = PyDict_GetItemString(main_dict, "trace_begin");
-	if (handler == NULL || !PyCallable_Check(handler))
-		goto out;
+	try_call_object("trace_begin", NULL);
 
-	retval = PyObject_CallObject(handler, NULL);
-	if (retval == NULL)
-		handler_call_die("trace_begin");
+	return 0;
 
-	Py_DECREF(retval);
-	return err;
 error:
 	Py_XDECREF(main_dict);
 	Py_XDECREF(main_module);
-out:
-	return err;
+	return -1;
 }
 
 /*
@@ -654,23 +644,13 @@ error:
  */
 static int python_stop_script(void)
 {
-	PyObject *handler, *retval;
-	int err = 0;
+	try_call_object("trace_end", NULL);
 
-	handler = PyDict_GetItemString(main_dict, "trace_end");
-	if (handler == NULL || !PyCallable_Check(handler))
-		goto out;
-
-	retval = PyObject_CallObject(handler, NULL);
-	if (retval == NULL)
-		handler_call_die("trace_end");
-	Py_DECREF(retval);
-out:
 	Py_XDECREF(main_dict);
 	Py_XDECREF(main_module);
 	Py_Finalize();
 
-	return err;
+	return 0;
 }
 
 static int python_generate_script(struct pevent *pevent, const char *outfile)
Signature · 1 line
1.8.3.2
author reviewer
#72 lore raw

PATCH 33/52 perf tools: Extend Python script interface to export data in a database-friendly way

In reply to Adrian Hunter

Use the new db_export facility to export data in a database-friendly way.

A Python script selects the db_export mode by setting a global variable 'perf_db_export_mode' to True. The script then optionally implements functions to receive table rows. The functions are:

evsel_table
machine_table
thread_table
comm_table
dso_table
symbol_table
sample_table

An example script is provided in a subsequent patch.

---
 .../util/scripting-engines/trace-event-python.c    | 281 ++++++++++++++++++++-
 1 file changed, 279 insertions(+), 2 deletions(-)
tools/perf/util/scripting-engines/trace-event-python.c +279 -2
index 26e5f14..3062eb8 100644
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdbool.h>
 #include <errno.h>
 
 #include "../../perf.h"
@@ -32,6 +33,9 @@
 #include "../util.h"
 #include "../event.h"
 #include "../thread.h"
+#include "../comm.h"
+#include "../machine.h"
+#include "../db-export.h"
 #include "../trace-event.h"
 #include "../machine.h"
 
@@ -52,6 +56,21 @@ static int zero_flag_atom;
 
 static PyObject *main_module, *main_dict;
 
+struct tables {
+	struct db_export	dbe;
+	PyObject		*evsel_handler;
+	PyObject		*machine_handler;
+	PyObject		*thread_handler;
+	PyObject		*comm_handler;
+	PyObject		*comm_thread_handler;
+	PyObject		*dso_handler;
+	PyObject		*symbol_handler;
+	PyObject		*sample_handler;
+	bool			db_export_mode;
+};
+
+static struct tables tables_global;
+
 static void handler_call_die(const char *handler_name) NORETURN;
 static void handler_call_die(const char *handler_name)
 {
@@ -474,6 +493,210 @@ static void python_process_tracepoint(struct perf_sample *sample,
 	Py_DECREF(t);
 }
 
+static PyObject *tuple_new(unsigned int sz)
+{
+	PyObject *t;
+
+	t = PyTuple_New(sz);
+	if (!t)
+		Py_FatalError("couldn't create Python tuple");
+	return t;
+}
+
+static int tuple_set_u64(PyObject *t, unsigned int pos, u64 val)
+{
+#if BITS_PER_LONG == 64
+	return PyTuple_SetItem(t, pos, PyInt_FromLong(val));
+#endif
+#if BITS_PER_LONG == 32
+	return PyTuple_SetItem(t, pos, PyLong_FromLongLong(val));
+#endif
+}
+
+static int tuple_set_s32(PyObject *t, unsigned int pos, s32 val)
+{
+	return PyTuple_SetItem(t, pos, PyInt_FromLong(val));
+}
+
+static int tuple_set_string(PyObject *t, unsigned int pos, const char *s)
+{
+	return PyTuple_SetItem(t, pos, PyString_FromString(s));
+}
+
+static int python_export_evsel(struct db_export *dbe, struct perf_evsel *evsel)
+{
+	struct tables *tables = container_of(dbe, struct tables, dbe);
+	PyObject *t;
+
+	t = tuple_new(2);
+
+	tuple_set_u64(t, 0, evsel->db_id);
+	tuple_set_string(t, 1, perf_evsel__name(evsel));
+
+	call_object(tables->evsel_handler, t, "evsel_table");
+
+	Py_DECREF(t);
+
+	return 0;
+}
+
+static int python_export_machine(struct db_export *dbe,
+				 struct machine *machine)
+{
+	struct tables *tables = container_of(dbe, struct tables, dbe);
+	PyObject *t;
+
+	t = tuple_new(3);
+
+	tuple_set_u64(t, 0, machine->db_id);
+	tuple_set_s32(t, 1, machine->pid);
+	tuple_set_string(t, 2, machine->root_dir ? machine->root_dir : "");
+
+	call_object(tables->machine_handler, t, "machine_table");
+
+	Py_DECREF(t);
+
+	return 0;
+}
+
+static int python_export_thread(struct db_export *dbe, struct thread *thread,
+				u64 main_thread_db_id, struct machine *machine)
+{
+	struct tables *tables = container_of(dbe, struct tables, dbe);
+	PyObject *t;
+
+	t = tuple_new(5);
+
+	tuple_set_u64(t, 0, thread->db_id);
+	tuple_set_u64(t, 1, machine->db_id);
+	tuple_set_u64(t, 2, main_thread_db_id);
+	tuple_set_s32(t, 3, thread->pid_);
+	tuple_set_s32(t, 4, thread->tid);
+
+	call_object(tables->thread_handler, t, "thread_table");
+
+	Py_DECREF(t);
+
+	return 0;
+}
+
+static int python_export_comm(struct db_export *dbe, struct comm *comm)
+{
+	struct tables *tables = container_of(dbe, struct tables, dbe);
+	PyObject *t;
+
+	t = tuple_new(2);
+
+	tuple_set_u64(t, 0, comm->db_id);
+	tuple_set_string(t, 1, comm__str(comm));
+
+	call_object(tables->comm_handler, t, "comm_table");
+
+	Py_DECREF(t);
+
+	return 0;
+}
+
+static int python_export_comm_thread(struct db_export *dbe, u64 db_id,
+				     struct comm *comm, struct thread *thread)
+{
+	struct tables *tables = container_of(dbe, struct tables, dbe);
+	PyObject *t;
+
+	t = tuple_new(3);
+
+	tuple_set_u64(t, 0, db_id);
+	tuple_set_u64(t, 1, comm->db_id);
+	tuple_set_u64(t, 2, thread->db_id);
+
+	call_object(tables->comm_thread_handler, t, "comm_thread_table");
+
+	Py_DECREF(t);
+
+	return 0;
+}
+
+static int python_export_dso(struct db_export *dbe, struct dso *dso,
+			     struct machine *machine)
+{
+	struct tables *tables = container_of(dbe, struct tables, dbe);
+	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+	PyObject *t;
+
+	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
+
+	t = tuple_new(5);
+
+	tuple_set_u64(t, 0, dso->db_id);
+	tuple_set_u64(t, 1, machine->db_id);
+	tuple_set_string(t, 2, dso->short_name);
+	tuple_set_string(t, 3, dso->long_name);
+	tuple_set_string(t, 4, sbuild_id);
+
+	call_object(tables->dso_handler, t, "dso_table");
+
+	Py_DECREF(t);
+
+	return 0;
+}
+
+static int python_export_symbol(struct db_export *dbe, struct symbol *sym,
+				struct dso *dso)
+{
+	struct tables *tables = container_of(dbe, struct tables, dbe);
+	PyObject *t;
+
+	t = tuple_new(6);
+
+	tuple_set_u64(t, 0, sym->db_id);
+	tuple_set_u64(t, 1, dso->db_id);
+	tuple_set_u64(t, 2, sym->start);
+	tuple_set_u64(t, 3, sym->end);
+	tuple_set_s32(t, 4, sym->binding);
+	tuple_set_string(t, 5, sym->name);
+
+	call_object(tables->symbol_handler, t, "symbol_table");
+
+	Py_DECREF(t);
+
+	return 0;
+}
+
+static int python_export_sample(struct db_export *dbe,
+				struct export_sample *es)
+{
+	struct tables *tables = container_of(dbe, struct tables, dbe);
+	PyObject *t;
+
+	t = tuple_new(19);
+
+	tuple_set_u64(t, 0, es->db_id);
+	tuple_set_u64(t, 1, es->evsel->db_id);
+	tuple_set_u64(t, 2, es->al->machine->db_id);
+	tuple_set_u64(t, 3, es->thread->db_id);
+	tuple_set_u64(t, 4, es->comm_db_id);
+	tuple_set_u64(t, 5, es->dso_db_id);
+	tuple_set_u64(t, 6, es->sym_db_id);
+	tuple_set_u64(t, 7, es->offset);
+	tuple_set_u64(t, 8, es->sample->ip);
+	tuple_set_u64(t, 9, es->sample->time);
+	tuple_set_s32(t, 10, es->sample->cpu);
+	tuple_set_u64(t, 11, es->addr_dso_db_id);
+	tuple_set_u64(t, 12, es->addr_sym_db_id);
+	tuple_set_u64(t, 13, es->addr_offset);
+	tuple_set_u64(t, 14, es->sample->addr);
+	tuple_set_u64(t, 15, es->sample->period);
+	tuple_set_u64(t, 16, es->sample->weight);
+	tuple_set_u64(t, 17, es->sample->transaction);
+	tuple_set_u64(t, 18, es->sample->data_src);
+
+	call_object(tables->sample_handler, t, "sample_table");
+
+	Py_DECREF(t);
+
+	return 0;
+}
+
 static void python_process_general_event(struct perf_sample *sample,
 					 struct perf_evsel *evsel,
 					 struct thread *thread,
@@ -550,19 +773,25 @@ exit:
 	Py_DECREF(t);
 }
 
-static void python_process_event(union perf_event *event __maybe_unused,
+static void python_process_event(union perf_event *event,
 				 struct perf_sample *sample,
 				 struct perf_evsel *evsel,
 				 struct thread *thread,
 				 struct addr_location *al)
 {
+	struct tables *tables = &tables_global;
+
 	switch (evsel->attr.type) {
 	case PERF_TYPE_TRACEPOINT:
 		python_process_tracepoint(sample, evsel, thread, al);
 		break;
 	/* Reserve for future process_hw/sw/raw APIs */
 	default:
-		python_process_general_event(sample, evsel, thread, al);
+		if (tables->db_export_mode)
+			db_export__sample(&tables->dbe, event, sample, evsel,
+					  thread, al);
+		else
+			python_process_general_event(sample, evsel, thread, al);
 	}
 }
 
@@ -588,11 +817,53 @@ error:
 	return -1;
 }
 
+#define SET_TABLE_HANDLER_(name, handler_name, table_name) do {		\
+	tables->handler_name = get_handler(#table_name);		\
+	if (tables->handler_name)					\
+		tables->dbe.export_ ## name = python_export_ ## name;	\
+} while (0)
+
+#define SET_TABLE_HANDLER(name) \
+	SET_TABLE_HANDLER_(name, name ## _handler, name ## _table)
+
+static void set_table_handlers(struct tables *tables)
+{
+	const char *perf_db_export_mode = "perf_db_export_mode";
+	PyObject *db_export_mode;
+	int ret;
+
+	memset(tables, 0, sizeof(struct tables));
+	if (db_export__init(&tables->dbe))
+		Py_FatalError("failed to initialize export");
+
+	db_export_mode = PyDict_GetItemString(main_dict, perf_db_export_mode);
+	if (!db_export_mode)
+		return;
+
+	ret = PyObject_IsTrue(db_export_mode);
+	if (ret == -1)
+		handler_call_die(perf_db_export_mode);
+	if (!ret)
+		return;
+
+	tables->db_export_mode = true;
+
+	SET_TABLE_HANDLER(evsel);
+	SET_TABLE_HANDLER(machine);
+	SET_TABLE_HANDLER(thread);
+	SET_TABLE_HANDLER(comm);
+	SET_TABLE_HANDLER(comm_thread);
+	SET_TABLE_HANDLER(dso);
+	SET_TABLE_HANDLER(symbol);
+	SET_TABLE_HANDLER(sample);
+}
+
 /*
  * Start trace script
  */
 static int python_start_script(const char *script, int argc, const char **argv)
 {
+	struct tables *tables = &tables_global;
 	const char **command_line;
 	char buf[PATH_MAX];
 	int i, err = 0;
@@ -631,6 +902,8 @@ static int python_start_script(const char *script, int argc, const char **argv)
 
 	free(command_line);
 
+	set_table_handlers(tables);
+
 	return err;
 error:
 	Py_Finalize();
@@ -644,8 +917,12 @@ error:
  */
 static int python_stop_script(void)
 {
+	struct tables *tables = &tables_global;
+
 	try_call_object("trace_end", NULL);
 
+	db_export__exit(&tables->dbe);
+
 	Py_XDECREF(main_dict);
 	Py_XDECREF(main_module);
 	Py_Finalize();
Signature · 1 line
1.8.3.2
author reviewer
#73 lore raw

PATCH 34/52 perf tools: Add Python script to export to postgresql

In reply to Adrian Hunter

Add a Python script to export to a postgresql database. The script requires the Python psycopg2 module. The caller of the script must be able to create postgresql databases.

The script takes the database name as a parameter. The database and database tables are created. Data is written to flat files which are then imported using SQL COPY FROM.

Example:

$ perf record ls
...
$ perf script report export-to-postgresql lsdb
2014-02-14 10:55:38.631431 Creating database...
2014-02-14 10:55:39.291958 Writing to intermediate files...
2014-02-14 10:55:39.350280 Copying to database...
2014-02-14 10:55:39.358536 Removing intermediate files...
2014-02-14 10:55:39.358665 Adding primary keys
2014-02-14 10:55:39.658697 Adding foreign keys
2014-02-14 10:55:39.667412 Done
$ psql lsdb
lsdb=# select * from samples_view;

id | time | cpu | pid | tid | command | event | ip_hex | symbol | sym_offset | dso_short_name | to_ip_hex | to_symbol | to_sym_offset | to_dso_short_name
----+-----------------+-----+-------+-------+---------+--------+------------------+------------------------------+------------+-------------------+-----------+-----------+---------------+-------------------

  1 | 592112202825015 |  -1 | 17339 | 17339 | :17339  | cycles | ffffffff8104d24a | native_write_msr_safe        |         10 | [kernel.kallsyms] | 0         | unknown   |             0 | unknown
  2 | 592112203258804 |  -1 | 17339 | 17339 | :17339  | cycles | ffffffff8104d24a | native_write_msr_safe        |         10 | [kernel.kallsyms] | 0         | unknown   |             0 | unknown
  3 | 592112203988119 |  -1 | 17339 | 17339 | :17339  | cycles | ffffffff8104d24a | native_write_msr_safe        |         10 | [kernel.kallsyms] | 0         | unknown   |             0 | unknown
---
 .../scripts/python/bin/export-to-postgresql-record |   8 +
 .../scripts/python/bin/export-to-postgresql-report |  24 ++
 tools/perf/scripts/python/export-to-postgresql.py  | 360 +++++++++++++++++++++
 3 files changed, 392 insertions(+)
 create mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-record
 create mode 100644 tools/perf/scripts/python/bin/export-to-postgresql-report
 create mode 100644 tools/perf/scripts/python/export-to-postgresql.py
tools/perf/scripts/python/bin/export-to-postgresql-record new file +8 -0
new file mode 100644
index 0000000..221d66e
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+#
+# export perf data to a postgresql database. Can cover
+# perf ip samples (excluding the tracepoints). No special
+# record requirements, just record what you want to export.
+#
+perf record $@
tools/perf/scripts/python/bin/export-to-postgresql-report new file +24 -0
new file mode 100644
index 0000000..a8fdd15
@@ -0,0 +1,24 @@
+#!/bin/bash
+# description: export perf data to a postgresql database
+# args: [database name] [columns]
+n_args=0
+for i in "$@"
+do
+    if expr match "$i" "-" > /dev/null ; then
+	break
+    fi
+    n_args=$(( $n_args + 1 ))
+done
+if [ "$n_args" -gt 2 ] ; then
+    echo "usage: export-to-postgresql-report [database name] [columns]"
+    exit
+fi
+if [ "$n_args" -gt 1 ] ; then
+    dbname=$1
+    columns=$2
+    shift 2
+elif [ "$n_args" -gt 0 ] ; then
+    dbname=$1
+    shift
+fi
+perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns
tools/perf/scripts/python/export-to-postgresql.py new file +360 -0

360 lines not on this page · raw message

Signature · 1 line
1.8.3.2
author reviewer
#74 lore raw

PATCH 35/52 perf tools: Add flags and insn_len to struct sample

In reply to Adrian Hunter

Add flags and insn_len to struct sample. The flags will be used to export branch type and transaction status. insn_len is preparation for pairing calls and returns because the return address equals the call address plus the instruction length (insn_len).

---
 tools/perf/util/event.h | 2 ++
 1 file changed, 2 insertions(+)
tools/perf/util/event.h +2 -0
index b8e5d1a..17048f7 100644
@@ -182,6 +182,8 @@ struct perf_sample {
 	u32 cpu;
 	u32 raw_size;
 	u64 data_src;
+	u32 flags;
+	u16 insn_len;
 	void *raw_data;
 	struct ip_callchain *callchain;
 	struct branch_stack *branch_stack;
Signature · 1 line
1.8.3.2
author reviewer
#75 lore raw

PATCH 36/52 perf tools: Add branch type to db export

In reply to Adrian Hunter

Add the ability to export branch types through the database export facility.

---
 tools/perf/util/db-export.c | 48 +++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/db-export.h |  6 ++++++
 2 files changed, 54 insertions(+)
tools/perf/util/db-export.c +48 -0
index 53d0e75..c5b6e02 100644
@@ -205,6 +205,15 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
 	return 0;
 }
 
+int db_export__branch_type(struct db_export *dbe, u32 branch_type,
+			   const char *name)
+{
+	if (dbe->export_branch_type)
+		return dbe->export_branch_type(dbe, branch_type, name);
+
+	return 0;
+}
+
 int db_export__sample(struct db_export *dbe, union perf_event *event,
 		      struct perf_sample *sample, struct perf_evsel *evsel,
 		      struct thread *thread, struct addr_location *al)
@@ -266,3 +275,42 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
 
 	return 0;
 }
+
+static struct {
+	u32 branch_type;
+	const char *name;
+} branch_types[] = {
+	{0, "no branch"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_CALL, "call"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_RETURN, "return"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_CONDITIONAL, "conditional jump"},
+	{PERF_FLAG_BRANCH, "unconditional jump"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_CALL | PERF_FLAG_INTERRUPT,
+	 "software interrupt"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_RETURN | PERF_FLAG_INTERRUPT,
+	 "return from interrupt"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_CALL | PERF_FLAG_SYSCALLRET,
+	 "system call"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_RETURN | PERF_FLAG_SYSCALLRET,
+	 "return from system call"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_ASYNC, "asynchronous branch"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_CALL | PERF_FLAG_ASYNC |
+	 PERF_FLAG_INTERRUPT, "hardware interrupt"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_TX_ABORT, "transaction abort"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_TRACE_BEGIN, "trace begin"},
+	{PERF_FLAG_BRANCH | PERF_FLAG_TRACE_END, "trace end"},
+	{0, NULL}
+};
+
+int db_export__branch_types(struct db_export *dbe)
+{
+	int i, err = 0;
+
+	for (i = 0; branch_types[i].name ; i++) {
+		err = db_export__branch_type(dbe, branch_types[i].branch_type,
+					     branch_types[i].name);
+		if (err)
+			break;
+	}
+	return err;
+}
tools/perf/util/db-export.h +6 -0
index b3643e8..e4baa45 100644
@@ -54,6 +54,8 @@ struct db_export {
 			  struct machine *machine);
 	int (*export_symbol)(struct db_export *dbe, struct symbol *sym,
 			     struct dso *dso);
+	int (*export_branch_type)(struct db_export *dbe, u32 branch_type,
+				  const char *name);
 	int (*export_sample)(struct db_export *dbe, struct export_sample *es);
 	u64 evsel_last_db_id;
 	u64 machine_last_db_id;
@@ -79,8 +81,12 @@ int db_export__dso(struct db_export *dbe, struct dso *dso,
 		   struct machine *machine);
 int db_export__symbol(struct db_export *dbe, struct symbol *sym,
 		      struct dso *dso);
+int db_export__branch_type(struct db_export *dbe, u32 branch_type,
+			   const char *name);
 int db_export__sample(struct db_export *dbe, union perf_event *event,
 		      struct perf_sample *sample, struct perf_evsel *evsel,
 		      struct thread *thread, struct addr_location *al);
 
+int db_export__branch_types(struct db_export *dbe);
+
 #endif
Signature · 1 line
1.8.3.2
author reviewer
#76 lore raw

PATCH 37/52 perf tools: Add branch_type and in_tx to Python export

In reply to Adrian Hunter

Add branch_type and in_tx to Python db export and
the export-to-postgresql.py script.

---
 tools/perf/scripts/python/export-to-postgresql.py  | 32 ++++++++++++++++++----
 .../util/scripting-engines/trace-event-python.c    | 30 +++++++++++++++++++-
 2 files changed, 55 insertions(+), 7 deletions(-)
tools/perf/scripts/python/export-to-postgresql.py +26 -6
index d8f6df0..bb79aec 100644
@@ -123,6 +123,10 @@ do_query(query, 'CREATE TABLE symbols ('
 		'sym_end	bigint,'
 		'binding	integer,'
 		'name		varchar(2048))')
+do_query(query, 'CREATE TABLE branch_types ('
+		'id		integer		NOT NULL,'
+		'name		varchar(80))')
+
 if branches:
 	do_query(query, 'CREATE TABLE samples ('
 		'id		bigint		NOT NULL,'
@@ -139,7 +143,9 @@ if branches:
 		'to_dso_id	bigint,'
 		'to_symbol_id	bigint,'
 		'to_sym_offset	bigint,'
-		'to_ip		bigint)')
+		'to_ip		bigint,'
+		'branch_type	integer,'
+		'in_tx		boolean)')
 else:
 	do_query(query, 'CREATE TABLE samples ('
 		'id		bigint		NOT NULL,'
@@ -160,7 +166,9 @@ else:
 		'period		bigint,'
 		'weight		bigint,'
 		'transaction	bigint,'
-		'data_src	bigint)')
+		'data_src	bigint,'
+		'branch_type	integer,'
+		'in_tx		boolean)')
 
 do_query(query, 'CREATE VIEW samples_view AS '
 	'SELECT '
@@ -178,7 +186,9 @@ do_query(query, 'CREATE VIEW samples_view AS '
 		'to_hex(to_ip) AS to_ip_hex,'
 		'(SELECT name FROM symbols WHERE id = to_symbol_id) AS to_symbol,'
 		'to_sym_offset,'
-		'(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name'
+		'(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,'
+		'(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,'
+		'in_tx'
 	' FROM samples')
 
 
@@ -234,6 +244,7 @@ comm_file		= open_output_file("comm_table.bin")
 comm_thread_file	= open_output_file("comm_thread_table.bin")
 dso_file		= open_output_file("dso_table.bin")
 symbol_file		= open_output_file("symbol_table.bin")
+branch_type_file	= open_output_file("branch_type_table.bin")
 sample_file		= open_output_file("sample_table.bin")
 
 def trace_begin():
@@ -257,6 +268,7 @@ def trace_end():
 	copy_output_file(comm_thread_file,	"comm_threads")
 	copy_output_file(dso_file,		"dsos")
 	copy_output_file(symbol_file,		"symbols")
+	copy_output_file(branch_type_file,	"branch_types")
 	copy_output_file(sample_file,		"samples")
 
 	print datetime.datetime.today(), "Removing intermediate files..."
@@ -267,6 +279,7 @@ def trace_end():
 	remove_output_file(comm_thread_file)
 	remove_output_file(dso_file)
 	remove_output_file(symbol_file)
+	remove_output_file(branch_type_file)
 	remove_output_file(sample_file)
 	os.rmdir(output_dir_name)
 	print datetime.datetime.today(), "Adding primary keys"
@@ -277,6 +290,7 @@ def trace_end():
 	do_query(query, 'ALTER TABLE comm_threads    ADD PRIMARY KEY (id)')
 	do_query(query, 'ALTER TABLE dsos            ADD PRIMARY KEY (id)')
 	do_query(query, 'ALTER TABLE symbols         ADD PRIMARY KEY (id)')
+	do_query(query, 'ALTER TABLE branch_types    ADD PRIMARY KEY (id)')
 	do_query(query, 'ALTER TABLE samples         ADD PRIMARY KEY (id)')
 
 	print datetime.datetime.today(), "Adding foreign keys"
@@ -352,9 +366,15 @@ def symbol_table(symbol_id, dso_id, sym_start, sym_end, binding, symbol_name, *x
 	value = struct.pack(fmt, 6, 8, symbol_id, 8, dso_id, 8, sym_start, 8, sym_end, 4, binding, n, symbol_name)
 	symbol_file.write(value)
 
-def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, *x):
+def branch_type_table(branch_type, name, *x):
+	n = len(name)
+	fmt = "!hiii" + str(n) + "s"
+	value = struct.pack(fmt, 2, 4, branch_type, n, name)
+	branch_type_file.write(value)
+
+def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, *x):
 	if branches:
-		value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiq", 15, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip)
+		value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiB", 17, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx)
 	else:
-		value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiq", 19, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src)
+		value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx)
 	sample_file.write(value)
tools/perf/util/scripting-engines/trace-event-python.c +29 -1
index 3062eb8..45483a4 100644
@@ -65,6 +65,7 @@ struct tables {
 	PyObject		*comm_thread_handler;
 	PyObject		*dso_handler;
 	PyObject		*symbol_handler;
+	PyObject		*branch_type_handler;
 	PyObject		*sample_handler;
 	bool			db_export_mode;
 };
@@ -662,13 +663,31 @@ static int python_export_symbol(struct db_export *dbe, struct symbol *sym,
 	return 0;
 }
 
+static int python_export_branch_type(struct db_export *dbe, u32 branch_type,
+				     const char *name)
+{
+	struct tables *tables = container_of(dbe, struct tables, dbe);
+	PyObject *t;
+
+	t = tuple_new(2);
+
+	tuple_set_s32(t, 0, branch_type);
+	tuple_set_string(t, 1, name);
+
+	call_object(tables->branch_type_handler, t, "branch_type_table");
+
+	Py_DECREF(t);
+
+	return 0;
+}
+
 static int python_export_sample(struct db_export *dbe,
 				struct export_sample *es)
 {
 	struct tables *tables = container_of(dbe, struct tables, dbe);
 	PyObject *t;
 
-	t = tuple_new(19);
+	t = tuple_new(21);
 
 	tuple_set_u64(t, 0, es->db_id);
 	tuple_set_u64(t, 1, es->evsel->db_id);
@@ -689,6 +708,8 @@ static int python_export_sample(struct db_export *dbe,
 	tuple_set_u64(t, 16, es->sample->weight);
 	tuple_set_u64(t, 17, es->sample->transaction);
 	tuple_set_u64(t, 18, es->sample->data_src);
+	tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK);
+	tuple_set_s32(t, 20, !!(es->sample->flags & PERF_FLAG_IN_TX));
 
 	call_object(tables->sample_handler, t, "sample_table");
 
@@ -855,6 +876,7 @@ static void set_table_handlers(struct tables *tables)
 	SET_TABLE_HANDLER(comm_thread);
 	SET_TABLE_HANDLER(dso);
 	SET_TABLE_HANDLER(symbol);
+	SET_TABLE_HANDLER(branch_type);
 	SET_TABLE_HANDLER(sample);
 }
 
@@ -904,6 +926,12 @@ static int python_start_script(const char *script, int argc, const char **argv)
 
 	set_table_handlers(tables);
 
+	if (tables->db_export_mode) {
+		err = db_export__branch_types(&tables->dbe);
+		if (err)
+			goto error;
+	}
+
 	return err;
 error:
 	Py_Finalize();
Signature · 1 line
1.8.3.2
author reviewer
#77 lore raw

PATCH 38/52 perf tools: Enhance the thread stack to output call/return data

In reply to Adrian Hunter

Enhance the thread stack to output detailed information about paired calls and returns.

---
 tools/perf/util/thread-stack.c | 547 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/thread-stack.h |  47 ++++
 2 files changed, 590 insertions(+), 4 deletions(-)
tools/perf/util/thread-stack.c +543 -4
index c1ca2a9..444d132 100644
@@ -13,15 +13,48 @@
  *
  */
 
+#include <linux/rbtree.h>
+#include <linux/list.h>
 #include "thread.h"
 #include "event.h"
+#include "machine.h"
 #include "util.h"
+#include "debug.h"
+#include "symbol.h"
+#include "comm.h"
 #include "thread-stack.h"
 
-#define STACK_GROWTH 4096
+#define CALL_PATH_BLOCK_SHIFT 8
+#define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT)
+#define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1)
+
+struct call_path_block {
+	struct call_path cp[CALL_PATH_BLOCK_SIZE];
+	struct list_head node;
+};
+
+struct call_path_root {
+	struct call_path call_path;
+	struct list_head blocks;
+	size_t next;
+	size_t sz;
+};
+
+struct call_return_processor {
+	struct call_path_root *cpr;
+	int (*process)(struct call_return *cr, void *data);
+	void *data;
+};
+
+#define STACK_GROWTH 2048
 
 struct thread_stack_entry {
 	u64 ret_addr;
+	u64 timestamp;
+	u64 ref;
+	u64 branch_count;
+	struct call_path *cp;
+	bool no_call;
 };
 
 struct thread_stack {
@@ -29,6 +62,11 @@ struct thread_stack {
 	size_t cnt;
 	size_t sz;
 	u64 trace_nr;
+	u64 branch_count;
+	u64 kernel_start;
+	u64 last_time;
+	struct call_return_processor *crp;
+	struct comm *comm;
 };
 
 static void thread_stack__grow(struct thread_stack *ts)
@@ -45,7 +83,8 @@ static void thread_stack__grow(struct thread_stack *ts)
 	}
 }
 
-static struct thread_stack *thread_stack__new(void)
+static struct thread_stack *thread_stack__new(struct thread *thread,
+					      struct call_return_processor *crp)
 {
 	struct thread_stack *ts;
 
@@ -59,6 +98,12 @@ static struct thread_stack *thread_stack__new(void)
 		return NULL;
 	}
 
+	if (thread->mg && thread->mg->machine)
+		ts->kernel_start = machine__kernel_start(thread->mg->machine);
+	else
+		ts->kernel_start = 1ULL << 63;
+	ts->crp = crp;
+
 	return ts;
 }
 
@@ -92,6 +137,64 @@ static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr)
 	}
 }
 
+static bool thread_stack__in_kernel(struct thread_stack *ts)
+{
+	if (!ts->cnt)
+		return false;
+
+	return ts->stack[ts->cnt - 1].cp->in_kernel;
+}
+
+static int thread_stack__call_return(struct thread *thread,
+				     struct thread_stack *ts, size_t idx,
+				     u64 timestamp, u64 ref, bool no_return)
+{
+	struct call_return_processor *crp = ts->crp;
+	struct thread_stack_entry *tse;
+	struct call_return cr = {
+		.thread = thread,
+		.comm = ts->comm,
+		.db_id = 0,
+	};
+
+	tse = &ts->stack[idx];
+	cr.cp = tse->cp;
+	cr.call_time = tse->timestamp;
+	cr.return_time = timestamp;
+	cr.branch_count = ts->branch_count - tse->branch_count;
+	cr.call_ref = tse->ref;
+	cr.return_ref = ref;
+	if (tse->no_call)
+		cr.flags |= CALL_RETURN_NO_CALL;
+	if (no_return)
+		cr.flags |= CALL_RETURN_NO_RETURN;
+
+	return crp->process(&cr, crp->data);
+}
+
+static int thread_stack__flush(struct thread *thread, struct thread_stack *ts)
+{
+	struct call_return_processor *crp = ts->crp;
+	int err;
+
+	if (!crp) {
+		ts->cnt = 0;
+		return 0;
+	}
+
+	while (ts->cnt) {
+		err = thread_stack__call_return(thread, ts, --ts->cnt,
+						ts->last_time, 0, true);
+		if (err) {
+			pr_err("Error flushing thread stack!\n");
+			ts->cnt = 0;
+			return err;
+		}
+	}
+
+	return 0;
+}
+
 void thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
 			 u64 to_ip, u16 insn_len, u64 trace_nr)
 {
@@ -99,17 +202,22 @@ void thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
 		return;
 
 	if (!thread->ts) {
-		thread->ts = thread_stack__new();
+		thread->ts = thread_stack__new(thread, NULL);
 		if (!thread->ts)
 			return;
 		thread->ts->trace_nr = trace_nr;
 	}
 
 	if (trace_nr != thread->ts->trace_nr) {
+		if (thread->ts->trace_nr)
+			thread_stack__flush(thread, thread->ts);
 		thread->ts->trace_nr = trace_nr;
-		thread->ts->cnt = 0;
 	}
 
+	/* Stop here if thread_stack__process() is in use */
+	if (thread->ts->crp)
+		return;
+
 	if (flags & PERF_FLAG_CALL) {
 		u64 ret_addr;
 
@@ -126,9 +234,22 @@ void thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
 	}
 }
 
+void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr)
+{
+	if (!thread || !thread->ts)
+		return;
+
+	if (trace_nr != thread->ts->trace_nr) {
+		if (thread->ts->trace_nr)
+			thread_stack__flush(thread, thread->ts);
+		thread->ts->trace_nr = trace_nr;
+	}
+}
+
 void thread_stack__free(struct thread *thread)
 {
 	if (thread->ts) {
+		thread_stack__flush(thread, thread->ts);
 		zfree(&thread->ts->stack);
 		zfree(&thread->ts);
 	}
@@ -149,3 +270,421 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
 	for (i = 1; i < chain->nr; i++)
 		chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr;
 }
+
+static void call_path__init(struct call_path *cp, struct call_path *parent,
+			    struct symbol *sym, u64 ip, bool in_kernel)
+{
+	cp->parent = parent;
+	cp->sym = sym;
+	cp->ip = sym ? 0 : ip;
+	cp->db_id = 0;
+	cp->in_kernel = in_kernel;
+	RB_CLEAR_NODE(&cp->rb_node);
+	cp->children = RB_ROOT;
+}
+
+static struct call_path_root *call_path_root__new(void)
+{
+	struct call_path_root *cpr;
+
+	cpr = zalloc(sizeof(struct call_path_root));
+	if (!cpr)
+		return NULL;
+	call_path__init(&cpr->call_path, NULL, NULL, 0, false);
+	INIT_LIST_HEAD(&cpr->blocks);
+	return cpr;
+}
+
+static void call_path_root__free(struct call_path_root *cpr)
+{
+	struct call_path_block *pos, *n;
+
+	list_for_each_entry_safe(pos, n, &cpr->blocks, node) {
+		list_del(&pos->node);
+		free(pos);
+	}
+	free(cpr);
+}
+
+static struct call_path *call_path__new(struct call_path_root *cpr,
+					struct call_path *parent,
+					struct symbol *sym, u64 ip,
+					bool in_kernel)
+{
+	struct call_path_block *cpb;
+	struct call_path *cp;
+	size_t n;
+
+	if (cpr->next < cpr->sz) {
+		cpb = list_last_entry(&cpr->blocks, struct call_path_block,
+				      node);
+	} else {
+		cpb = zalloc(sizeof(struct call_path_block));
+		if (!cpb)
+			return NULL;
+		list_add_tail(&cpb->node, &cpr->blocks);
+		cpr->sz += CALL_PATH_BLOCK_SIZE;
+	}
+
+	n = cpr->next++ & CALL_PATH_BLOCK_MASK;
+	cp = &cpb->cp[n];
+
+	call_path__init(cp, parent, sym, ip, in_kernel);
+
+	return cp;
+}
+
+static struct call_path *call_path__findnew(struct call_path_root *cpr,
+					    struct call_path *parent,
+					    struct symbol *sym, u64 ip, u64 ks)
+{
+	struct rb_node **p;
+	struct rb_node *node_parent = NULL;
+	struct call_path *cp;
+	bool in_kernel = ip >= ks;
+
+	if (sym)
+		ip = 0;
+
+	if (!parent)
+		return call_path__new(cpr, parent, sym, ip, in_kernel);
+
+	p = &parent->children.rb_node;
+	while (*p != NULL) {
+		node_parent = *p;
+		cp = rb_entry(node_parent, struct call_path, rb_node);
+
+		if (cp->sym == sym && cp->ip == ip)
+			return cp;
+
+		if (sym < cp->sym || (sym == cp->sym && ip < cp->ip))
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+
+	cp = call_path__new(cpr, parent, sym, ip, in_kernel);
+	if (!cp)
+		return NULL;
+
+	rb_link_node(&cp->rb_node, node_parent, p);
+	rb_insert_color(&cp->rb_node, &parent->children);
+
+	return cp;
+}
+
+struct call_return_processor *
+call_return_processor__new(int (*process)(struct call_return *cr, void *data),
+			   void *data)
+{
+	struct call_return_processor *crp;
+
+	crp = zalloc(sizeof(struct call_return_processor));
+	if (!crp)
+		return NULL;
+	crp->cpr = call_path_root__new();
+	if (!crp->cpr)
+		goto out_free;
+	crp->process = process;
+	crp->data = data;
+	return crp;
+
+out_free:
+	free(crp);
+	return NULL;
+}
+
+void call_return_processor__free(struct call_return_processor *crp)
+{
+	if (crp) {
+		call_path_root__free(crp->cpr);
+		free(crp);
+	}
+}
+
+static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
+				 u64 timestamp, u64 ref, struct call_path *cp,
+				 bool no_call)
+{
+	struct thread_stack_entry *tse;
+
+	if (ts->cnt == ts->sz) {
+		thread_stack__grow(ts);
+		if (ts->cnt == ts->sz)
+			return -ENOMEM;
+	}
+
+	tse = &ts->stack[ts->cnt++];
+	tse->ret_addr = ret_addr;
+	tse->timestamp = timestamp;
+	tse->ref = ref;
+	tse->branch_count = ts->branch_count;
+	tse->cp = cp;
+	tse->no_call = no_call;
+
+	return 0;
+}
+
+static int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
+				u64 ret_addr, u64 timestamp, u64 ref,
+				struct symbol *sym)
+{
+	int err;
+
+	if (!ts->cnt)
+		return 1;
+
+	if (ts->cnt == 1) {
+		struct thread_stack_entry *tse = &ts->stack[0];
+
+		if (tse->cp->sym == sym)
+			return thread_stack__call_return(thread, ts, --ts->cnt,
+							 timestamp, ref, false);
+	}
+
+	if (ts->stack[ts->cnt - 1].ret_addr == ret_addr) {
+		return thread_stack__call_return(thread, ts, --ts->cnt,
+						 timestamp, ref, false);
+	} else {
+		size_t i = ts->cnt - 1;
+
+		while (i--) {
+			if (ts->stack[i].ret_addr != ret_addr)
+				continue;
+			i += 1;
+			while (ts->cnt > i) {
+				err = thread_stack__call_return(thread, ts,
+								--ts->cnt,
+								timestamp, ref,
+								true);
+				if (err)
+					return err;
+			}
+			return thread_stack__call_return(thread, ts, --ts->cnt,
+							 timestamp, ref, false);
+		}
+	}
+
+	return 1;
+}
+
+static int thread_stack__bottom(struct thread *thread, struct thread_stack *ts,
+				struct perf_sample *sample,
+				struct addr_location *from_al,
+				struct addr_location *to_al, u64 ref)
+{
+	struct call_path_root *cpr = ts->crp->cpr;
+	struct call_path *cp;
+	struct symbol *sym;
+	u64 ip;
+
+	if (sample->ip) {
+		ip = sample->ip;
+		sym = from_al->sym;
+	} else if (sample->addr) {
+		ip = sample->addr;
+		sym = to_al->sym;
+	} else {
+		return 0;
+	}
+
+	cp = call_path__findnew(cpr, &cpr->call_path, sym, ip,
+				ts->kernel_start);
+	if (!cp)
+		return -ENOMEM;
+
+	return thread_stack__push_cp(thread->ts, ip, sample->time, ref, cp,
+				     true);
+}
+
+static int thread_stack__no_call_return(struct thread *thread,
+					struct thread_stack *ts,
+					struct perf_sample *sample,
+					struct addr_location *from_al,
+					struct addr_location *to_al, u64 ref)
+{
+	struct call_path_root *cpr = ts->crp->cpr;
+	struct call_path *cp, *parent;
+	u64 ks = ts->kernel_start;
+	int err;
+
+	if (sample->ip >= ks && sample->addr < ks) {
+		/* Return to userspace, so pop all kernel addresses */
+		while (thread_stack__in_kernel(ts)) {
+			err = thread_stack__call_return(thread, ts, --ts->cnt,
+							sample->time, ref,
+							true);
+			if (err)
+				return err;
+		}
+
+		/* If the stack is empty, push the userspace address */
+		if (!ts->cnt) {
+			cp = call_path__findnew(cpr, &cpr->call_path,
+						to_al->sym, sample->addr,
+						ts->kernel_start);
+			if (!cp)
+				return -ENOMEM;
+			return thread_stack__push_cp(ts, 0, sample->time, ref,
+						     cp, true);
+		}
+	} else if (thread_stack__in_kernel(ts) && sample->ip < ks) {
+		/* Return to userspace, so pop all kernel addresses */
+		while (thread_stack__in_kernel(ts)) {
+			err = thread_stack__call_return(thread, ts, --ts->cnt,
+							sample->time, ref,
+							true);
+			if (err)
+				return err;
+		}
+	}
+
+	if (ts->cnt)
+		parent = ts->stack[ts->cnt - 1].cp;
+	else
+		parent = &cpr->call_path;
+
+	/* This 'return' had no 'call', so push and pop top of stack */
+	cp = call_path__findnew(cpr, parent, from_al->sym, sample->ip,
+				ts->kernel_start);
+	if (!cp)
+		return -ENOMEM;
+
+	err = thread_stack__push_cp(ts, sample->addr, sample->time, ref, cp,
+				    true);
+	if (err)
+		return err;
+
+	return thread_stack__pop_cp(thread, ts, sample->addr, sample->time, ref,
+				    to_al->sym);
+}
+
+static int thread_stack__trace_begin(struct thread *thread,
+				     struct thread_stack *ts, u64 timestamp,
+				     u64 ref)
+{
+	struct thread_stack_entry *tse;
+	int err;
+
+	if (!ts->cnt)
+		return 0;
+
+	/* Pop trace end */
+	tse = &ts->stack[ts->cnt - 1];
+	if (tse->cp->sym == NULL && tse->cp->ip == 0) {
+		err = thread_stack__call_return(thread, ts, --ts->cnt,
+						timestamp, ref, false);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int thread_stack__trace_end(struct thread_stack *ts,
+				   struct perf_sample *sample, u64 ref)
+{
+	struct call_path_root *cpr = ts->crp->cpr;
+	struct call_path *cp;
+	u64 ret_addr;
+
+	/* No point having 'trace end' on the bottom of the stack */
+	if (!ts->cnt || (ts->cnt == 1 && ts->stack[0].ref == ref))
+		return 0;
+
+	cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp, NULL, 0,
+				ts->kernel_start);
+	if (!cp)
+		return -ENOMEM;
+
+	ret_addr = sample->ip + sample->insn_len;
+
+	return thread_stack__push_cp(ts, ret_addr, sample->time, ref, cp,
+				     false);
+}
+
+int thread_stack__process(struct thread *thread, struct comm *comm,
+			  struct perf_sample *sample,
+			  struct addr_location *from_al,
+			  struct addr_location *to_al, u64 ref,
+			  struct call_return_processor *crp)
+{
+	struct thread_stack *ts = thread->ts;
+	int err = 0;
+
+	if (ts) {
+		if (!ts->crp) {
+			/* Supersede thread_stack__event() */
+			thread_stack__free(thread);
+			thread->ts = thread_stack__new(thread, crp);
+			if (!thread->ts)
+				return -ENOMEM;
+			ts = thread->ts;
+			ts->comm = comm;
+		}
+	} else {
+		thread->ts = thread_stack__new(thread, crp);
+		if (!thread->ts)
+			return -ENOMEM;
+		ts = thread->ts;
+		ts->comm = comm;
+	}
+
+	/* Flush stack on exec */
+	if (ts->comm != comm && thread->pid_ == thread->tid) {
+		err = thread_stack__flush(thread, ts);
+		if (err)
+			return err;
+		ts->comm = comm;
+	}
+
+	/* If the stack is empty, put the current symbol on the stack */
+	if (!ts->cnt) {
+		err = thread_stack__bottom(thread, ts, sample, from_al, to_al,
+					   ref);
+		if (err)
+			return err;
+	}
+
+	ts->branch_count += 1;
+	ts->last_time = sample->time;
+
+	if (sample->flags & PERF_FLAG_CALL) {
+		struct call_path_root *cpr = ts->crp->cpr;
+		struct call_path *cp;
+		u64 ret_addr;
+
+		if (!sample->ip || !sample->addr)
+			return 0;
+
+		ret_addr = sample->ip + sample->insn_len;
+		if (ret_addr == sample->addr)
+			return 0; /* Zero-length calls are excluded */
+
+		cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp,
+					to_al->sym, sample->addr,
+					ts->kernel_start);
+		if (!cp)
+			return -ENOMEM;
+		err = thread_stack__push_cp(ts, ret_addr, sample->time, ref,
+					    cp, false);
+	} else if (sample->flags & PERF_FLAG_RETURN) {
+		if (!sample->ip || !sample->addr)
+			return 0;
+
+		err = thread_stack__pop_cp(thread, ts, sample->addr,
+					   sample->time, ref, from_al->sym);
+		if (err) {
+			if (err < 0)
+				return err;
+			err = thread_stack__no_call_return(thread, ts, sample,
+							   from_al, to_al, ref);
+		}
+	} else if (sample->flags & PERF_FLAG_TRACE_BEGIN) {
+		err = thread_stack__trace_begin(thread, ts, sample->time, ref);
+	} else if (sample->flags & PERF_FLAG_TRACE_END) {
+		err = thread_stack__trace_end(ts, sample, ref);
+	}
+
+	return err;
+}
tools/perf/util/thread-stack.h +47 -0

61 lines not on this page · raw message

Signature · 1 line
1.8.3.2
author reviewer
#78 lore raw

PATCH 39/52 perf tools: Add call information to the database export API

In reply to Adrian Hunter

Make it possible for the database export API to use the enhanced thread stack and export detailed information about paired calls and returns.

---
 tools/perf/util/db-export.c | 52 ++++++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/db-export.h | 12 +++++++++++
 2 files changed, 63 insertions(+), 1 deletion(-)
tools/perf/util/db-export.c +51 -1
index c5b6e02..ca79616 100644
@@ -21,6 +21,7 @@
 #include "comm.h"
 #include "symbol.h"
 #include "event.h"
+#include "thread-stack.h"
 #include "db-export.h"
 
 int db_export__init(struct db_export *dbe)
@@ -29,8 +30,10 @@ int db_export__init(struct db_export *dbe)
 	return 0;
 }
 
-void db_export__exit(struct db_export *dbe __maybe_unused)
+void db_export__exit(struct db_export *dbe)
 {
+	call_return_processor__free(dbe->crp);
+	dbe->crp = NULL;
 }
 
 int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel)
@@ -268,6 +271,13 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
 				     &es.addr_sym_db_id, &es.addr_offset);
 		if (err)
 			return err;
+		if (dbe->crp) {
+			err = thread_stack__process(thread, comm, sample, al,
+						    &addr_al, es.db_id,
+						    dbe->crp);
+			if (err)
+				return err;
+		}
 	}
 
 	if (dbe->export_sample)
@@ -314,3 +324,43 @@ int db_export__branch_types(struct db_export *dbe)
 	}
 	return err;
 }
+
+int db_export__call_path(struct db_export *dbe, struct call_path *cp)
+{
+	int err;
+
+	if (cp->db_id)
+		return 0;
+
+	if (cp->parent) {
+		err = db_export__call_path(dbe, cp->parent);
+		if (err)
+			return err;
+	}
+
+	cp->db_id = ++dbe->call_path_last_db_id;
+
+	if (dbe->export_call_path)
+		return dbe->export_call_path(dbe, cp);
+
+	return 0;
+}
+
+int db_export__call_return(struct db_export *dbe, struct call_return *cr)
+{
+	int err;
+
+	if (cr->db_id)
+		return 0;
+
+	err = db_export__call_path(dbe, cr->cp);
+	if (err)
+		return err;
+
+	cr->db_id = ++dbe->call_return_last_db_id;
+
+	if (dbe->export_call_return)
+		return dbe->export_call_return(dbe, cr);
+
+	return 0;
+}
tools/perf/util/db-export.h +12 -0
index e4baa45..dd5ac2a 100644
@@ -25,6 +25,9 @@ struct comm;
 struct dso;
 struct perf_sample;
 struct addr_location;
+struct call_return_processor;
+struct call_path;
+struct call_return;
 
 struct export_sample {
 	union perf_event	*event;
@@ -57,6 +60,10 @@ struct db_export {
 	int (*export_branch_type)(struct db_export *dbe, u32 branch_type,
 				  const char *name);
 	int (*export_sample)(struct db_export *dbe, struct export_sample *es);
+	int (*export_call_path)(struct db_export *dbe, struct call_path *cp);
+	int (*export_call_return)(struct db_export *dbe,
+				  struct call_return *cr);
+	struct call_return_processor *crp;
 	u64 evsel_last_db_id;
 	u64 machine_last_db_id;
 	u64 thread_last_db_id;
@@ -65,6 +72,8 @@ struct db_export {
 	u64 dso_last_db_id;
 	u64 symbol_last_db_id;
 	u64 sample_last_db_id;
+	u64 call_path_last_db_id;
+	u64 call_return_last_db_id;
 };
 
 int db_export__init(struct db_export *dbe);
@@ -89,4 +98,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
 
 int db_export__branch_types(struct db_export *dbe);
 
+int db_export__call_path(struct db_export *dbe, struct call_path *cp);
+int db_export__call_return(struct db_export *dbe, struct call_return *cr);
+
 #endif
Signature · 1 line
1.8.3.2
author reviewer
#79 lore raw

PATCH 40/52 perf tools: Add call information to Python export

In reply to Adrian Hunter

Add the ability to export detailed information about paired calls and returns to Python db export and the export-to-postgresql.py script.

---
 .../scripts/python/bin/export-to-postgresql-report | 15 ++--
 tools/perf/scripts/python/export-to-postgresql.py  | 66 ++++++++++++++++-
 .../util/scripting-engines/trace-event-python.c    | 84 +++++++++++++++++++++-
 3 files changed, 158 insertions(+), 7 deletions(-)
tools/perf/scripts/python/bin/export-to-postgresql-report +10 -5
index a8fdd15..cd335b6 100644
@@ -1,6 +1,6 @@
 #!/bin/bash
 # description: export perf data to a postgresql database
-# args: [database name] [columns]
+# args: [database name] [columns] [calls]
 n_args=0
 for i in "$@"
 do
@@ -9,11 +9,16 @@ do
     fi
     n_args=$(( $n_args + 1 ))
 done
-if [ "$n_args" -gt 2 ] ; then
-    echo "usage: export-to-postgresql-report [database name] [columns]"
+if [ "$n_args" -gt 3 ] ; then
+    echo "usage: export-to-postgresql-report [database name] [columns] [calls]"
     exit
 fi
-if [ "$n_args" -gt 1 ] ; then
+if [ "$n_args" -gt 2 ] ; then
+    dbname=$1
+    columns=$2
+    calls=$3
+    shift 3
+elif [ "$n_args" -gt 1 ] ; then
     dbname=$1
     columns=$2
     shift 2
@@ -21,4 +26,4 @@ elif [ "$n_args" -gt 0 ] ; then
     dbname=$1
     shift
 fi
-perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns
+perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns $calls
tools/perf/scripts/python/export-to-postgresql.py +65 -1

126 lines not on this page · raw message

tools/perf/util/scripting-engines/trace-event-python.c +83 -1

120 lines not on this page · raw message

Signature · 1 line
1.8.3.2
author reviewer
#80 lore raw

PATCH 41/52 perf tools: Add 'flush' callback to scripting API

In reply to Adrian Hunter

In order to defer some output via the scripting API, there needs to be a callback after session processing but before the session is deleted.

---
 tools/perf/builtin-script.c                            | 12 ++++++++++++
 tools/perf/util/scripting-engines/trace-event-perl.c   |  6 ++++++
 tools/perf/util/scripting-engines/trace-event-python.c |  6 ++++++
 tools/perf/util/trace-event-scripting.c                |  7 +++++++
 tools/perf/util/trace-event.h                          |  1 +
 5 files changed, 32 insertions(+)
tools/perf/builtin-script.c +12 -0
index 163d12b..4d4fe4e 100644
@@ -485,6 +485,11 @@ static int default_start_script(const char *script __maybe_unused,
 	return 0;
 }
 
+static int default_flush_script(void)
+{
+	return 0;
+}
+
 static int default_stop_script(void)
 {
 	return 0;
@@ -498,6 +503,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused,
 
 static struct scripting_ops default_scripting_ops = {
 	.start_script		= default_start_script,
+	.flush_script		= default_flush_script,
 	.stop_script		= default_stop_script,
 	.process_event		= process_event,
 	.generate_script	= default_generate_script,
@@ -513,6 +519,11 @@ static void setup_scripting(void)
 	scripting_ops = &default_scripting_ops;
 }
 
+static int flush_scripting(void)
+{
+	return scripting_ops->flush_script();
+}
+
 static int cleanup_scripting(void)
 {
 	pr_debug("\nperf script stopped\n");
@@ -1806,6 +1817,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 
 	err = __cmd_script(&script);
 
+	flush_scripting();
 	perf_session__delete(session);
 	cleanup_scripting();
 out:
tools/perf/util/scripting-engines/trace-event-perl.c +6 -0
index b2dba9c..0a01bac 100644
@@ -432,6 +432,11 @@ error:
 	return err;
 }
 
+static int perl_flush_script(void)
+{
+	return 0;
+}
+
 /*
  * Stop trace script
  */
@@ -633,6 +638,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)
 struct scripting_ops perl_scripting_ops = {
 	.name = "Perl",
 	.start_script = perl_start_script,
+	.flush_script = perl_flush_script,
 	.stop_script = perl_stop_script,
 	.process_event = perl_process_event,
 	.generate_script = perl_generate_script,
tools/perf/util/scripting-engines/trace-event-python.c +6 -0
index 5f7b76b..ed754d0 100644
@@ -1022,6 +1022,11 @@ error:
 	return err;
 }
 
+static int python_flush_script(void)
+{
+	return 0;
+}
+
 /*
  * Stop trace script
  */
@@ -1210,6 +1215,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
 struct scripting_ops python_scripting_ops = {
 	.name = "Python",
 	.start_script = python_start_script,
+	.flush_script = python_flush_script,
 	.stop_script = python_stop_script,
 	.process_event = python_process_event,
 	.generate_script = python_generate_script,
tools/perf/util/trace-event-scripting.c +7 -0
index 57aaccc..5c9bdd1 100644
@@ -30,6 +30,11 @@
 
 struct scripting_context *scripting_context;
 
+static int flush_script_unsupported(void)
+{
+	return 0;
+}
+
 static int stop_script_unsupported(void)
 {
 	return 0;
@@ -74,6 +79,7 @@ static int python_generate_script_unsupported(struct pevent *pevent
 struct scripting_ops python_scripting_unsupported_ops = {
 	.name = "Python",
 	.start_script = python_start_script_unsupported,
+	.flush_script = flush_script_unsupported,
 	.stop_script = stop_script_unsupported,
 	.process_event = process_event_unsupported,
 	.generate_script = python_generate_script_unsupported,
@@ -137,6 +143,7 @@ static int perl_generate_script_unsupported(struct pevent *pevent
 struct scripting_ops perl_scripting_unsupported_ops = {
 	.name = "Perl",
 	.start_script = perl_start_script_unsupported,
+	.flush_script = flush_script_unsupported,
 	.stop_script = stop_script_unsupported,
 	.process_event = process_event_unsupported,
 	.generate_script = perl_generate_script_unsupported,
tools/perf/util/trace-event.h +1 -0
index 7b6d686..52aaa19 100644
@@ -64,6 +64,7 @@ struct perf_session;
 struct scripting_ops {
 	const char *name;
 	int (*start_script) (const char *script, int argc, const char **argv);
+	int (*flush_script) (void);
 	int (*stop_script) (void);
 	void (*process_event) (union perf_event *event,
 			       struct perf_sample *sample,
Signature · 1 line
1.8.3.2
author reviewer
#81 lore raw

PATCH 42/52 perf tools: Defer export of comms that were not 'set'

In reply to Adrian Hunter

Tracing for a workload begins before the comm event is seen, which results in the initial comm having a string of the form ":<pid>" (e.g. ":12345"). In order to export the correct string, defer the export until the new script 'flush' callback.

---
 tools/perf/util/db-export.c                        | 62 +++++++++++++++++++++-
 tools/perf/util/db-export.h                        |  3 ++
 .../util/scripting-engines/trace-event-python.c    |  4 +-
 3 files changed, 67 insertions(+), 2 deletions(-)
tools/perf/util/db-export.c +61 -1
index ca79616..ef61cf7 100644
@@ -21,17 +21,74 @@
 #include "comm.h"
 #include "symbol.h"
 #include "event.h"
+#include "util.h"
 #include "thread-stack.h"
 #include "db-export.h"
 
+struct deferred_export {
+	struct list_head node;
+	struct comm *comm;
+};
+
+static int db_export__deferred(struct db_export *dbe)
+{
+	struct deferred_export *de;
+	int err;
+
+	while (!list_empty(&dbe->deferred)) {
+		de = list_entry(dbe->deferred.next, struct deferred_export,
+				node);
+		err = dbe->export_comm(dbe, de->comm);
+		list_del(&de->node);
+		free(de);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static void db_export__free_deferred(struct db_export *dbe)
+{
+	struct deferred_export *de;
+
+	while (!list_empty(&dbe->deferred)) {
+		de = list_entry(dbe->deferred.next, struct deferred_export,
+				node);
+		list_del(&de->node);
+		free(de);
+	}
+}
+
+static int db_export__defer_comm(struct db_export *dbe, struct comm *comm)
+{
+	struct deferred_export *de;
+
+	de = zalloc(sizeof(struct deferred_export));
+	if (!de)
+		return -ENOMEM;
+
+	de->comm = comm;
+	list_add_tail(&de->node, &dbe->deferred);
+
+	return 0;
+}
+
 int db_export__init(struct db_export *dbe)
 {
 	memset(dbe, 0, sizeof(struct db_export));
+	INIT_LIST_HEAD(&dbe->deferred);
 	return 0;
 }
 
+int db_export__flush(struct db_export *dbe)
+{
+	return db_export__deferred(dbe);
+}
+
 void db_export__exit(struct db_export *dbe)
 {
+	db_export__free_deferred(dbe);
 	call_return_processor__free(dbe->crp);
 	dbe->crp = NULL;
 }
@@ -115,7 +172,10 @@ int db_export__comm(struct db_export *dbe, struct comm *comm,
 	comm->db_id = ++dbe->comm_last_db_id;
 
 	if (dbe->export_comm) {
-		err = dbe->export_comm(dbe, comm);
+		if (main_thread->comm_set)
+			err = dbe->export_comm(dbe, comm);
+		else
+			err = db_export__defer_comm(dbe, comm);
 		if (err)
 			return err;
 	}
tools/perf/util/db-export.h +3 -0
index dd5ac2a..adbd22d 100644
@@ -17,6 +17,7 @@
 #define __PERF_DB_EXPORT_H
 
 #include <linux/types.h>
+#include <linux/list.h>
 
 struct perf_evsel;
 struct machine;
@@ -74,9 +75,11 @@ struct db_export {
 	u64 sample_last_db_id;
 	u64 call_path_last_db_id;
 	u64 call_return_last_db_id;
+	struct list_head deferred;
 };
 
 int db_export__init(struct db_export *dbe);
+int db_export__flush(struct db_export *dbe);
 void db_export__exit(struct db_export *dbe);
 int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel);
 int db_export__machine(struct db_export *dbe, struct machine *machine);
tools/perf/util/scripting-engines/trace-event-python.c +3 -1
index ed754d0..6c0ce62 100644
@@ -1024,7 +1024,9 @@ error:
 
 static int python_flush_script(void)
 {
-	return 0;
+	struct tables *tables = &tables_global;
+
+	return db_export__flush(&tables->dbe);
 }
 
 /*
Signature · 1 line
1.8.3.2
author reviewer
#82 lore raw

PATCH 43/52 perf tools: Add perf-with-kcore script

In reply to Adrian Hunter

Decoding an Intel PT trace of the kernel requires an accurate kernel object image. This is provided by making a copy of kcore. However the copy needs to be made under the same conditions as the original recording, and then it needs to be associated with the perf.data file. The perf-with-kcore script does that.

The script also checks the permissions on the buildid cache and can be used to fix them. That is needed for distributions where root does not have a home directory and consequently writes to the same buildid cache as the user, resulting in cached files that the user does not have access to.

Example:

$ ./perf-with-kcore
Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]
       <perf sub-command> can be record, script, report or inject
   or: perf-with-kcore fix_buildid_cache_permissions
$ ./perf-with-kcore record pt_uname -e intel_pt// -- uname
Recording
Using /home/ahunter/bin/perf
perf version 3.15.rc3.g4549ba
/home/ahunter/bin/perf record -o pt_uname/perf.data -e intel_pt//  -- uname
Linux
[ perf record: Woken up 3 times to write data ]
[ perf record: Captured and wrote 0.023 MB pt_uname/perf.data ]
Copying kcore
[sudo] password for ahunter:
Done
$ tools/perf/perf-with-kcore.sh script pt_uname | head
Using /home/ahunter/bin/perf
perf version 3.15.rc3.g4549ba
/home/ahunter/bin/perf script -i pt_uname/perf.data --kallsyms=pt_uname/kcore_dir/kallsyms
         swapper     0 [002] 161533.969666: sched:sched_switch: swapper/2:0 [120] R ==> perf:11316 [120]
          :11315 11315 [003] 161533.969704: sched:sched_switch: perf:11315 [120] S ==> swapper/3:0 [120]
          :11316 11316 [002] 161533.969783: sched:sched_switch: perf:11316 [120] R ==> migration/2:33 [0]
             :33    33 [002] 161533.969791: sched:sched_switch: migration/2:33 [0] S ==> swapper/2:0 [120]
         swapper     0 [003] 161533.969792: sched:sched_switch: swapper/3:0 [120] R ==> perf:11316 [120]
          :11316 11316 [003] 161533.970062: branches:                 0 [unknown] ([unknown]) => ffffffff810532fa native_write_msr_safe ([kernel.kallsyms])
          :11316 11316 [003] 161533.970062: branches:  ffffffff810532fd native_write_msr_safe ([kernel.kallsyms]) => ffffffff81035b31 pt_config_start ([kernel.kallsyms])
---
 tools/perf/.gitignore         |   1 +
 tools/perf/Makefile.perf      |   5 +-
 tools/perf/perf-with-kcore.sh | 259 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 264 insertions(+), 1 deletion(-)
 create mode 100644 tools/perf/perf-with-kcore.sh
tools/perf/.gitignore +1 -0
index 782d86e..717221e 100644
@@ -15,6 +15,7 @@ perf.data
 perf.data.old
 output.svg
 perf-archive
+perf-with-kcore
 tags
 TAGS
 cscope*
tools/perf/Makefile.perf +4 -1
index f7bb2b4..9b1f05d 100644
@@ -126,6 +126,7 @@ PYRF_OBJS =
 SCRIPT_SH =
 
 SCRIPT_SH += perf-archive.sh
+SCRIPT_SH += perf-with-kcore.sh
 
 grep-libs = $(filter -l%,$(1))
 strip-libs = $(filter-out -l%,$(1))
@@ -879,6 +880,8 @@ install-bin: all install-gtk
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 	$(call QUIET_INSTALL, perf-archive) \
 		$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
+	$(call QUIET_INSTALL, perf-with-kcore) \
+		$(INSTALL) $(OUTPUT)perf-with-kcore -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 ifndef NO_LIBPERL
 	$(call QUIET_INSTALL, perl-scripts) \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
@@ -924,7 +927,7 @@ config-clean:
 	@$(MAKE) -C config/feature-checks clean >/dev/null
 
 clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
-	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
+	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
 	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
 	$(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
 	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
tools/perf/perf-with-kcore.sh new file +259 -0

259 lines not on this page · raw message

Signature · 1 line
1.8.3.2
author reviewer
#83 lore raw

PATCH 44/52 perf tools: Pass machine to vdso__dso_findnew()

In reply to Adrian Hunter

This is preparation for removing the global variables used in vdso.c and thereby fixing the lifetime of the VDSO temporary file.

---
 tools/perf/util/machine.c | 4 ++--
 tools/perf/util/map.c     | 7 ++++---
 tools/perf/util/map.h     | 2 +-
 tools/perf/util/vdso.c    | 7 ++++---
 tools/perf/util/vdso.h    | 4 +++-
 5 files changed, 14 insertions(+), 10 deletions(-)
tools/perf/util/machine.c +2 -2
index 34dd63f..5d21792 100644
@@ -1124,7 +1124,7 @@ int machine__process_mmap2_event(struct machine *machine,
 	else
 		type = MAP__FUNCTION;
 
-	map = map__new(&machine->user_dsos, event->mmap2.start,
+	map = map__new(machine, event->mmap2.start,
 			event->mmap2.len, event->mmap2.pgoff,
 			event->mmap2.pid, event->mmap2.maj,
 			event->mmap2.min, event->mmap2.ino,
@@ -1174,7 +1174,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
 	else
 		type = MAP__FUNCTION;
 
-	map = map__new(&machine->user_dsos, event->mmap.start,
+	map = map__new(machine, event->mmap.start,
 			event->mmap.len, event->mmap.pgoff,
 			event->mmap.pid, 0, 0, 0, 0, 0, 0,
 			event->mmap.filename,
tools/perf/util/map.c +4 -3
index 845f627..dffc8dc 100644
@@ -13,6 +13,7 @@
 #include "build-id.h"
 #include "util.h"
 #include "debug.h"
+#include "machine.h"
 #include <linux/string.h>
 
 const char *map_type__name[MAP__NR_TYPES] = {
@@ -137,7 +138,7 @@ void map__init(struct map *map, enum map_type type,
 	map->erange_warned = false;
 }
 
-struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
+struct map *map__new(struct machine *machine, u64 start, u64 len,
 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
 		     u64 ino_gen, u32 prot, u32 flags, char *filename,
 		     enum map_type type)
@@ -173,9 +174,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
 
 		if (vdso) {
 			pgoff = 0;
-			dso = vdso__dso_findnew(dsos__list);
+			dso = vdso__dso_findnew(machine);
 		} else
-			dso = __dsos__findnew(dsos__list, filename);
+			dso = __dsos__findnew(&machine->user_dsos, filename);
 
 		if (dso == NULL)
 			goto out_delete;
tools/perf/util/map.h +1 -1
index 22d13a2..a95e677 100644
@@ -119,7 +119,7 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 
 void map__init(struct map *map, enum map_type type,
 	       u64 start, u64 end, u64 pgoff, struct dso *dso);
-struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
+struct map *map__new(struct machine *machine, u64 start, u64 len,
 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
 		     u64 ino_gen, u32 prot, u32 flags,
 		     char *filename, enum map_type type);
tools/perf/util/vdso.c +4 -3
index 2905824..da5ba4d 100644
@@ -11,6 +11,7 @@
 #include "vdso.h"
 #include "util.h"
 #include "symbol.h"
+#include "machine.h"
 #include "linux/string.h"
 #include "debug.h"
 
@@ -90,9 +91,9 @@ void vdso__exit(void)
 		unlink(vdso_file);
 }
 
-struct dso *vdso__dso_findnew(struct list_head *head)
+struct dso *vdso__dso_findnew(struct machine *machine)
 {
-	struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true);
+	struct dso *dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
 
 	if (!dso) {
 		char *file;
@@ -103,7 +104,7 @@ struct dso *vdso__dso_findnew(struct list_head *head)
 
 		dso = dso__new(VDSO__MAP_NAME);
 		if (dso != NULL) {
-			dsos__add(head, dso);
+			dsos__add(&machine->user_dsos, dso);
 			dso__set_long_name(dso, file, false);
 		}
 	}
tools/perf/util/vdso.h +3 -1
index 0f76e7c..9ab0738 100644
@@ -12,7 +12,9 @@ static inline bool is_vdso_map(const char *filename)
 	return !strcmp(filename, VDSO__MAP_NAME);
 }
 
-struct dso *vdso__dso_findnew(struct list_head *head);
+struct machine;
+
+struct dso *vdso__dso_findnew(struct machine *machine);
 void vdso__exit(void);
 
 #endif /* __PERF_VDSO__ */
Signature · 1 line
1.8.3.2
#84 lore raw

[tip:perf/core] perf tools: Pass machine to vdso__dso_findnew()

perf tools: Pass machine to vdso__dso_findnew()
Commit-ID:  2a03068c5cfa104768703cbefa2e23a6353f8de5
Gitweb:     http://git.kernel.org/tip/2a03068c5cfa104768703cbefa2e23a6353f8de5
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:53 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 16:45:50 -0300

perf tools: Pass machine to vdso__dso_findnew()

This is preparation for removing the global variables used in vdso.c and thereby fixing the lifetime of the VDSO temporary file.

---
 tools/perf/util/machine.c | 4 ++--
 tools/perf/util/map.c     | 7 ++++---
 tools/perf/util/map.h     | 2 +-
 tools/perf/util/vdso.c    | 7 ++++---
 tools/perf/util/vdso.h    | 4 +++-
 5 files changed, 14 insertions(+), 10 deletions(-)
tools/perf/util/machine.c +2 -2
index cfc6910..a25f3ee 100644
@@ -1095,7 +1095,7 @@ int machine__process_mmap2_event(struct machine *machine,
 	else
 		type = MAP__FUNCTION;
 
-	map = map__new(&machine->user_dsos, event->mmap2.start,
+	map = map__new(machine, event->mmap2.start,
 			event->mmap2.len, event->mmap2.pgoff,
 			event->mmap2.pid, event->mmap2.maj,
 			event->mmap2.min, event->mmap2.ino,
@@ -1145,7 +1145,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
 	else
 		type = MAP__FUNCTION;
 
-	map = map__new(&machine->user_dsos, event->mmap.start,
+	map = map__new(machine, event->mmap.start,
 			event->mmap.len, event->mmap.pgoff,
 			event->mmap.pid, 0, 0, 0, 0, 0, 0,
 			event->mmap.filename,
tools/perf/util/map.c +4 -3
index 845f627..dffc8dc 100644
@@ -13,6 +13,7 @@
 #include "build-id.h"
 #include "util.h"
 #include "debug.h"
+#include "machine.h"
 #include <linux/string.h>
 
 const char *map_type__name[MAP__NR_TYPES] = {
@@ -137,7 +138,7 @@ void map__init(struct map *map, enum map_type type,
 	map->erange_warned = false;
 }
 
-struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
+struct map *map__new(struct machine *machine, u64 start, u64 len,
 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
 		     u64 ino_gen, u32 prot, u32 flags, char *filename,
 		     enum map_type type)
@@ -173,9 +174,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
 
 		if (vdso) {
 			pgoff = 0;
-			dso = vdso__dso_findnew(dsos__list);
+			dso = vdso__dso_findnew(machine);
 		} else
-			dso = __dsos__findnew(dsos__list, filename);
+			dso = __dsos__findnew(&machine->user_dsos, filename);
 
 		if (dso == NULL)
 			goto out_delete;
tools/perf/util/map.h +1 -1
index 22d13a2..a95e677 100644
@@ -119,7 +119,7 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 
 void map__init(struct map *map, enum map_type type,
 	       u64 start, u64 end, u64 pgoff, struct dso *dso);
-struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
+struct map *map__new(struct machine *machine, u64 start, u64 len,
 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
 		     u64 ino_gen, u32 prot, u32 flags,
 		     char *filename, enum map_type type);
tools/perf/util/vdso.c +4 -3
index 2905824..da5ba4d 100644
@@ -11,6 +11,7 @@
 #include "vdso.h"
 #include "util.h"
 #include "symbol.h"
+#include "machine.h"
 #include "linux/string.h"
 #include "debug.h"
 
@@ -90,9 +91,9 @@ void vdso__exit(void)
 		unlink(vdso_file);
 }
 
-struct dso *vdso__dso_findnew(struct list_head *head)
+struct dso *vdso__dso_findnew(struct machine *machine)
 {
-	struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true);
+	struct dso *dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
 
 	if (!dso) {
 		char *file;
@@ -103,7 +104,7 @@ struct dso *vdso__dso_findnew(struct list_head *head)
 
 		dso = dso__new(VDSO__MAP_NAME);
 		if (dso != NULL) {
-			dsos__add(head, dso);
+			dsos__add(&machine->user_dsos, dso);
 			dso__set_long_name(dso, file, false);
 		}
 	}
tools/perf/util/vdso.h +3 -1
index 0f76e7c..9ab0738 100644
@@ -12,7 +12,9 @@ static inline bool is_vdso_map(const char *filename)
 	return !strcmp(filename, VDSO__MAP_NAME);
 }
 
-struct dso *vdso__dso_findnew(struct list_head *head);
+struct machine;
+
+struct dso *vdso__dso_findnew(struct machine *machine);
 void vdso__exit(void);
 
 #endif /* __PERF_VDSO__ */
author reviewer
#85 lore raw

PATCH 45/52 perf tools: Group VDSO global variables into a structure

In reply to Adrian Hunter

This is preparation for removing the global variables used in vdso.c and thereby fixing the lifetime of the VDSO temporary file.

Also allowance is made for the later addition of
support for compat VDSOs.

---
 tools/perf/util/vdso.c | 44 ++++++++++++++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 12 deletions(-)
tools/perf/util/vdso.c +32 -12
index da5ba4d..75245f0 100644
@@ -15,8 +15,27 @@
 #include "linux/string.h"
 #include "debug.h"
 
-static bool vdso_found;
-static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
+#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
+
+struct vdso_file {
+	bool found;
+	bool error;
+	char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
+	const char *dso_name;
+};
+
+struct vdso_info {
+	struct vdso_file vdso;
+};
+
+static struct vdso_info vdso_info_ = {
+	.vdso = {
+		.temp_file_name = VDSO__TEMP_FILE_NAME,
+		.dso_name = VDSO__MAP_NAME,
+	},
+};
+
+static struct vdso_info *vdso_info = &vdso_info_;
 
 static int find_vdso_map(void **start, void **end)
 {
@@ -49,7 +68,7 @@ static int find_vdso_map(void **start, void **end)
 	return !found;
 }
 
-static char *get_file(void)
+static char *get_file(struct vdso_file *vdso_file)
 {
 	char *vdso = NULL;
 	char *buf = NULL;
@@ -57,10 +76,10 @@ static char *get_file(void)
 	size_t size;
 	int fd;
 
-	if (vdso_found)
-		return vdso_file;
+	if (vdso_file->found)
+		return vdso_file->temp_file_name;
 
-	if (find_vdso_map(&start, &end))
+	if (vdso_file->error || find_vdso_map(&start, &end))
 		return NULL;
 
 	size = end - start;
@@ -69,26 +88,27 @@ static char *get_file(void)
 	if (!buf)
 		return NULL;
 
-	fd = mkstemp(vdso_file);
+	fd = mkstemp(vdso_file->temp_file_name);
 	if (fd < 0)
 		goto out;
 
 	if (size == (size_t) write(fd, buf, size))
-		vdso = vdso_file;
+		vdso = vdso_file->temp_file_name;
 
 	close(fd);
 
  out:
 	free(buf);
 
-	vdso_found = (vdso != NULL);
+	vdso_file->found = (vdso != NULL);
+	vdso_file->error = !vdso_file->found;
 	return vdso;
 }
 
 void vdso__exit(void)
 {
-	if (vdso_found)
-		unlink(vdso_file);
+	if (vdso_info->vdso.found)
+		unlink(vdso_info->vdso.temp_file_name);
 }
 
 struct dso *vdso__dso_findnew(struct machine *machine)
@@ -98,7 +118,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)
 	if (!dso) {
 		char *file;
 
-		file = get_file();
+		file = get_file(&vdso_info->vdso);
 		if (!file)
 			return NULL;
 
Signature · 1 line
1.8.3.2
#86 lore raw

[tip:perf/core] perf tools: Group VDSO global variables into a structure

perf tools: Group VDSO global variables into a structure
Commit-ID:  30f4f815a45d0b148d17afb0d5a5575ae2ba4309
Gitweb:     http://git.kernel.org/tip/30f4f815a45d0b148d17afb0d5a5575ae2ba4309
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:54 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 17:11:26 -0300

perf tools: Group VDSO global variables into a structure

This is preparation for removing the global variables used in vdso.c and thereby fixing the lifetime of the VDSO temporary file.

Also allowance is made for the later addition of support for compat VDSOs.

---
 tools/perf/util/vdso.c | 44 ++++++++++++++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 12 deletions(-)
tools/perf/util/vdso.c +32 -12
index da5ba4d..75245f0 100644
@@ -15,8 +15,27 @@
 #include "linux/string.h"
 #include "debug.h"
 
-static bool vdso_found;
-static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
+#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
+
+struct vdso_file {
+	bool found;
+	bool error;
+	char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
+	const char *dso_name;
+};
+
+struct vdso_info {
+	struct vdso_file vdso;
+};
+
+static struct vdso_info vdso_info_ = {
+	.vdso = {
+		.temp_file_name = VDSO__TEMP_FILE_NAME,
+		.dso_name = VDSO__MAP_NAME,
+	},
+};
+
+static struct vdso_info *vdso_info = &vdso_info_;
 
 static int find_vdso_map(void **start, void **end)
 {
@@ -49,7 +68,7 @@ static int find_vdso_map(void **start, void **end)
 	return !found;
 }
 
-static char *get_file(void)
+static char *get_file(struct vdso_file *vdso_file)
 {
 	char *vdso = NULL;
 	char *buf = NULL;
@@ -57,10 +76,10 @@ static char *get_file(void)
 	size_t size;
 	int fd;
 
-	if (vdso_found)
-		return vdso_file;
+	if (vdso_file->found)
+		return vdso_file->temp_file_name;
 
-	if (find_vdso_map(&start, &end))
+	if (vdso_file->error || find_vdso_map(&start, &end))
 		return NULL;
 
 	size = end - start;
@@ -69,26 +88,27 @@ static char *get_file(void)
 	if (!buf)
 		return NULL;
 
-	fd = mkstemp(vdso_file);
+	fd = mkstemp(vdso_file->temp_file_name);
 	if (fd < 0)
 		goto out;
 
 	if (size == (size_t) write(fd, buf, size))
-		vdso = vdso_file;
+		vdso = vdso_file->temp_file_name;
 
 	close(fd);
 
  out:
 	free(buf);
 
-	vdso_found = (vdso != NULL);
+	vdso_file->found = (vdso != NULL);
+	vdso_file->error = !vdso_file->found;
 	return vdso;
 }
 
 void vdso__exit(void)
 {
-	if (vdso_found)
-		unlink(vdso_file);
+	if (vdso_info->vdso.found)
+		unlink(vdso_info->vdso.temp_file_name);
 }
 
 struct dso *vdso__dso_findnew(struct machine *machine)
@@ -98,7 +118,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)
 	if (!dso) {
 		char *file;
 
-		file = get_file();
+		file = get_file(&vdso_info->vdso);
 		if (!file)
 			return NULL;
 
author reviewer
#87 lore raw

PATCH 46/52 perf tools: Fix the lifetime of the VDSO temporary file

In reply to Adrian Hunter

The VDSO temporary file is unlinked when a session is deleted. That precludes the possibilities that there is no session or there is more than one session. Correctly the vdso belongs to the machine so put the information on 'struct machine' and get rid of the global variables.

---
 tools/perf/util/machine.c |  2 ++
 tools/perf/util/machine.h |  3 +++
 tools/perf/util/session.c |  2 --
 tools/perf/util/vdso.c    | 39 +++++++++++++++++++++++++++++----------
 tools/perf/util/vdso.h    |  2 +-
 5 files changed, 35 insertions(+), 13 deletions(-)
tools/perf/util/machine.c +2 -0
index 5d21792..9b9fd26 100644
@@ -8,6 +8,7 @@
 #include "sort.h"
 #include "strlist.h"
 #include "thread.h"
+#include "vdso.h"
 #include <stdbool.h>
 #include <symbol/kallsyms.h>
 #include "unwind.h"
@@ -107,6 +108,7 @@ void machine__exit(struct machine *machine)
 	map_groups__exit(&machine->kmaps);
 	dsos__delete(&machine->user_dsos);
 	dsos__delete(&machine->kernel_dsos);
+	vdso__exit(machine);
 	zfree(&machine->root_dir);
 	zfree(&machine->current_tid);
 }
tools/perf/util/machine.h +3 -0
index f91a7e1..f385f23 100644
@@ -20,6 +20,8 @@ union perf_event;
 
 extern const char *ref_reloc_sym_names[];
 
+struct vdso_info;
+
 struct machine {
 	struct rb_node	  rb_node;
 	pid_t		  pid;
@@ -29,6 +31,7 @@ struct machine {
 	struct rb_root	  threads;
 	struct list_head  dead_threads;
 	struct thread	  *last_match;
+	struct vdso_info  *vdso_info;
 	struct list_head  user_dsos;
 	struct list_head  kernel_dsos;
 	struct map_groups kmaps;
tools/perf/util/session.c +0 -2
index ca3cd1f..5ad5e12 100644
@@ -14,7 +14,6 @@
 #include "util.h"
 #include "cpumap.h"
 #include "perf_regs.h"
-#include "vdso.h"
 
 static int perf_session__open(struct perf_session *session)
 {
@@ -176,7 +175,6 @@ void perf_session__delete(struct perf_session *session)
 	if (session->file)
 		perf_data_file__close(session->file);
 	free(session);
-	vdso__exit();
 }
 
 static int process_event_synth_tracing_data_stub(struct perf_tool *tool
tools/perf/util/vdso.c +29 -10
index 75245f0..fdaccaf 100644
@@ -28,14 +28,17 @@ struct vdso_info {
 	struct vdso_file vdso;
 };
 
-static struct vdso_info vdso_info_ = {
-	.vdso = {
-		.temp_file_name = VDSO__TEMP_FILE_NAME,
-		.dso_name = VDSO__MAP_NAME,
-	},
-};
-
-static struct vdso_info *vdso_info = &vdso_info_;
+static struct vdso_info *vdso_info__new(void)
+{
+	static const struct vdso_info vdso_info_init = {
+		.vdso    = {
+			.temp_file_name = VDSO__TEMP_FILE_NAME,
+			.dso_name = VDSO__MAP_NAME,
+		},
+	};
+
+	return memdup(&vdso_info_init, sizeof(vdso_info_init));
+}
 
 static int find_vdso_map(void **start, void **end)
 {
@@ -105,16 +108,32 @@ static char *get_file(struct vdso_file *vdso_file)
 	return vdso;
 }
 
-void vdso__exit(void)
+void vdso__exit(struct machine *machine)
 {
+	struct vdso_info *vdso_info = machine->vdso_info;
+
+	if (!vdso_info)
+		return;
+
 	if (vdso_info->vdso.found)
 		unlink(vdso_info->vdso.temp_file_name);
+
+	zfree(&machine->vdso_info);
 }
 
 struct dso *vdso__dso_findnew(struct machine *machine)
 {
-	struct dso *dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
+	struct vdso_info *vdso_info;
+	struct dso *dso;
+
+	if (!machine->vdso_info)
+		machine->vdso_info = vdso_info__new();
+
+	vdso_info = machine->vdso_info;
+	if (!vdso_info)
+		return NULL;
 
+	dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
 	if (!dso) {
 		char *file;
 
tools/perf/util/vdso.h +1 -1
index 9ab0738..7cf1576 100644
@@ -15,6 +15,6 @@ static inline bool is_vdso_map(const char *filename)
 struct machine;
 
 struct dso *vdso__dso_findnew(struct machine *machine);
-void vdso__exit(void);
+void vdso__exit(struct machine *machine);
 
 #endif /* __PERF_VDSO__ */
Signature · 1 line
1.8.3.2
author reviewer
#88 lore raw

PATCH v2 46/52 perf tools: Fix the lifetime of the VDSO temporary file

The VDSO temporary file is unlinked when a session is deleted. That precludes the possibilities that there is no session or there is more than one session. Correctly the vdso belongs to the machine so put the information on 'struct machine' and get rid of the global variables.

---

V2:
Initialize vdso_info to NULL in machine_init()

The change is reflected in the branch here:

http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/for-acme

 tools/perf/util/machine.c |  4 ++++
 tools/perf/util/machine.h |  3 +++
 tools/perf/util/session.c |  2 --
 tools/perf/util/vdso.c    | 39 +++++++++++++++++++++++++++++----------
 tools/perf/util/vdso.h    |  2 +-
 5 files changed, 37 insertions(+), 13 deletions(-)
tools/perf/util/machine.c +4 -0
index 5d21792..1732cc1 100644
@@ -8,6 +8,7 @@
 #include "sort.h"
 #include "strlist.h"
 #include "thread.h"
+#include "vdso.h"
 #include <stdbool.h>
 #include <symbol/kallsyms.h>
 #include "unwind.h"
@@ -23,6 +24,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 	INIT_LIST_HEAD(&machine->dead_threads);
 	machine->last_match = NULL;
 
+	machine->vdso_info = NULL;
+
 	machine->kmaps.machine = machine;
 	machine->pid = pid;
 
@@ -107,6 +110,7 @@ void machine__exit(struct machine *machine)
 	map_groups__exit(&machine->kmaps);
 	dsos__delete(&machine->user_dsos);
 	dsos__delete(&machine->kernel_dsos);
+	vdso__exit(machine);
 	zfree(&machine->root_dir);
 	zfree(&machine->current_tid);
 }
tools/perf/util/machine.h +3 -0
index f91a7e1..f385f23 100644
@@ -20,6 +20,8 @@ union perf_event;
 
 extern const char *ref_reloc_sym_names[];
 
+struct vdso_info;
+
 struct machine {
 	struct rb_node	  rb_node;
 	pid_t		  pid;
@@ -29,6 +31,7 @@ struct machine {
 	struct rb_root	  threads;
 	struct list_head  dead_threads;
 	struct thread	  *last_match;
+	struct vdso_info  *vdso_info;
 	struct list_head  user_dsos;
 	struct list_head  kernel_dsos;
 	struct map_groups kmaps;
tools/perf/util/session.c +0 -2
index ca3cd1f..5ad5e12 100644
@@ -14,7 +14,6 @@
 #include "util.h"
 #include "cpumap.h"
 #include "perf_regs.h"
-#include "vdso.h"
 
 static int perf_session__open(struct perf_session *session)
 {
@@ -176,7 +175,6 @@ void perf_session__delete(struct perf_session *session)
 	if (session->file)
 		perf_data_file__close(session->file);
 	free(session);
-	vdso__exit();
 }
 
 static int process_event_synth_tracing_data_stub(struct perf_tool *tool
tools/perf/util/vdso.c +29 -10
index 75245f0..fdaccaf 100644
@@ -28,14 +28,17 @@ struct vdso_info {
 	struct vdso_file vdso;
 };
 
-static struct vdso_info vdso_info_ = {
-	.vdso = {
-		.temp_file_name = VDSO__TEMP_FILE_NAME,
-		.dso_name = VDSO__MAP_NAME,
-	},
-};
-
-static struct vdso_info *vdso_info = &vdso_info_;
+static struct vdso_info *vdso_info__new(void)
+{
+	static const struct vdso_info vdso_info_init = {
+		.vdso    = {
+			.temp_file_name = VDSO__TEMP_FILE_NAME,
+			.dso_name = VDSO__MAP_NAME,
+		},
+	};
+
+	return memdup(&vdso_info_init, sizeof(vdso_info_init));
+}
 
 static int find_vdso_map(void **start, void **end)
 {
@@ -105,16 +108,32 @@ static char *get_file(struct vdso_file *vdso_file)
 	return vdso;
 }
 
-void vdso__exit(void)
+void vdso__exit(struct machine *machine)
 {
+	struct vdso_info *vdso_info = machine->vdso_info;
+
+	if (!vdso_info)
+		return;
+
 	if (vdso_info->vdso.found)
 		unlink(vdso_info->vdso.temp_file_name);
+
+	zfree(&machine->vdso_info);
 }
 
 struct dso *vdso__dso_findnew(struct machine *machine)
 {
-	struct dso *dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
+	struct vdso_info *vdso_info;
+	struct dso *dso;
+
+	if (!machine->vdso_info)
+		machine->vdso_info = vdso_info__new();
+
+	vdso_info = machine->vdso_info;
+	if (!vdso_info)
+		return NULL;
 
+	dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
 	if (!dso) {
 		char *file;
 
tools/perf/util/vdso.h +1 -1
index 9ab0738..7cf1576 100644
@@ -15,6 +15,6 @@ static inline bool is_vdso_map(const char *filename)
 struct machine;
 
 struct dso *vdso__dso_findnew(struct machine *machine);
-void vdso__exit(void);
+void vdso__exit(struct machine *machine);
 
 #endif /* __PERF_VDSO__ */
Signature · 1 line
1.8.3.2
#89 lore raw

[tip:perf/core] perf machine: Fix the lifetime of the VDSO temporary file

perf machine: Fix the lifetime of the VDSO temporary file
Commit-ID:  d027b64001b21328cc92d35c6444e1a7a926ea76
Gitweb:     http://git.kernel.org/tip/d027b64001b21328cc92d35c6444e1a7a926ea76
Author:     Adrian Hunter <[email protected]>
AuthorDate: Wed, 23 Jul 2014 14:23:00 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 17:14:39 -0300

perf machine: Fix the lifetime of the VDSO temporary file

The VDSO temporary file is unlinked when a session is deleted. That precludes the possibilities that there is no session or there is more than one session.

Correctly the vdso belongs to the machine so put the information on 'struct machine' and get rid of the global variables.

---
 tools/perf/util/machine.c |  4 ++++
 tools/perf/util/machine.h |  3 +++
 tools/perf/util/session.c |  2 --
 tools/perf/util/vdso.c    | 39 +++++++++++++++++++++++++++++----------
 tools/perf/util/vdso.h    |  2 +-
 5 files changed, 37 insertions(+), 13 deletions(-)
tools/perf/util/machine.c +4 -0
index a25f3ee..65269b8 100644
@@ -8,6 +8,7 @@
 #include "sort.h"
 #include "strlist.h"
 #include "thread.h"
+#include "vdso.h"
 #include <stdbool.h>
 #include <symbol/kallsyms.h>
 #include "unwind.h"
@@ -23,6 +24,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 	INIT_LIST_HEAD(&machine->dead_threads);
 	machine->last_match = NULL;
 
+	machine->vdso_info = NULL;
+
 	machine->kmaps.machine = machine;
 	machine->pid = pid;
 
@@ -105,6 +108,7 @@ void machine__exit(struct machine *machine)
 	map_groups__exit(&machine->kmaps);
 	dsos__delete(&machine->user_dsos);
 	dsos__delete(&machine->kernel_dsos);
+	vdso__exit(machine);
 	zfree(&machine->root_dir);
 	zfree(&machine->current_tid);
 }
tools/perf/util/machine.h +3 -0
index 8771d0c..b972824 100644
@@ -20,6 +20,8 @@ union perf_event;
 
 extern const char *ref_reloc_sym_names[];
 
+struct vdso_info;
+
 struct machine {
 	struct rb_node	  rb_node;
 	pid_t		  pid;
@@ -28,6 +30,7 @@ struct machine {
 	struct rb_root	  threads;
 	struct list_head  dead_threads;
 	struct thread	  *last_match;
+	struct vdso_info  *vdso_info;
 	struct list_head  user_dsos;
 	struct list_head  kernel_dsos;
 	struct map_groups kmaps;
tools/perf/util/session.c +0 -2
index d3da105..fab5838 100644
@@ -14,7 +14,6 @@
 #include "util.h"
 #include "cpumap.h"
 #include "perf_regs.h"
-#include "vdso.h"
 
 static int perf_session__open(struct perf_session *session)
 {
@@ -156,7 +155,6 @@ void perf_session__delete(struct perf_session *session)
 	if (session->file)
 		perf_data_file__close(session->file);
 	free(session);
-	vdso__exit();
 }
 
 static int process_event_synth_tracing_data_stub(struct perf_tool *tool
tools/perf/util/vdso.c +29 -10
index 75245f0..fdaccaf 100644
@@ -28,14 +28,17 @@ struct vdso_info {
 	struct vdso_file vdso;
 };
 
-static struct vdso_info vdso_info_ = {
-	.vdso = {
-		.temp_file_name = VDSO__TEMP_FILE_NAME,
-		.dso_name = VDSO__MAP_NAME,
-	},
-};
-
-static struct vdso_info *vdso_info = &vdso_info_;
+static struct vdso_info *vdso_info__new(void)
+{
+	static const struct vdso_info vdso_info_init = {
+		.vdso    = {
+			.temp_file_name = VDSO__TEMP_FILE_NAME,
+			.dso_name = VDSO__MAP_NAME,
+		},
+	};
+
+	return memdup(&vdso_info_init, sizeof(vdso_info_init));
+}
 
 static int find_vdso_map(void **start, void **end)
 {
@@ -105,16 +108,32 @@ static char *get_file(struct vdso_file *vdso_file)
 	return vdso;
 }
 
-void vdso__exit(void)
+void vdso__exit(struct machine *machine)
 {
+	struct vdso_info *vdso_info = machine->vdso_info;
+
+	if (!vdso_info)
+		return;
+
 	if (vdso_info->vdso.found)
 		unlink(vdso_info->vdso.temp_file_name);
+
+	zfree(&machine->vdso_info);
 }
 
 struct dso *vdso__dso_findnew(struct machine *machine)
 {
-	struct dso *dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
+	struct vdso_info *vdso_info;
+	struct dso *dso;
+
+	if (!machine->vdso_info)
+		machine->vdso_info = vdso_info__new();
+
+	vdso_info = machine->vdso_info;
+	if (!vdso_info)
+		return NULL;
 
+	dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
 	if (!dso) {
 		char *file;
 
tools/perf/util/vdso.h +1 -1
index 9ab0738..7cf1576 100644
@@ -15,6 +15,6 @@ static inline bool is_vdso_map(const char *filename)
 struct machine;
 
 struct dso *vdso__dso_findnew(struct machine *machine);
-void vdso__exit(void);
+void vdso__exit(struct machine *machine);
 
 #endif /* __PERF_VDSO__ */
author reviewer
#90 lore raw

PATCH 47/52 perf tools: Add vdso__new()

In reply to Adrian Hunter

This is preparation for adding support for
compat VDSOs.

---
 tools/perf/util/vdso.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/util/vdso.c +15 -5
index fdaccaf..946d927 100644
@@ -121,6 +121,20 @@ void vdso__exit(struct machine *machine)
 	zfree(&machine->vdso_info);
 }
 
+static struct dso *vdso__new(struct machine *machine, const char *short_name,
+			     const char *long_name)
+{
+	struct dso *dso;
+
+	dso = dso__new(short_name);
+	if (dso != NULL) {
+		dsos__add(&machine->user_dsos, dso);
+		dso__set_long_name(dso, long_name, false);
+	}
+
+	return dso;
+}
+
 struct dso *vdso__dso_findnew(struct machine *machine)
 {
 	struct vdso_info *vdso_info;
@@ -141,11 +155,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)
 		if (!file)
 			return NULL;
 
-		dso = dso__new(VDSO__MAP_NAME);
-		if (dso != NULL) {
-			dsos__add(&machine->user_dsos, dso);
-			dso__set_long_name(dso, file, false);
-		}
+		dso = vdso__new(machine, VDSO__MAP_NAME, file);
 	}
 
 	return dso;
Signature · 1 line
1.8.3.2
#91 lore raw

[tip:perf/core] perf tools: Add vdso__new()

perf tools: Add vdso__new()
Commit-ID:  4f71f2a0abe8b2a76669a4608a62f5020a64205a
Gitweb:     http://git.kernel.org/tip/4f71f2a0abe8b2a76669a4608a62f5020a64205a
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:56 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 17:34:47 -0300

perf tools: Add vdso__new()

This is preparation for adding support for compat VDSOs.

---
 tools/perf/util/vdso.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/util/vdso.c +15 -5
index fdaccaf..946d927 100644
@@ -121,6 +121,20 @@ void vdso__exit(struct machine *machine)
 	zfree(&machine->vdso_info);
 }
 
+static struct dso *vdso__new(struct machine *machine, const char *short_name,
+			     const char *long_name)
+{
+	struct dso *dso;
+
+	dso = dso__new(short_name);
+	if (dso != NULL) {
+		dsos__add(&machine->user_dsos, dso);
+		dso__set_long_name(dso, long_name, false);
+	}
+
+	return dso;
+}
+
 struct dso *vdso__dso_findnew(struct machine *machine)
 {
 	struct vdso_info *vdso_info;
@@ -141,11 +155,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)
 		if (!file)
 			return NULL;
 
-		dso = dso__new(VDSO__MAP_NAME);
-		if (dso != NULL) {
-			dsos__add(&machine->user_dsos, dso);
-			dso__set_long_name(dso, file, false);
-		}
+		dso = vdso__new(machine, VDSO__MAP_NAME, file);
 	}
 
 	return dso;
author reviewer
#92 lore raw

PATCH 48/52 perf tools: Separate the VDSO map name from the VDSO dso name

In reply to Adrian Hunter

This is in preparation for supporting 32-bit compatibility VDSOs.

---
 tools/perf/util/header.c     | 10 +++++-----
 tools/perf/util/symbol-elf.c |  2 +-
 tools/perf/util/vdso.c       | 11 ++++++++---
 tools/perf/util/vdso.h       |  6 ++++++
 4 files changed, 20 insertions(+), 9 deletions(-)
tools/perf/util/header.c +5 -5
index a588a3e..158c787 100644
@@ -256,9 +256,9 @@ static int __dsos__write_buildid_table(struct list_head *head,
 		if (!pos->hit)
 			continue;
 
-		if (is_vdso_map(pos->short_name)) {
-			name = (char *) VDSO__MAP_NAME;
-			name_len = sizeof(VDSO__MAP_NAME) + 1;
+		if (dso__is_vdso(pos)) {
+			name = pos->short_name;
+			name_len = pos->short_name_len + 1;
 		} else if (dso__is_kcore(pos)) {
 			machine__mmap_name(machine, nm, sizeof(nm));
 			name = nm;
@@ -339,7 +339,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
 
 	len = scnprintf(filename, size, "%s%s%s",
 		       debugdir, slash ? "/" : "",
-		       is_vdso ? VDSO__MAP_NAME : realname);
+		       is_vdso ? DSO__NAME_VDSO : realname);
 	if (mkdir_p(filename, 0755))
 		goto out_free;
 
@@ -427,7 +427,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
 			       const char *debugdir)
 {
 	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
-	bool is_vdso = is_vdso_map(dso->short_name);
+	bool is_vdso = dso__is_vdso(dso);
 	const char *name = dso->long_name;
 	char nm[PATH_MAX];
 
tools/perf/util/symbol-elf.c +1 -1
index 84f5e2a..0387780 100644
@@ -622,7 +622,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 		GElf_Shdr shdr;
 		ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
 				ehdr.e_type == ET_REL ||
-				is_vdso_map(dso->short_name) ||
+				dso__is_vdso(dso) ||
 				elf_section_by_name(elf, &ehdr, &shdr,
 						     ".gnu.prelink_undo",
 						     NULL) != NULL);
tools/perf/util/vdso.c +8 -3
index 946d927..a9300f8 100644
@@ -33,7 +33,7 @@ static struct vdso_info *vdso_info__new(void)
 	static const struct vdso_info vdso_info_init = {
 		.vdso    = {
 			.temp_file_name = VDSO__TEMP_FILE_NAME,
-			.dso_name = VDSO__MAP_NAME,
+			.dso_name = DSO__NAME_VDSO,
 		},
 	};
 
@@ -147,7 +147,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)
 	if (!vdso_info)
 		return NULL;
 
-	dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
+	dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
 	if (!dso) {
 		char *file;
 
@@ -155,8 +155,13 @@ struct dso *vdso__dso_findnew(struct machine *machine)
 		if (!file)
 			return NULL;
 
-		dso = vdso__new(machine, VDSO__MAP_NAME, file);
+		dso = vdso__new(machine, DSO__NAME_VDSO, file);
 	}
 
 	return dso;
 }
+
+bool dso__is_vdso(struct dso *dso)
+{
+	return !strcmp(dso->short_name, DSO__NAME_VDSO);
+}
tools/perf/util/vdso.h +6 -0
index 7cf1576..be3eb43 100644
@@ -7,11 +7,17 @@
 
 #define VDSO__MAP_NAME "[vdso]"
 
+#define DSO__NAME_VDSO "[vdso]"
+
 static inline bool is_vdso_map(const char *filename)
 {
 	return !strcmp(filename, VDSO__MAP_NAME);
 }
 
+struct dso;
+
+bool dso__is_vdso(struct dso *dso);
+
 struct machine;
 
 struct dso *vdso__dso_findnew(struct machine *machine);
Signature · 1 line
1.8.3.2
#93 lore raw

[tip:perf/core] perf tools: Separate the VDSO map name from the VDSO dso name

perf tools: Separate the VDSO map name from the VDSO dso name
Commit-ID:  51682dc744c3db89e515ac47a4c1f7003fd81d20
Gitweb:     http://git.kernel.org/tip/51682dc744c3db89e515ac47a4c1f7003fd81d20
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:57 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 17:36:32 -0300

perf tools: Separate the VDSO map name from the VDSO dso name

This is in preparation for supporting 32-bit compatibility VDSOs.

---
 tools/perf/util/header.c     | 10 +++++-----
 tools/perf/util/symbol-elf.c |  2 +-
 tools/perf/util/vdso.c       | 11 ++++++++---
 tools/perf/util/vdso.h       |  6 ++++++
 4 files changed, 20 insertions(+), 9 deletions(-)
tools/perf/util/header.c +5 -5
index a588a3e..158c787 100644
@@ -256,9 +256,9 @@ static int __dsos__write_buildid_table(struct list_head *head,
 		if (!pos->hit)
 			continue;
 
-		if (is_vdso_map(pos->short_name)) {
-			name = (char *) VDSO__MAP_NAME;
-			name_len = sizeof(VDSO__MAP_NAME) + 1;
+		if (dso__is_vdso(pos)) {
+			name = pos->short_name;
+			name_len = pos->short_name_len + 1;
 		} else if (dso__is_kcore(pos)) {
 			machine__mmap_name(machine, nm, sizeof(nm));
 			name = nm;
@@ -339,7 +339,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
 
 	len = scnprintf(filename, size, "%s%s%s",
 		       debugdir, slash ? "/" : "",
-		       is_vdso ? VDSO__MAP_NAME : realname);
+		       is_vdso ? DSO__NAME_VDSO : realname);
 	if (mkdir_p(filename, 0755))
 		goto out_free;
 
@@ -427,7 +427,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
 			       const char *debugdir)
 {
 	bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
-	bool is_vdso = is_vdso_map(dso->short_name);
+	bool is_vdso = dso__is_vdso(dso);
 	const char *name = dso->long_name;
 	char nm[PATH_MAX];
 
tools/perf/util/symbol-elf.c +1 -1
index cef8f42..61b9cd4 100644
@@ -622,7 +622,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 		GElf_Shdr shdr;
 		ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
 				ehdr.e_type == ET_REL ||
-				is_vdso_map(dso->short_name) ||
+				dso__is_vdso(dso) ||
 				elf_section_by_name(elf, &ehdr, &shdr,
 						     ".gnu.prelink_undo",
 						     NULL) != NULL);
tools/perf/util/vdso.c +8 -3
index 946d927..a9300f8 100644
@@ -33,7 +33,7 @@ static struct vdso_info *vdso_info__new(void)
 	static const struct vdso_info vdso_info_init = {
 		.vdso    = {
 			.temp_file_name = VDSO__TEMP_FILE_NAME,
-			.dso_name = VDSO__MAP_NAME,
+			.dso_name = DSO__NAME_VDSO,
 		},
 	};
 
@@ -147,7 +147,7 @@ struct dso *vdso__dso_findnew(struct machine *machine)
 	if (!vdso_info)
 		return NULL;
 
-	dso = dsos__find(&machine->user_dsos, VDSO__MAP_NAME, true);
+	dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
 	if (!dso) {
 		char *file;
 
@@ -155,8 +155,13 @@ struct dso *vdso__dso_findnew(struct machine *machine)
 		if (!file)
 			return NULL;
 
-		dso = vdso__new(machine, VDSO__MAP_NAME, file);
+		dso = vdso__new(machine, DSO__NAME_VDSO, file);
 	}
 
 	return dso;
 }
+
+bool dso__is_vdso(struct dso *dso)
+{
+	return !strcmp(dso->short_name, DSO__NAME_VDSO);
+}
tools/perf/util/vdso.h +6 -0
index 7cf1576..be3eb43 100644
@@ -7,11 +7,17 @@
 
 #define VDSO__MAP_NAME "[vdso]"
 
+#define DSO__NAME_VDSO "[vdso]"
+
 static inline bool is_vdso_map(const char *filename)
 {
 	return !strcmp(filename, VDSO__MAP_NAME);
 }
 
+struct dso;
+
+bool dso__is_vdso(struct dso *dso);
+
 struct machine;
 
 struct dso *vdso__dso_findnew(struct machine *machine);
author reviewer
#94 lore raw

PATCH 49/52 perf tools: Build programs to copy 32-bit compatibility VDSOs

In reply to Adrian Hunter

perf tools copy VDSO out of memory. However, on 64-bit machines there may be 32-bit compatibility VDOs also. To copy those requires separate 32-bit executables. This patch adds to the build additional programs perf-read-vdso32 and perf-read-vdsox32 for 32-bit and x32 respectively.

---
 tools/perf/Makefile.perf        | 37 +++++++++++++++++++++++---
 tools/perf/config/Makefile      | 21 +++++++++++++++
 tools/perf/config/Makefile.arch |  8 ++++++
 tools/perf/perf-read-vdso.c     | 59 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 121 insertions(+), 4 deletions(-)
 create mode 100644 tools/perf/perf-read-vdso.c
tools/perf/Makefile.perf +33 -4
index 9b1f05d..2cd3316 100644
@@ -60,6 +60,12 @@ include config/utilities.mak
 #
 # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
 # for dwarf backtrace post unwind.
+#
+# Define NO_PERF_READ_VDSO32 if you do not want to build perf-read-vdso32
+# for reading the 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
+# for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
 
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -171,11 +177,16 @@ $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
 
-#
-# Single 'perf' binary right now:
-#
 PROGRAMS += $(OUTPUT)perf
 
+ifndef NO_PERF_READ_VDSO32
+PROGRAMS += $(OUTPUT)perf-read-vdso32
+endif
+
+ifndef NO_PERF_READ_VDSOX32
+PROGRAMS += $(OUTPUT)perf-read-vdsox32
+endif
+
 # what 'all' will build and 'install' will install, in perfexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
 
@@ -732,6 +743,16 @@ $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Uti
 $(OUTPUT)perf-%: %.o $(PERFLIBS)
 	$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
 
+ifndef NO_PERF_READ_VDSO32
+$(OUTPUT)perf-read-vdso32: perf-read-vdso.c
+	$(QUIET_CC)$(CC) -m32 -Wall -Werror -o $@ perf-read-vdso.c
+endif
+
+ifndef NO_PERF_READ_VDSOX32
+$(OUTPUT)perf-read-vdsox32: perf-read-vdso.c
+	$(QUIET_CC)$(CC) -mx32 -Wall -Werror -o $@ perf-read-vdso.c
+endif
+
 $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
 $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
 
@@ -876,6 +897,14 @@ install-bin: all install-gtk
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \
 		$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \
 		$(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace'
+ifndef NO_PERF_READ_VDSO32
+	$(call QUIET_INSTALL, perf-read-vdso32) \
+		$(INSTALL) $(OUTPUT)perf-read-vdso32 '$(DESTDIR_SQ)$(bindir_SQ)';
+endif
+ifndef NO_PERF_READ_VDSOX32
+	$(call QUIET_INSTALL, perf-read-vdsox32) \
+		$(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)';
+endif
 	$(call QUIET_INSTALL, libexec) \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 	$(call QUIET_INSTALL, perf-archive) \
@@ -928,7 +957,7 @@ config-clean:
 
 clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
 	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
-	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
+	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
 	$(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
 	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
 	$(python-clean)
tools/perf/config/Makefile +21 -0
index 1f67aa0..45ab040 100644
@@ -604,6 +604,27 @@ ifdef HAVE_KVM_STAT_SUPPORT
     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
 endif
 
+ifeq (${IS_64_BIT}, 1)
+  ifndef NO_PERF_READ_VDSO32
+    CAN_DO := $(shell echo "main() {}" | ${CC} -m32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0)
+    ifneq (${CAN_DO}, 1)
+      NO_PERF_READ_VDSO32 := 1
+    endif
+  endif
+  ifneq (${IS_X86_64}, 1)
+    NO_PERF_READ_VDSOX32 := 1
+  endif
+  ifndef NO_PERF_READ_VDSOX32
+    CAN_DO := $(shell echo 'main() {}' | ${CC} -mx32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0)
+    ifneq (${CAN_DO}, 1)
+      NO_PERF_READ_VDSOX32 := 1
+    endif
+  endif
+else
+  NO_PERF_READ_VDSO32 := 1
+  NO_PERF_READ_VDSOX32 := 1
+endif
+
 # Among the variables below, these:
 #   perfexecdir
 #   template_dir
tools/perf/config/Makefile.arch +8 -0
index 4b06719..851cd01 100644
@@ -21,3 +21,11 @@ ifeq ($(ARCH),x86_64)
     RAW_ARCH := x86_64
   endif
 endif
+
+ifeq (${IS_X86_64}, 1)
+  IS_64_BIT := 1
+else ifeq ($(ARCH),x86)
+  IS_64_BIT := 0
+else
+  IS_64_BIT := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
+endif
tools/perf/perf-read-vdso.c new file +59 -0

59 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#95 lore raw

Re: [PATCH 49/52] perf tools: Build programs to copy 32-bit compatibility VDSOs

On Tue, Jul 22, 2014 at 04:17:58PM +0300, Adrian Hunter wrote:

SNIP

Quoted 13 lines

index 1f67aa0..45ab040 100644

tools/perf/config/Makefile +6 -0
@@ -604,6 +604,27 @@ ifdef HAVE_KVM_STAT_SUPPORT
     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
 endif
 
+ifeq (${IS_64_BIT}, 1)
+  ifndef NO_PERF_READ_VDSO32
+    CAN_DO := $(shell echo "main() {}" | ${CC} -m32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0)
+    ifneq (${CAN_DO}, 1)
+      NO_PERF_READ_VDSO32 := 1
+    endif

tools/perf/config/Makefile ifdef HAVE_KVM_STAT_SUPPORT · line 622

Quoted 10 lines
tools/perf/config/Makefile +10 -0
+  endif
+  ifneq (${IS_X86_64}, 1)
+    NO_PERF_READ_VDSOX32 := 1
+  endif
+  ifndef NO_PERF_READ_VDSOX32
+    CAN_DO := $(shell echo 'main() {}' | ${CC} -mx32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0)
+    ifneq (${CAN_DO}, 1)
+      NO_PERF_READ_VDSOX32 := 1
+    endif
+  endif

please move those check into feature config code under config/features/..

SNIP

Quoted 27 lines
tools/perf/config/Makefile +26 -0
+++ b/tools/perf/perf-read-vdso.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+
+#define VDSO__MAP_NAME "[vdso]"
+
+static int find_vdso_map(void **start, void **end)
+{
+	FILE *maps;
+	char line[128];
+	int found = 0;
+
+	maps = fopen("/proc/self/maps", "r");
+	if (!maps) {
+		fprintf(stderr, "vdso: cannot open maps\n");
+		return -1;
+	}
+
+	while (!found && fgets(line, sizeof(line), maps)) {
+		int m = -1;
+
+		/* We care only about private r-x mappings. */
+		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
+				start, end, &m))
+			continue;
+		if (m < 0)

tools/perf/config/Makefile line 35

Quoted 10 lines
tools/perf/config/Makefile +10 -0
+			continue;
+
+		if (!strncmp(&line[m], VDSO__MAP_NAME,
+			     sizeof(VDSO__MAP_NAME) - 1))
+			found = 1;
+	}
+
+	fclose(maps);
+	return !found;
+}

hum, any easy way to use/share find_vdso_map from vdso.c? I guess this way is more straighforward and clear.. it's probably not worthy for function this simple

jirka

author reviewer
#96 lore raw

Re: [PATCH 49/52] perf tools: Build programs to copy 32-bit compatibility VDSOs

Quoted 21 lines · Jiri Olsa

On Tue, Jul 22, 2014 at 04:17:58PM +0300, Adrian Hunter wrote:

SNIP

Quoted 17 lines

index 1f67aa0..45ab040 100644

tools/perf/config/Makefile +10 -0
@@ -604,6 +604,27 @@ ifdef HAVE_KVM_STAT_SUPPORT
     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
 endif
 
+ifeq (${IS_64_BIT}, 1)
+  ifndef NO_PERF_READ_VDSO32
+    CAN_DO := $(shell echo "main() {}" | ${CC} -m32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0)
+    ifneq (${CAN_DO}, 1)
+      NO_PERF_READ_VDSO32 := 1
+    endif
+  endif
+  ifneq (${IS_X86_64}, 1)
+    NO_PERF_READ_VDSOX32 := 1
+  endif
Quoted 8 lines

tools/perf/config/Makefile ifdef HAVE_KVM_STAT_SUPPORT · line 622

Quoted 6 lines
tools/perf/config/Makefile +6 -0
+  ifndef NO_PERF_READ_VDSOX32
+    CAN_DO := $(shell echo 'main() {}' | ${CC} -mx32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0)
+    ifneq (${CAN_DO}, 1)
+      NO_PERF_READ_VDSOX32 := 1
+    endif
+  endif

please move those check into feature config code under config/features/..

I will look at doing that.

Quoted 36 lines

SNIP

Quoted 33 lines

+++ b/tools/perf/perf-read-vdso.c

tools/perf/config/Makefile +31 -0
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+
+#define VDSO__MAP_NAME "[vdso]"
+
+static int find_vdso_map(void **start, void **end)
+{
+	FILE *maps;
+	char line[128];
+	int found = 0;
+
+	maps = fopen("/proc/self/maps", "r");
+	if (!maps) {
+		fprintf(stderr, "vdso: cannot open maps\n");
+		return -1;
+	}
+
+	while (!found && fgets(line, sizeof(line), maps)) {
+		int m = -1;
+
+		/* We care only about private r-x mappings. */
+		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
+				start, end, &m))
+			continue;
+		if (m < 0)
+			continue;
+
+		if (!strncmp(&line[m], VDSO__MAP_NAME,
+			     sizeof(VDSO__MAP_NAME) - 1))
+			found = 1;
+	}
Quoted 8 lines

tools/perf/config/Makefile line 35

Quoted 4 lines
tools/perf/config/Makefile +4 -0
+
+	fclose(maps);
+	return !found;
+}

hum, any easy way to use/share find_vdso_map from vdso.c? I guess this way is more straighforward and clear.. it's probably not worthy for function this simple

Would have to create another source file and include it. I am not sure it is worth it. Maybe Arnaldo can decide?

#97 lore raw

Re: [PATCH 49/52] perf tools: Build programs to copy 32-bit compatibility VDSOs

Em Wed, Jul 23, 2014 at 04:55:03PM +0300, Adrian Hunter escreveu:

Quoted 31 lines · Jiri Olsa
Quoted 21 lines · Adrian Hunter

SNIP

Quoted 17 lines

index 1f67aa0..45ab040 100644

tools/perf/config/Makefile +10 -0
@@ -604,6 +604,27 @@ ifdef HAVE_KVM_STAT_SUPPORT
     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
 endif
 
+ifeq (${IS_64_BIT}, 1)
+  ifndef NO_PERF_READ_VDSO32
+    CAN_DO := $(shell echo "main() {}" | ${CC} -m32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0)
+    ifneq (${CAN_DO}, 1)
+      NO_PERF_READ_VDSO32 := 1
+    endif
+  endif
+  ifneq (${IS_X86_64}, 1)
+    NO_PERF_READ_VDSOX32 := 1
+  endif
Quoted 8 lines

tools/perf/config/Makefile ifdef HAVE_KVM_STAT_SUPPORT · line 622

Quoted 6 lines
tools/perf/config/Makefile +6 -0
+  ifndef NO_PERF_READ_VDSOX32
+    CAN_DO := $(shell echo 'main() {}' | ${CC} -mx32 -x c - >/dev/null 2>/dev/null && echo 1 || echo 0)
+    ifneq (${CAN_DO}, 1)
+      NO_PERF_READ_VDSOX32 := 1
+    endif
+  endif

please move those check into feature config code under config/features/..

Quoted 1 line

I will look at doing that.

Ok, probably this can be done in a follow up patch, Jiri?

Quoted 43 lines
Quoted 34 lines

SNIP

Quoted 33 lines

+++ b/tools/perf/perf-read-vdso.c

tools/perf/config/Makefile +31 -0
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+
+#define VDSO__MAP_NAME "[vdso]"
+
+static int find_vdso_map(void **start, void **end)
+{
+	FILE *maps;
+	char line[128];
+	int found = 0;
+
+	maps = fopen("/proc/self/maps", "r");
+	if (!maps) {
+		fprintf(stderr, "vdso: cannot open maps\n");
+		return -1;
+	}
+
+	while (!found && fgets(line, sizeof(line), maps)) {
+		int m = -1;
+
+		/* We care only about private r-x mappings. */
+		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
+				start, end, &m))
+			continue;
+		if (m < 0)
+			continue;
+
+		if (!strncmp(&line[m], VDSO__MAP_NAME,
+			     sizeof(VDSO__MAP_NAME) - 1))
+			found = 1;
+	}
Quoted 8 lines

tools/perf/config/Makefile line 35

Quoted 4 lines
tools/perf/config/Makefile +4 -0
+
+	fclose(maps);
+	return !found;
+}

hum, any easy way to use/share find_vdso_map from vdso.c? I guess this way is more straighforward and clear.. it's probably not worthy for function this simple

Quoted 2 lines

Would have to create another source file and include it. I am not sure it is worth it. Maybe Arnaldo can decide?

I think it is, either do direct sourcing with #include or add it to a linking list for the binaries that use it.

- Arnaldo

author reviewer
#98 lore raw

PATCH 1/1 perf tools: Build programs to copy 32-bit compatibility VDSOs

perf tools copy VDSO out of memory. However, on 64-bit machines there may be 32-bit compatibility VDOs also. To copy those requires separate 32-bit executables. This patch adds to the build additional programs perf-read-vdso32 and perf-read-vdsox32 for 32-bit and x32 respectively.

---

V2:
Move -m32/-mx32 checks under config/features/

Put duplicated find_vdso_map() function into a separate source file and #include it

Support static build of perf-read-vdso32 and perf-read-vdsox32

 tools/perf/Makefile.perf                        | 38 ++++++++++++++++++++++---
 tools/perf/config/Makefile                      | 25 +++++++++++++++-
 tools/perf/config/Makefile.arch                 |  8 ++++++
 tools/perf/config/feature-checks/Makefile       | 10 ++++++-
 tools/perf/config/feature-checks/test-compile.c |  4 +++
 tools/perf/perf-read-vdso.c                     | 34 ++++++++++++++++++++++
 tools/perf/util/find-vdso-map.c                 | 30 +++++++++++++++++++
 tools/perf/util/vdso.c                          | 37 ++++--------------------
 8 files changed, 149 insertions(+), 37 deletions(-)
 create mode 100644 tools/perf/config/feature-checks/test-compile.c
 create mode 100644 tools/perf/perf-read-vdso.c
 create mode 100644 tools/perf/util/find-vdso-map.c
tools/perf/Makefile.perf +34 -4
index 9b1f05d..cd31be6 100644
@@ -60,6 +60,12 @@ include config/utilities.mak
 #
 # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
 # for dwarf backtrace post unwind.
+#
+# Define NO_PERF_READ_VDSO32 if you do not want to build perf-read-vdso32
+# for reading the 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
+# for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
 
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -171,11 +177,16 @@ $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
 
-#
-# Single 'perf' binary right now:
-#
 PROGRAMS += $(OUTPUT)perf
 
+ifndef NO_PERF_READ_VDSO32
+PROGRAMS += $(OUTPUT)perf-read-vdso32
+endif
+
+ifndef NO_PERF_READ_VDSOX32
+PROGRAMS += $(OUTPUT)perf-read-vdsox32
+endif
+
 # what 'all' will build and 'install' will install, in perfexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
 
@@ -305,6 +316,7 @@ LIB_H += util/data.h
 LIB_H += util/kvm-stat.h
 LIB_H += util/thread-stack.h
 LIB_H += util/db-export.h
+LIB_H += util/find-vdso-map.c
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -732,6 +744,16 @@ $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Uti
 $(OUTPUT)perf-%: %.o $(PERFLIBS)
 	$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
 
+ifndef NO_PERF_READ_VDSO32
+$(OUTPUT)perf-read-vdso32: perf-read-vdso.c util/find-vdso-map.c
+	$(QUIET_CC)$(CC) -m32 $(findstring -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c
+endif
+
+ifndef NO_PERF_READ_VDSOX32
+$(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c
+	$(QUIET_CC)$(CC) -mx32 $(findstring -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c
+endif
+
 $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
 $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
 
@@ -876,6 +898,14 @@ install-bin: all install-gtk
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \
 		$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \
 		$(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace'
+ifndef NO_PERF_READ_VDSO32
+	$(call QUIET_INSTALL, perf-read-vdso32) \
+		$(INSTALL) $(OUTPUT)perf-read-vdso32 '$(DESTDIR_SQ)$(bindir_SQ)';
+endif
+ifndef NO_PERF_READ_VDSOX32
+	$(call QUIET_INSTALL, perf-read-vdsox32) \
+		$(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)';
+endif
 	$(call QUIET_INSTALL, libexec) \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 	$(call QUIET_INSTALL, perf-archive) \
@@ -928,7 +958,7 @@ config-clean:
 
 clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
 	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
-	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
+	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
 	$(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
 	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
 	$(python-clean)
tools/perf/config/Makefile +24 -1
index 1f67aa0..81c44cb 100644
@@ -211,7 +211,9 @@ VF_FEATURE_TESTS =			\
 	bionic				\
 	liberty				\
 	liberty-z			\
-	cplus-demangle
+	cplus-demangle			\
+	compile-32			\
+	compile-x32
 
 # Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
 # If in the future we need per-feature checks/flags for features not
@@ -604,6 +606,27 @@ ifdef HAVE_KVM_STAT_SUPPORT
     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
 endif
 
+ifeq (${IS_64_BIT}, 1)
+  ifndef NO_PERF_READ_VDSO32
+    $(call feature_check,compile-32)
+    ifneq ($(feature-compile-32), 1)
+      NO_PERF_READ_VDSO32 := 1
+    endif
+  endif
+  ifneq (${IS_X86_64}, 1)
+    NO_PERF_READ_VDSOX32 := 1
+  endif
+  ifndef NO_PERF_READ_VDSOX32
+    $(call feature_check,compile-x32)
+    ifneq ($(feature-compile-x32), 1)
+      NO_PERF_READ_VDSOX32 := 1
+    endif
+  endif
+else
+  NO_PERF_READ_VDSO32 := 1
+  NO_PERF_READ_VDSOX32 := 1
+endif
+
 # Among the variables below, these:
 #   perfexecdir
 #   template_dir
tools/perf/config/Makefile.arch +8 -0
index 4b06719..851cd01 100644
@@ -21,3 +21,11 @@ ifeq ($(ARCH),x86_64)
     RAW_ARCH := x86_64
   endif
 endif
+
+ifeq (${IS_X86_64}, 1)
+  IS_64_BIT := 1
+else ifeq ($(ARCH),x86)
+  IS_64_BIT := 0
+else
+  IS_64_BIT := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
+endif
tools/perf/config/feature-checks/Makefile +9 -1
index 6088f8d..8065dc5 100644
@@ -27,7 +27,9 @@ FILES=					\
 	test-libunwind-debug-frame.bin	\
 	test-stackprotector-all.bin	\
 	test-timerfd.bin		\
-	test-libdw-dwarf-unwind.bin
+	test-libdw-dwarf-unwind.bin	\
+	test-compile-32.bin		\
+	test-compile-x32.bin
 
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -145,6 +147,12 @@ test-libdw-dwarf-unwind.bin:
 test-sync-compare-and-swap.bin:
 	$(BUILD) -Werror
 
+test-compile-32.bin:
+	$(CC) -m32 -o $(OUTPUT)$@ test-compile.c
+
+test-compile-x32.bin:
+	$(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
+
 -include *.d
 
 ###############################
tools/perf/config/feature-checks/test-compile.c new file +4 -0
new file mode 100644
index 0000000..31dbf45
@@ -0,0 +1,4 @@
+int main(void)
+{
+	return 0;
+}
tools/perf/perf-read-vdso.c new file +34 -0
new file mode 100644
index 0000000..764e254
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <string.h>
+
+#define VDSO__MAP_NAME "[vdso]"
+
+/*
+ * Include definition of find_vdso_map() also used in util/vdso.c for
+ * building perf.
+ */
+#include "util/find-vdso-map.c"
+
+int main(void)
+{
+	void *start, *end;
+	size_t size, written;
+
+	if (find_vdso_map(&start, &end))
+		return 1;
+
+	size = end - start;
+
+	while (size) {
+		written = fwrite(start, 1, size, stdout);
+		if (!written)
+			return 1;
+		start += written;
+		size -= written;
+	}
+
+	if (fflush(stdout))
+		return 1;
+
+	return 0;
+}
tools/perf/util/find-vdso-map.c new file +30 -0
new file mode 100644
index 0000000..95ef1cf
@@ -0,0 +1,30 @@
+static int find_vdso_map(void **start, void **end)
+{
+	FILE *maps;
+	char line[128];
+	int found = 0;
+
+	maps = fopen("/proc/self/maps", "r");
+	if (!maps) {
+		fprintf(stderr, "vdso: cannot open maps\n");
+		return -1;
+	}
+
+	while (!found && fgets(line, sizeof(line), maps)) {
+		int m = -1;
+
+		/* We care only about private r-x mappings. */
+		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
+				start, end, &m))
+			continue;
+		if (m < 0)
+			continue;
+
+		if (!strncmp(&line[m], VDSO__MAP_NAME,
+			     sizeof(VDSO__MAP_NAME) - 1))
+			found = 1;
+	}
+
+	fclose(maps);
+	return !found;
+}
tools/perf/util/vdso.c +6 -31
index a9300f8..36151e6 100644
@@ -15,6 +15,12 @@
 #include "linux/string.h"
 #include "debug.h"
 
+/*
+ * Include definition of find_vdso_map() also used in perf-read-vdso.c for
+ * building perf-read-vdso32 and perf-read-vdsox32.
+ */
+#include "find-vdso-map.c"
+
 #define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
 
 struct vdso_file {
@@ -40,37 +46,6 @@ static struct vdso_info *vdso_info__new(void)
 	return memdup(&vdso_info_init, sizeof(vdso_info_init));
 }
 
-static int find_vdso_map(void **start, void **end)
-{
-	FILE *maps;
-	char line[128];
-	int found = 0;
-
-	maps = fopen("/proc/self/maps", "r");
-	if (!maps) {
-		pr_err("vdso: cannot open maps\n");
-		return -1;
-	}
-
-	while (!found && fgets(line, sizeof(line), maps)) {
-		int m = -1;
-
-		/* We care only about private r-x mappings. */
-		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
-				start, end, &m))
-			continue;
-		if (m < 0)
-			continue;
-
-		if (!strncmp(&line[m], VDSO__MAP_NAME,
-			     sizeof(VDSO__MAP_NAME) - 1))
-			found = 1;
-	}
-
-	fclose(maps);
-	return !found;
-}
-
 static char *get_file(struct vdso_file *vdso_file)
 {
 	char *vdso = NULL;
Signature · 1 line
1.8.3.2
#99 lore raw

Re: [PATCH] perf tools: Build programs to copy 32-bit compatibility VDSOs

Em Thu, Jul 24, 2014 at 01:05:54PM +0300, Adrian Hunter escreveu:

Quoted 10 lines

perf tools copy VDSO out of memory. However, on 64-bit machines there may be 32-bit compatibility VDOs also. To copy those requires separate 32-bit executables. This patch adds to the build additional programs perf-read-vdso32 and perf-read-vdsox32 for 32-bit and x32 respectively.

---

Quoted 8 lines

V2:
Move -m32/-mx32 checks under config/features/

Put duplicated find_vdso_map() function into a separate source file and #include it

Support static build of perf-read-vdso32 and perf-read-vdsox32

Haven't tested, but from quick look seems OK, Jiri?

- Arnaldo

Quoted 330 lines
 tools/perf/Makefile.perf                        | 38 ++++++++++++++++++++++---
 tools/perf/config/Makefile                      | 25 +++++++++++++++-
 tools/perf/config/Makefile.arch                 |  8 ++++++
 tools/perf/config/feature-checks/Makefile       | 10 ++++++-
 tools/perf/config/feature-checks/test-compile.c |  4 +++
 tools/perf/perf-read-vdso.c                     | 34 ++++++++++++++++++++++
 tools/perf/util/find-vdso-map.c                 | 30 +++++++++++++++++++
 tools/perf/util/vdso.c                          | 37 ++++--------------------
 8 files changed, 149 insertions(+), 37 deletions(-)
 create mode 100644 tools/perf/config/feature-checks/test-compile.c
 create mode 100644 tools/perf/perf-read-vdso.c
 create mode 100644 tools/perf/util/find-vdso-map.c
tools/perf/Makefile.perf +34 -4
index 9b1f05d..cd31be6 100644
@@ -60,6 +60,12 @@ include config/utilities.mak
 #
 # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
 # for dwarf backtrace post unwind.
+#
+# Define NO_PERF_READ_VDSO32 if you do not want to build perf-read-vdso32
+# for reading the 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
+# for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
 
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -171,11 +177,16 @@ $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
 
-#
-# Single 'perf' binary right now:
-#
 PROGRAMS += $(OUTPUT)perf
 
+ifndef NO_PERF_READ_VDSO32
+PROGRAMS += $(OUTPUT)perf-read-vdso32
+endif
+
+ifndef NO_PERF_READ_VDSOX32
+PROGRAMS += $(OUTPUT)perf-read-vdsox32
+endif
+
 # what 'all' will build and 'install' will install, in perfexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
 
@@ -305,6 +316,7 @@ LIB_H += util/data.h
 LIB_H += util/kvm-stat.h
 LIB_H += util/thread-stack.h
 LIB_H += util/db-export.h
+LIB_H += util/find-vdso-map.c
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -732,6 +744,16 @@ $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Uti
 $(OUTPUT)perf-%: %.o $(PERFLIBS)
 	$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
 
+ifndef NO_PERF_READ_VDSO32
+$(OUTPUT)perf-read-vdso32: perf-read-vdso.c util/find-vdso-map.c
+	$(QUIET_CC)$(CC) -m32 $(findstring -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c
+endif
+
+ifndef NO_PERF_READ_VDSOX32
+$(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c
+	$(QUIET_CC)$(CC) -mx32 $(findstring -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c
+endif
+
 $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
 $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
 
@@ -876,6 +898,14 @@ install-bin: all install-gtk
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \
 		$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \
 		$(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace'
+ifndef NO_PERF_READ_VDSO32
+	$(call QUIET_INSTALL, perf-read-vdso32) \
+		$(INSTALL) $(OUTPUT)perf-read-vdso32 '$(DESTDIR_SQ)$(bindir_SQ)';
+endif
+ifndef NO_PERF_READ_VDSOX32
+	$(call QUIET_INSTALL, perf-read-vdsox32) \
+		$(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)';
+endif
 	$(call QUIET_INSTALL, libexec) \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 	$(call QUIET_INSTALL, perf-archive) \
@@ -928,7 +958,7 @@ config-clean:
 
 clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
 	$(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
-	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
+	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
 	$(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
 	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
 	$(python-clean)
tools/perf/config/Makefile +24 -1
index 1f67aa0..81c44cb 100644
@@ -211,7 +211,9 @@ VF_FEATURE_TESTS =			\
 	bionic				\
 	liberty				\
 	liberty-z			\
-	cplus-demangle
+	cplus-demangle			\
+	compile-32			\
+	compile-x32
 
 # Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
 # If in the future we need per-feature checks/flags for features not
@@ -604,6 +606,27 @@ ifdef HAVE_KVM_STAT_SUPPORT
     CFLAGS += -DHAVE_KVM_STAT_SUPPORT
 endif
 
+ifeq (${IS_64_BIT}, 1)
+  ifndef NO_PERF_READ_VDSO32
+    $(call feature_check,compile-32)
+    ifneq ($(feature-compile-32), 1)
+      NO_PERF_READ_VDSO32 := 1
+    endif
+  endif
+  ifneq (${IS_X86_64}, 1)
+    NO_PERF_READ_VDSOX32 := 1
+  endif
+  ifndef NO_PERF_READ_VDSOX32
+    $(call feature_check,compile-x32)
+    ifneq ($(feature-compile-x32), 1)
+      NO_PERF_READ_VDSOX32 := 1
+    endif
+  endif
+else
+  NO_PERF_READ_VDSO32 := 1
+  NO_PERF_READ_VDSOX32 := 1
+endif
+
 # Among the variables below, these:
 #   perfexecdir
 #   template_dir
tools/perf/config/Makefile.arch +8 -0
index 4b06719..851cd01 100644
@@ -21,3 +21,11 @@ ifeq ($(ARCH),x86_64)
     RAW_ARCH := x86_64
   endif
 endif
+
+ifeq (${IS_X86_64}, 1)
+  IS_64_BIT := 1
+else ifeq ($(ARCH),x86)
+  IS_64_BIT := 0
+else
+  IS_64_BIT := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
+endif
tools/perf/config/feature-checks/Makefile +9 -1
index 6088f8d..8065dc5 100644
@@ -27,7 +27,9 @@ FILES=					\
 	test-libunwind-debug-frame.bin	\
 	test-stackprotector-all.bin	\
 	test-timerfd.bin		\
-	test-libdw-dwarf-unwind.bin
+	test-libdw-dwarf-unwind.bin	\
+	test-compile-32.bin		\
+	test-compile-x32.bin
 
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -145,6 +147,12 @@ test-libdw-dwarf-unwind.bin:
 test-sync-compare-and-swap.bin:
 	$(BUILD) -Werror
 
+test-compile-32.bin:
+	$(CC) -m32 -o $(OUTPUT)$@ test-compile.c
+
+test-compile-x32.bin:
+	$(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
+
 -include *.d
 
 ###############################
tools/perf/config/feature-checks/test-compile.c new file +4 -0
new file mode 100644
index 0000000..31dbf45
@@ -0,0 +1,4 @@
+int main(void)
+{
+	return 0;
+}
tools/perf/perf-read-vdso.c new file +34 -0
new file mode 100644
index 0000000..764e254
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <string.h>
+
+#define VDSO__MAP_NAME "[vdso]"
+
+/*
+ * Include definition of find_vdso_map() also used in util/vdso.c for
+ * building perf.
+ */
+#include "util/find-vdso-map.c"
+
+int main(void)
+{
+	void *start, *end;
+	size_t size, written;
+
+	if (find_vdso_map(&start, &end))
+		return 1;
+
+	size = end - start;
+
+	while (size) {
+		written = fwrite(start, 1, size, stdout);
+		if (!written)
+			return 1;
+		start += written;
+		size -= written;
+	}
+
+	if (fflush(stdout))
+		return 1;
+
+	return 0;
+}
tools/perf/util/find-vdso-map.c new file +30 -0
new file mode 100644
index 0000000..95ef1cf
@@ -0,0 +1,30 @@
+static int find_vdso_map(void **start, void **end)
+{
+	FILE *maps;
+	char line[128];
+	int found = 0;
+
+	maps = fopen("/proc/self/maps", "r");
+	if (!maps) {
+		fprintf(stderr, "vdso: cannot open maps\n");
+		return -1;
+	}
+
+	while (!found && fgets(line, sizeof(line), maps)) {
+		int m = -1;
+
+		/* We care only about private r-x mappings. */
+		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
+				start, end, &m))
+			continue;
+		if (m < 0)
+			continue;
+
+		if (!strncmp(&line[m], VDSO__MAP_NAME,
+			     sizeof(VDSO__MAP_NAME) - 1))
+			found = 1;
+	}
+
+	fclose(maps);
+	return !found;
+}
tools/perf/util/vdso.c +6 -31
index a9300f8..36151e6 100644
@@ -15,6 +15,12 @@
 #include "linux/string.h"
 #include "debug.h"
 
+/*
+ * Include definition of find_vdso_map() also used in perf-read-vdso.c for
+ * building perf-read-vdso32 and perf-read-vdsox32.
+ */
+#include "find-vdso-map.c"
+
 #define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
 
 struct vdso_file {
@@ -40,37 +46,6 @@ static struct vdso_info *vdso_info__new(void)
 	return memdup(&vdso_info_init, sizeof(vdso_info_init));
 }
 
-static int find_vdso_map(void **start, void **end)
-{
-	FILE *maps;
-	char line[128];
-	int found = 0;
-
-	maps = fopen("/proc/self/maps", "r");
-	if (!maps) {
-		pr_err("vdso: cannot open maps\n");
-		return -1;
-	}
-
-	while (!found && fgets(line, sizeof(line), maps)) {
-		int m = -1;
-
-		/* We care only about private r-x mappings. */
-		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
-				start, end, &m))
-			continue;
-		if (m < 0)
-			continue;
-
-		if (!strncmp(&line[m], VDSO__MAP_NAME,
-			     sizeof(VDSO__MAP_NAME) - 1))
-			found = 1;
-	}
-
-	fclose(maps);
-	return !found;
-}
-
 static char *get_file(struct vdso_file *vdso_file)
 {
 	char *vdso = NULL;
Signature · 1 line
1.8.3.2
author reviewer
#100 lore raw

PATCH 50/52 perf tools: Add dso__type()

In reply to Adrian Hunter

dso__type() determines wheather a dso is 32-bit,
x32 (32-bit with 64-bit registers) or 64-bit.
dso__type() will be used to determine the VDSO
a program maps.

---
 tools/perf/util/dso.c            | 11 +++++++++++
 tools/perf/util/dso.h            | 10 ++++++++++
 tools/perf/util/symbol-elf.c     | 33 +++++++++++++++++++++++++++++++++
 tools/perf/util/symbol-minimal.c | 21 +++++++++++++++++++++
 tools/perf/util/symbol.h         |  2 ++
 5 files changed, 77 insertions(+)
tools/perf/util/dso.c +11 -0
index e657d86..90d02c66 100644
@@ -940,3 +940,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
 
 	return ret;
 }
+
+enum dso_type dso__type(struct dso *dso, struct machine *machine)
+{
+	int fd;
+
+	fd = dso__data_fd(dso, machine);
+	if (fd < 0)
+		return DSO__TYPE_UNKNOWN;
+
+	return dso__type_fd(fd);
+}
tools/perf/util/dso.h +10 -0
index d03720b..1c72a33 100644
@@ -5,6 +5,7 @@
 #include <linux/rbtree.h>
 #include <stdbool.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 #include "map.h"
 #include "build-id.h"
 
@@ -50,6 +51,13 @@ enum dso_data_status_seen {
 	DSO_DATA_STATUS_SEEN_ITRACE,
 };
 
+enum dso_type {
+	DSO__TYPE_UNKNOWN,
+	DSO__TYPE_64BIT,
+	DSO__TYPE_32BIT,
+	DSO__TYPE_X32BIT,
+};
+
 #define DSO__SWAP(dso, type, val)			\
 ({							\
 	type ____r = val;				\
@@ -246,4 +254,6 @@ static inline bool dso__is_kcore(struct dso *dso)
 
 void dso__free_a2l(struct dso *dso);
 
+enum dso_type dso__type(struct dso *dso, struct machine *machine);
+
 #endif /* __PERF_DSO */
tools/perf/util/symbol-elf.c +33 -0
index 0387780..ec0b8ea 100644
@@ -1028,6 +1028,39 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
 	return err;
 }
 
+enum dso_type dso__type_fd(int fd)
+{
+	enum dso_type dso_type = DSO__TYPE_UNKNOWN;
+	GElf_Ehdr ehdr;
+	Elf_Kind ek;
+	Elf *elf;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		goto out;
+
+	ek = elf_kind(elf);
+	if (ek != ELF_K_ELF)
+		goto out_end;
+
+	if (gelf_getclass(elf) == ELFCLASS64) {
+		dso_type = DSO__TYPE_64BIT;
+		goto out_end;
+	}
+
+	if (gelf_getehdr(elf, &ehdr) == NULL)
+		goto out_end;
+
+	if (ehdr.e_machine == EM_X86_64)
+		dso_type = DSO__TYPE_X32BIT;
+	else
+		dso_type = DSO__TYPE_32BIT;
+out_end:
+	elf_end(elf);
+out:
+	return dso_type;
+}
+
 static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
 {
 	ssize_t r;
tools/perf/util/symbol-minimal.c +21 -0
index 101f55d..c9541fe 100644
@@ -305,6 +305,27 @@ static int fd__is_64_bit(int fd)
 	return e_ident[EI_CLASS] == ELFCLASS64;
 }
 
+enum dso_type dso__type_fd(int fd)
+{
+	Elf64_Ehdr ehdr;
+	int ret;
+
+	ret = fd__is_64_bit(fd);
+	if (ret < 0)
+		return DSO__TYPE_UNKNOWN;
+
+	if (ret)
+		return DSO__TYPE_64BIT;
+
+	if (readn(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
+		return DSO__TYPE_UNKNOWN;
+
+	if (ehdr.e_machine == EM_X86_64)
+		return DSO__TYPE_X32BIT;
+
+	return DSO__TYPE_32BIT;
+}
+
 int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
 		  struct symsrc *ss,
 		  struct symsrc *runtime_ss __maybe_unused,
tools/perf/util/symbol.h +2 -0
index 31e5400..51fb26b 100644
@@ -244,6 +244,8 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
 struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
 struct symbol *dso__next_symbol(struct symbol *sym);
 
+enum dso_type dso__type_fd(int fd);
+
 int filename__read_build_id(const char *filename, void *bf, size_t size);
 int sysfs__read_build_id(const char *filename, void *bf, size_t size);
 int modules__parse(const char *filename, void *arg,
Signature · 1 line
1.8.3.2
#101 lore raw

[tip:perf/core] perf tools: Add dso__type()

perf tools: Add dso__type()
Commit-ID:  2b5b8bb27b9ec899cfba686dabec113ea0d4cbda
Gitweb:     http://git.kernel.org/tip/2b5b8bb27b9ec899cfba686dabec113ea0d4cbda
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:17:59 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 17:36:36 -0300

perf tools: Add dso__type()

dso__type() determines wheather a dso is 32-bit, x32 (32-bit with 64-bit registers) or 64-bit.

dso__type() will be used to determine the VDSO a program maps.

---
 tools/perf/util/dso.c            | 11 +++++++++++
 tools/perf/util/dso.h            | 10 ++++++++++
 tools/perf/util/symbol-elf.c     | 33 +++++++++++++++++++++++++++++++++
 tools/perf/util/symbol-minimal.c | 21 +++++++++++++++++++++
 tools/perf/util/symbol.h         |  2 ++
 5 files changed, 77 insertions(+)
tools/perf/util/dso.c +11 -0
index e657d86..90d02c66 100644
@@ -940,3 +940,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
 
 	return ret;
 }
+
+enum dso_type dso__type(struct dso *dso, struct machine *machine)
+{
+	int fd;
+
+	fd = dso__data_fd(dso, machine);
+	if (fd < 0)
+		return DSO__TYPE_UNKNOWN;
+
+	return dso__type_fd(fd);
+}
tools/perf/util/dso.h +10 -0
index af1c256..5e463c0 100644
@@ -5,6 +5,7 @@
 #include <linux/rbtree.h>
 #include <stdbool.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 #include "map.h"
 #include "build-id.h"
 
@@ -50,6 +51,13 @@ enum dso_data_status_seen {
 	DSO_DATA_STATUS_SEEN_ITRACE,
 };
 
+enum dso_type {
+	DSO__TYPE_UNKNOWN,
+	DSO__TYPE_64BIT,
+	DSO__TYPE_32BIT,
+	DSO__TYPE_X32BIT,
+};
+
 #define DSO__SWAP(dso, type, val)			\
 ({							\
 	type ____r = val;				\
@@ -245,4 +253,6 @@ static inline bool dso__is_kcore(struct dso *dso)
 
 void dso__free_a2l(struct dso *dso);
 
+enum dso_type dso__type(struct dso *dso, struct machine *machine);
+
 #endif /* __PERF_DSO */
tools/perf/util/symbol-elf.c +33 -0
index 61b9cd4..d753499 100644
@@ -1028,6 +1028,39 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
 	return err;
 }
 
+enum dso_type dso__type_fd(int fd)
+{
+	enum dso_type dso_type = DSO__TYPE_UNKNOWN;
+	GElf_Ehdr ehdr;
+	Elf_Kind ek;
+	Elf *elf;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		goto out;
+
+	ek = elf_kind(elf);
+	if (ek != ELF_K_ELF)
+		goto out_end;
+
+	if (gelf_getclass(elf) == ELFCLASS64) {
+		dso_type = DSO__TYPE_64BIT;
+		goto out_end;
+	}
+
+	if (gelf_getehdr(elf, &ehdr) == NULL)
+		goto out_end;
+
+	if (ehdr.e_machine == EM_X86_64)
+		dso_type = DSO__TYPE_X32BIT;
+	else
+		dso_type = DSO__TYPE_32BIT;
+out_end:
+	elf_end(elf);
+out:
+	return dso_type;
+}
+
 static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
 {
 	ssize_t r;
tools/perf/util/symbol-minimal.c +21 -0
index 101f55d..c9541fe 100644
@@ -305,6 +305,27 @@ static int fd__is_64_bit(int fd)
 	return e_ident[EI_CLASS] == ELFCLASS64;
 }
 
+enum dso_type dso__type_fd(int fd)
+{
+	Elf64_Ehdr ehdr;
+	int ret;
+
+	ret = fd__is_64_bit(fd);
+	if (ret < 0)
+		return DSO__TYPE_UNKNOWN;
+
+	if (ret)
+		return DSO__TYPE_64BIT;
+
+	if (readn(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
+		return DSO__TYPE_UNKNOWN;
+
+	if (ehdr.e_machine == EM_X86_64)
+		return DSO__TYPE_X32BIT;
+
+	return DSO__TYPE_32BIT;
+}
+
 int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
 		  struct symsrc *ss,
 		  struct symsrc *runtime_ss __maybe_unused,
tools/perf/util/symbol.h +2 -0
index ee2d3cc..e7295e9 100644
@@ -243,6 +243,8 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
 struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
 struct symbol *dso__next_symbol(struct symbol *sym);
 
+enum dso_type dso__type_fd(int fd);
+
 int filename__read_build_id(const char *filename, void *bf, size_t size);
 int sysfs__read_build_id(const char *filename, void *bf, size_t size);
 int modules__parse(const char *filename, void *arg,
author reviewer
#102 lore raw

PATCH 51/52 perf tools: Add thread parameter to vdso__dso_findnew()

In reply to Adrian Hunter

The thread will be needed to determine the VDSO
type.

---
 tools/perf/util/machine.c | 4 ++--
 tools/perf/util/map.c     | 4 ++--
 tools/perf/util/map.h     | 3 ++-
 tools/perf/util/vdso.c    | 3 ++-
 tools/perf/util/vdso.h    | 3 ++-
 5 files changed, 10 insertions(+), 7 deletions(-)
tools/perf/util/machine.c +2 -2
index 9b9fd26..a431bc9 100644
@@ -1133,7 +1133,7 @@ int machine__process_mmap2_event(struct machine *machine,
 			event->mmap2.ino_generation,
 			event->mmap2.prot,
 			event->mmap2.flags,
-			event->mmap2.filename, type);
+			event->mmap2.filename, type, thread);
 
 	if (map == NULL)
 		goto out_problem;
@@ -1180,7 +1180,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
 			event->mmap.len, event->mmap.pgoff,
 			event->mmap.pid, 0, 0, 0, 0, 0, 0,
 			event->mmap.filename,
-			type);
+			type, thread);
 
 	if (map == NULL)
 		goto out_problem;
tools/perf/util/map.c +2 -2
index dffc8dc..31b8905 100644
@@ -141,7 +141,7 @@ void map__init(struct map *map, enum map_type type,
 struct map *map__new(struct machine *machine, u64 start, u64 len,
 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
 		     u64 ino_gen, u32 prot, u32 flags, char *filename,
-		     enum map_type type)
+		     enum map_type type, struct thread *thread)
 {
 	struct map *map = malloc(sizeof(*map));
 
@@ -174,7 +174,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
 
 		if (vdso) {
 			pgoff = 0;
-			dso = vdso__dso_findnew(machine);
+			dso = vdso__dso_findnew(machine, thread);
 		} else
 			dso = __dsos__findnew(&machine->user_dsos, filename);
 
tools/perf/util/map.h +2 -1
index a95e677..2f83954 100644
@@ -104,6 +104,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip);
 u64 map__objdump_2mem(struct map *map, u64 ip);
 
 struct symbol;
+struct thread;
 
 /* map__for_each_symbol - iterate over the symbols in the given map
  *
@@ -122,7 +123,7 @@ void map__init(struct map *map, enum map_type type,
 struct map *map__new(struct machine *machine, u64 start, u64 len,
 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
 		     u64 ino_gen, u32 prot, u32 flags,
-		     char *filename, enum map_type type);
+		     char *filename, enum map_type type, struct thread *thread);
 struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
 void map__delete(struct map *map);
 struct map *map__clone(struct map *map);
tools/perf/util/vdso.c +2 -1
index a9300f8..adca693 100644
@@ -135,7 +135,8 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,
 	return dso;
 }
 
-struct dso *vdso__dso_findnew(struct machine *machine)
+struct dso *vdso__dso_findnew(struct machine *machine,
+			      struct thread *thread __maybe_unused)
 {
 	struct vdso_info *vdso_info;
 	struct dso *dso;
tools/perf/util/vdso.h +2 -1
index be3eb43..af9d692 100644
@@ -19,8 +19,9 @@ struct dso;
 bool dso__is_vdso(struct dso *dso);
 
 struct machine;
+struct thread;
 
-struct dso *vdso__dso_findnew(struct machine *machine);
+struct dso *vdso__dso_findnew(struct machine *machine, struct thread *thread);
 void vdso__exit(struct machine *machine);
 
 #endif /* __PERF_VDSO__ */
Signature · 1 line
1.8.3.2
#103 lore raw

[tip:perf/core] perf tools: Add thread parameter to vdso__dso_findnew()

perf tools: Add thread parameter to vdso__dso_findnew()
Commit-ID:  5835eddab6f162b38e9a6a5447a2c3a128637956
Gitweb:     http://git.kernel.org/tip/5835eddab6f162b38e9a6a5447a2c3a128637956
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 22 Jul 2014 16:18:00 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 23 Jul 2014 17:37:26 -0300

perf tools: Add thread parameter to vdso__dso_findnew()

The thread will be needed to determine the VDSO type.

---
 tools/perf/util/machine.c | 4 ++--
 tools/perf/util/map.c     | 4 ++--
 tools/perf/util/map.h     | 3 ++-
 tools/perf/util/vdso.c    | 3 ++-
 tools/perf/util/vdso.h    | 3 ++-
 5 files changed, 10 insertions(+), 7 deletions(-)
tools/perf/util/machine.c +2 -2
index 65269b8..16bba9f 100644
@@ -1106,7 +1106,7 @@ int machine__process_mmap2_event(struct machine *machine,
 			event->mmap2.ino_generation,
 			event->mmap2.prot,
 			event->mmap2.flags,
-			event->mmap2.filename, type);
+			event->mmap2.filename, type, thread);
 
 	if (map == NULL)
 		goto out_problem;
@@ -1153,7 +1153,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
 			event->mmap.len, event->mmap.pgoff,
 			event->mmap.pid, 0, 0, 0, 0, 0, 0,
 			event->mmap.filename,
-			type);
+			type, thread);
 
 	if (map == NULL)
 		goto out_problem;
tools/perf/util/map.c +2 -2
index dffc8dc..31b8905 100644
@@ -141,7 +141,7 @@ void map__init(struct map *map, enum map_type type,
 struct map *map__new(struct machine *machine, u64 start, u64 len,
 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
 		     u64 ino_gen, u32 prot, u32 flags, char *filename,
-		     enum map_type type)
+		     enum map_type type, struct thread *thread)
 {
 	struct map *map = malloc(sizeof(*map));
 
@@ -174,7 +174,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
 
 		if (vdso) {
 			pgoff = 0;
-			dso = vdso__dso_findnew(machine);
+			dso = vdso__dso_findnew(machine, thread);
 		} else
 			dso = __dsos__findnew(&machine->user_dsos, filename);
 
tools/perf/util/map.h +2 -1
index a95e677..2f83954 100644
@@ -104,6 +104,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip);
 u64 map__objdump_2mem(struct map *map, u64 ip);
 
 struct symbol;
+struct thread;
 
 /* map__for_each_symbol - iterate over the symbols in the given map
  *
@@ -122,7 +123,7 @@ void map__init(struct map *map, enum map_type type,
 struct map *map__new(struct machine *machine, u64 start, u64 len,
 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
 		     u64 ino_gen, u32 prot, u32 flags,
-		     char *filename, enum map_type type);
+		     char *filename, enum map_type type, struct thread *thread);
 struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
 void map__delete(struct map *map);
 struct map *map__clone(struct map *map);
tools/perf/util/vdso.c +2 -1
index a9300f8..adca693 100644
@@ -135,7 +135,8 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,
 	return dso;
 }
 
-struct dso *vdso__dso_findnew(struct machine *machine)
+struct dso *vdso__dso_findnew(struct machine *machine,
+			      struct thread *thread __maybe_unused)
 {
 	struct vdso_info *vdso_info;
 	struct dso *dso;
tools/perf/util/vdso.h +2 -1
index be3eb43..af9d692 100644
@@ -19,8 +19,9 @@ struct dso;
 bool dso__is_vdso(struct dso *dso);
 
 struct machine;
+struct thread;
 
-struct dso *vdso__dso_findnew(struct machine *machine);
+struct dso *vdso__dso_findnew(struct machine *machine, struct thread *thread);
 void vdso__exit(struct machine *machine);
 
 #endif /* __PERF_VDSO__ */
author reviewer
#104 lore raw

PATCH 52/52 perf tools: Add support for 32-bit compatibility VDSOs

In reply to Adrian Hunter

'perf record' post-processes the event stream to create a list of build-ids for object files for which sample events have been recorded. That results in those object files being recorded in the build-id cache.

In the case of VDSO, perf tools reads it from memory and copies it into a temporary file, which as decribed above, gets added to the build-id cache.

Then when the perf.data file is processed by other tools, the build-id of VDSO is listed in the perf.data file and the VDSO can be read from the build-id cache. In that case the name of the map, the short name of the DSO, and the entry in the build-id cache are all "[vdso]".

However, in the 64-bit case, there also can be 32-bit compatibility VDSOs.

A previous patch added programs "perf-read-vdso32" and "perf read-vdsox32". This patch uses those programs to read the correct VDSO for a thread and create a temporary file just as for the 64-bit VDSO. The map name and the entry in the build-id cache are still "[vdso]" but the DSO short name becomes "[vdso32]" and "[vdsox32]" respectively.

---
 tools/perf/util/vdso.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/vdso.h |   4 +-
 2 files changed, 172 insertions(+), 2 deletions(-)
tools/perf/util/vdso.c +169 -1
index adca693..b721f4c 100644
@@ -12,6 +12,7 @@
 #include "util.h"
 #include "symbol.h"
 #include "machine.h"
+#include "thread.h"
 #include "linux/string.h"
 #include "debug.h"
 
@@ -22,10 +23,15 @@ struct vdso_file {
 	bool error;
 	char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
 	const char *dso_name;
+	const char *read_prog;
 };
 
 struct vdso_info {
 	struct vdso_file vdso;
+#if BITS_PER_LONG == 64
+	struct vdso_file vdso32;
+	struct vdso_file vdsox32;
+#endif
 };
 
 static struct vdso_info *vdso_info__new(void)
@@ -35,6 +41,18 @@ static struct vdso_info *vdso_info__new(void)
 			.temp_file_name = VDSO__TEMP_FILE_NAME,
 			.dso_name = DSO__NAME_VDSO,
 		},
+#if BITS_PER_LONG == 64
+		.vdso32  = {
+			.temp_file_name = VDSO__TEMP_FILE_NAME,
+			.dso_name = DSO__NAME_VDSO32,
+			.read_prog = "perf-read-vdso32",
+		},
+		.vdsox32  = {
+			.temp_file_name = VDSO__TEMP_FILE_NAME,
+			.dso_name = DSO__NAME_VDSOX32,
+			.read_prog = "perf-read-vdsox32",
+		},
+#endif
 	};
 
 	return memdup(&vdso_info_init, sizeof(vdso_info_init));
@@ -117,6 +135,12 @@ void vdso__exit(struct machine *machine)
 
 	if (vdso_info->vdso.found)
 		unlink(vdso_info->vdso.temp_file_name);
+#if BITS_PER_LONG == 64
+	if (vdso_info->vdso32.found)
+		unlink(vdso_info->vdso.temp_file_name);
+	if (vdso_info->vdsox32.found)
+		unlink(vdso_info->vdso.temp_file_name);
+#endif
 
 	zfree(&machine->vdso_info);
 }
@@ -135,6 +159,143 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,
 	return dso;
 }
 
+#if BITS_PER_LONG == 64
+
+static enum dso_type machine__thread_dso_type(struct machine *machine,
+					      struct thread *thread)
+{
+	enum dso_type dso_type = DSO__TYPE_UNKNOWN;
+	struct map *map;
+	struct dso *dso;
+
+	map = map_groups__first(thread->mg, MAP__FUNCTION);
+	for (; map ; map = map_groups__next(map)) {
+		dso = map->dso;
+		if (!dso || dso->long_name[0] != '/')
+			continue;
+		dso_type = dso__type(dso, machine);
+		if (dso_type != DSO__TYPE_UNKNOWN)
+			break;
+	}
+
+	return dso_type;
+}
+
+static int vdso__do_copy_compat(FILE *f, int fd)
+{
+	char buf[4096];
+	size_t count;
+
+	while (1) {
+		count = fread(buf, 1, sizeof(buf), f);
+		if (ferror(f))
+			return -errno;
+		if (feof(f))
+			break;
+		if (count && writen(fd, buf, count) != (ssize_t)count)
+			return -errno;
+	}
+
+	return 0;
+}
+
+static int vdso__copy_compat(const char *prog, int fd)
+{
+	FILE *f;
+	int err;
+
+	f = popen(prog, "r");
+	if (!f)
+		return -errno;
+
+	err = vdso__do_copy_compat(f, fd);
+
+	if (pclose(f) == -1)
+		return -errno;
+
+	return err;
+}
+
+static int vdso__create_compat_file(const char *prog, char *temp_name)
+{
+	int fd, err;
+
+	fd = mkstemp(temp_name);
+	if (fd < 0)
+		return -errno;
+
+	err = vdso__copy_compat(prog, fd);
+
+	if (close(fd) == -1)
+		return -errno;
+
+	return err;
+}
+
+static const char *vdso__get_compat_file(struct vdso_file *vdso_file)
+{
+	int err;
+
+	if (vdso_file->found)
+		return vdso_file->temp_file_name;
+
+	if (vdso_file->error)
+		return NULL;
+
+	err = vdso__create_compat_file(vdso_file->read_prog,
+				       vdso_file->temp_file_name);
+	if (err) {
+		pr_err("%s failed, error %d\n", vdso_file->read_prog, err);
+		vdso_file->error = true;
+		return NULL;
+	}
+
+	vdso_file->found = true;
+
+	return vdso_file->temp_file_name;
+}
+
+static struct dso *vdso__findnew_compat(struct machine *machine,
+					struct vdso_file *vdso_file)
+{
+	const char *file_name;
+	struct dso *dso;
+
+	dso = dsos__find(&machine->user_dsos, vdso_file->dso_name, true);
+	if (dso)
+		return dso;
+
+	file_name = vdso__get_compat_file(vdso_file);
+	if (!file_name)
+		return NULL;
+
+	return vdso__new(machine, vdso_file->dso_name, file_name);
+}
+
+static int vdso__dso_findnew_compat(struct machine *machine,
+				    struct thread *thread,
+				    struct vdso_info *vdso_info,
+				    struct dso **dso)
+{
+	enum dso_type dso_type;
+
+	dso_type = machine__thread_dso_type(machine, thread);
+	switch (dso_type) {
+	case DSO__TYPE_32BIT:
+		*dso = vdso__findnew_compat(machine, &vdso_info->vdso32);
+		return 1;
+	case DSO__TYPE_X32BIT:
+		*dso = vdso__findnew_compat(machine, &vdso_info->vdsox32);
+		return 1;
+	case DSO__TYPE_UNKNOWN:
+	case DSO__TYPE_64BIT:
+	default:
+		return 0;
+	}
+}
+
+#endif
+
 struct dso *vdso__dso_findnew(struct machine *machine,
 			      struct thread *thread __maybe_unused)
 {
@@ -148,6 +309,11 @@ struct dso *vdso__dso_findnew(struct machine *machine,
 	if (!vdso_info)
 		return NULL;
 
+#if BITS_PER_LONG == 64
+	if (vdso__dso_findnew_compat(machine, thread, vdso_info, &dso))
+		return dso;
+#endif
+
 	dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
 	if (!dso) {
 		char *file;
@@ -164,5 +330,7 @@ struct dso *vdso__dso_findnew(struct machine *machine,
 
 bool dso__is_vdso(struct dso *dso)
 {
-	return !strcmp(dso->short_name, DSO__NAME_VDSO);
+	return !strcmp(dso->short_name, DSO__NAME_VDSO) ||
+	       !strcmp(dso->short_name, DSO__NAME_VDSO32) ||
+	       !strcmp(dso->short_name, DSO__NAME_VDSOX32);
 }
tools/perf/util/vdso.h +3 -1
index af9d692..d97da16 100644
@@ -7,7 +7,9 @@
 
 #define VDSO__MAP_NAME "[vdso]"
 
-#define DSO__NAME_VDSO "[vdso]"
+#define DSO__NAME_VDSO    "[vdso]"
+#define DSO__NAME_VDSO32  "[vdso32]"
+#define DSO__NAME_VDSOX32 "[vdsox32]"
 
 static inline bool is_vdso_map(const char *filename)
 {
Signature · 1 line
1.8.3.2
#105 lore raw

Re: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs

Quoted 4 lines · Adrian Hunter

'perf record' post-processes the event stream to create a list of build-ids for object files for which sample events have been recorded. That results in those object files being recorded in the build-id cache.

SNIP

Quoted 13 lines
tools/perf/util/vdso.c +6 -0
 	if (vdso_info->vdso.found)
 		unlink(vdso_info->vdso.temp_file_name);
+#if BITS_PER_LONG == 64
+	if (vdso_info->vdso32.found)
+		unlink(vdso_info->vdso.temp_file_name);
+	if (vdso_info->vdsox32.found)
+		unlink(vdso_info->vdso.temp_file_name);
+#endif
 
 	zfree(&machine->vdso_info);
 }

tools/perf/util/vdso.c static struct dso *vdso__new(struct machine *machine, const char *short_name, · line 162

Quoted 4 lines
tools/perf/util/vdso.c +1 -0
@@ -135,6 +159,143 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,
 	return dso;
 }
 
+#if BITS_PER_LONG == 64

Does this define mean all 64 archs? Do we want other than x86 in here? (all of its instances)

jirka

Quoted 20 lines
tools/perf/util/vdso.c +20 -0
+
+static enum dso_type machine__thread_dso_type(struct machine *machine,
+					      struct thread *thread)
+{
+	enum dso_type dso_type = DSO__TYPE_UNKNOWN;
+	struct map *map;
+	struct dso *dso;
+
+	map = map_groups__first(thread->mg, MAP__FUNCTION);
+	for (; map ; map = map_groups__next(map)) {
+		dso = map->dso;
+		if (!dso || dso->long_name[0] != '/')
+			continue;
+		dso_type = dso__type(dso, machine);
+		if (dso_type != DSO__TYPE_UNKNOWN)
+			break;
+	}
+
+	return dso_type;
+}

SNIP

author reviewer
#106 lore raw

Re: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs

Quoted 24 lines · Jiri Olsa
Quoted 4 lines · Adrian Hunter

'perf record' post-processes the event stream to create a list of build-ids for object files for which sample events have been recorded. That results in those object files being recorded in the build-id cache.

SNIP

Quoted 16 lines
tools/perf/util/vdso.c +6 -0
 	if (vdso_info->vdso.found)
 		unlink(vdso_info->vdso.temp_file_name);
+#if BITS_PER_LONG == 64
+	if (vdso_info->vdso32.found)
+		unlink(vdso_info->vdso.temp_file_name);
+	if (vdso_info->vdsox32.found)
+		unlink(vdso_info->vdso.temp_file_name);
+#endif
 
 	zfree(&machine->vdso_info);
 }
@@ -135,6 +159,143 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,
 	return dso;
 }
 
Quoted 4 lines

Review static struct dso *vdso__new(struct machine *machine, const char *short_name, · line 162

Quoted 1 line
(quoted diff) +1 -0
+#if BITS_PER_LONG == 64

Does this define mean all 64 archs? Do we want other than x86 in here? (all of its instances)

Any 64-bit arch can have 32-bit compatibility VDSOs. This should be OK for other arches too.

Quoted 27 lines

jirka

Quoted 20 lines
tools/perf/util/vdso.c +20 -0
+
+static enum dso_type machine__thread_dso_type(struct machine *machine,
+					      struct thread *thread)
+{
+	enum dso_type dso_type = DSO__TYPE_UNKNOWN;
+	struct map *map;
+	struct dso *dso;
+
+	map = map_groups__first(thread->mg, MAP__FUNCTION);
+	for (; map ; map = map_groups__next(map)) {
+		dso = map->dso;
+		if (!dso || dso->long_name[0] != '/')
+			continue;
+		dso_type = dso__type(dso, machine);
+		if (dso_type != DSO__TYPE_UNKNOWN)
+			break;
+	}
+
+	return dso_type;
+}

SNIP

maintainer
#107 lore raw

Re: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs

Hi Adrian,

Quoted 10 lines · Adrian Hunter
Quoted 9 lines · Jiri Olsa
Quoted 4 lines · Adrian Hunter

'perf record' post-processes the event stream to create a list of build-ids for object files for which sample events have been recorded. That results in those object files being recorded in the build-id cache.

SNIP

Quoted 1 line
Quoted 8 lines
Quoted 8 lines

tools/perf/util/vdso.c void vdso__exit(struct machine *machine) · line 143

Quoted 8 lines
tools/perf/util/vdso.c +6 -0
 	if (vdso_info->vdso.found)
 		unlink(vdso_info->vdso.temp_file_name);
+#if BITS_PER_LONG == 64
+	if (vdso_info->vdso32.found)
+		unlink(vdso_info->vdso.temp_file_name);
+	if (vdso_info->vdsox32.found)
+		unlink(vdso_info->vdso.temp_file_name);
+#endif

Looks like copy-and-paste errors. Did you mean below?

#if BITS_PER_LONG == 64
	if (vdso_info->vdso32.found)
		unlink(vdso_info->vdso32.temp_file_name);
	if (vdso_info->vdsox32.found)
		unlink(vdso_info->vdsox32.temp_file_name);

#endif

                                      ^^^

Thanks,
Namhyung

author reviewer
#108 lore raw

PATCH v2 52/52 perf tools: Add support for 32-bit compatibility VDSOs

'perf record' post-processes the event stream to create a list of build-ids for object files for which sample events have been recorded. That results in those object files being recorded in the build-id cache.

In the case of VDSO, perf tools reads it from memory and copies it into a temporary file, which as decribed above, gets added to the build-id cache.

Then when the perf.data file is processed by other tools, the build-id of VDSO is listed in the perf.data file and the VDSO can be read from the build-id cache. In that case the name of the map, the short name of the DSO, and the entry in the build-id cache are all "[vdso]".

However, in the 64-bit case, there also can be 32-bit compatibility VDSOs.

A previous patch added programs "perf-read-vdso32" and "perf read-vdsox32". This patch uses those programs to read the correct VDSO for a thread and create a temporary file just as for the 64-bit VDSO. The map name and the entry in the build-id cache are still "[vdso]" but the DSO short name becomes "[vdso32]" and "[vdsox32]" respectively.

---

V2:
Fix copy-and-paste errors spotted by Namhyung (Thank you!)

 tools/perf/util/vdso.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/vdso.h |   4 +-
 2 files changed, 172 insertions(+), 2 deletions(-)
tools/perf/util/vdso.c +169 -1
index adca693..25381cf 100644
@@ -12,6 +12,7 @@
 #include "util.h"
 #include "symbol.h"
 #include "machine.h"
+#include "thread.h"
 #include "linux/string.h"
 #include "debug.h"
 
@@ -22,10 +23,15 @@ struct vdso_file {
 	bool error;
 	char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
 	const char *dso_name;
+	const char *read_prog;
 };
 
 struct vdso_info {
 	struct vdso_file vdso;
+#if BITS_PER_LONG == 64
+	struct vdso_file vdso32;
+	struct vdso_file vdsox32;
+#endif
 };
 
 static struct vdso_info *vdso_info__new(void)
@@ -35,6 +41,18 @@ static struct vdso_info *vdso_info__new(void)
 			.temp_file_name = VDSO__TEMP_FILE_NAME,
 			.dso_name = DSO__NAME_VDSO,
 		},
+#if BITS_PER_LONG == 64
+		.vdso32  = {
+			.temp_file_name = VDSO__TEMP_FILE_NAME,
+			.dso_name = DSO__NAME_VDSO32,
+			.read_prog = "perf-read-vdso32",
+		},
+		.vdsox32  = {
+			.temp_file_name = VDSO__TEMP_FILE_NAME,
+			.dso_name = DSO__NAME_VDSOX32,
+			.read_prog = "perf-read-vdsox32",
+		},
+#endif
 	};
 
 	return memdup(&vdso_info_init, sizeof(vdso_info_init));
@@ -117,6 +135,12 @@ void vdso__exit(struct machine *machine)
 
 	if (vdso_info->vdso.found)
 		unlink(vdso_info->vdso.temp_file_name);
+#if BITS_PER_LONG == 64
+	if (vdso_info->vdso32.found)
+		unlink(vdso_info->vdso32.temp_file_name);
+	if (vdso_info->vdsox32.found)
+		unlink(vdso_info->vdsox32.temp_file_name);
+#endif
 
 	zfree(&machine->vdso_info);
 }
@@ -135,6 +159,143 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,
 	return dso;
 }
 
+#if BITS_PER_LONG == 64
+
+static enum dso_type machine__thread_dso_type(struct machine *machine,
+					      struct thread *thread)
+{
+	enum dso_type dso_type = DSO__TYPE_UNKNOWN;
+	struct map *map;
+	struct dso *dso;
+
+	map = map_groups__first(thread->mg, MAP__FUNCTION);
+	for (; map ; map = map_groups__next(map)) {
+		dso = map->dso;
+		if (!dso || dso->long_name[0] != '/')
+			continue;
+		dso_type = dso__type(dso, machine);
+		if (dso_type != DSO__TYPE_UNKNOWN)
+			break;
+	}
+
+	return dso_type;
+}
+
+static int vdso__do_copy_compat(FILE *f, int fd)
+{
+	char buf[4096];
+	size_t count;
+
+	while (1) {
+		count = fread(buf, 1, sizeof(buf), f);
+		if (ferror(f))
+			return -errno;
+		if (feof(f))
+			break;
+		if (count && writen(fd, buf, count) != (ssize_t)count)
+			return -errno;
+	}
+
+	return 0;
+}
+
+static int vdso__copy_compat(const char *prog, int fd)
+{
+	FILE *f;
+	int err;
+
+	f = popen(prog, "r");
+	if (!f)
+		return -errno;
+
+	err = vdso__do_copy_compat(f, fd);
+
+	if (pclose(f) == -1)
+		return -errno;
+
+	return err;
+}
+
+static int vdso__create_compat_file(const char *prog, char *temp_name)
+{
+	int fd, err;
+
+	fd = mkstemp(temp_name);
+	if (fd < 0)
+		return -errno;
+
+	err = vdso__copy_compat(prog, fd);
+
+	if (close(fd) == -1)
+		return -errno;
+
+	return err;
+}
+
+static const char *vdso__get_compat_file(struct vdso_file *vdso_file)
+{
+	int err;
+
+	if (vdso_file->found)
+		return vdso_file->temp_file_name;
+
+	if (vdso_file->error)
+		return NULL;
+
+	err = vdso__create_compat_file(vdso_file->read_prog,
+				       vdso_file->temp_file_name);
+	if (err) {
+		pr_err("%s failed, error %d\n", vdso_file->read_prog, err);
+		vdso_file->error = true;
+		return NULL;
+	}
+
+	vdso_file->found = true;
+
+	return vdso_file->temp_file_name;
+}
+
+static struct dso *vdso__findnew_compat(struct machine *machine,
+					struct vdso_file *vdso_file)
+{
+	const char *file_name;
+	struct dso *dso;
+
+	dso = dsos__find(&machine->user_dsos, vdso_file->dso_name, true);
+	if (dso)
+		return dso;
+
+	file_name = vdso__get_compat_file(vdso_file);
+	if (!file_name)
+		return NULL;
+
+	return vdso__new(machine, vdso_file->dso_name, file_name);
+}
+
+static int vdso__dso_findnew_compat(struct machine *machine,
+				    struct thread *thread,
+				    struct vdso_info *vdso_info,
+				    struct dso **dso)
+{
+	enum dso_type dso_type;
+
+	dso_type = machine__thread_dso_type(machine, thread);
+	switch (dso_type) {
+	case DSO__TYPE_32BIT:
+		*dso = vdso__findnew_compat(machine, &vdso_info->vdso32);
+		return 1;
+	case DSO__TYPE_X32BIT:
+		*dso = vdso__findnew_compat(machine, &vdso_info->vdsox32);
+		return 1;
+	case DSO__TYPE_UNKNOWN:
+	case DSO__TYPE_64BIT:
+	default:
+		return 0;
+	}
+}
+
+#endif
+
 struct dso *vdso__dso_findnew(struct machine *machine,
 			      struct thread *thread __maybe_unused)
 {
@@ -148,6 +309,11 @@ struct dso *vdso__dso_findnew(struct machine *machine,
 	if (!vdso_info)
 		return NULL;
 
+#if BITS_PER_LONG == 64
+	if (vdso__dso_findnew_compat(machine, thread, vdso_info, &dso))
+		return dso;
+#endif
+
 	dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
 	if (!dso) {
 		char *file;
@@ -164,5 +330,7 @@ struct dso *vdso__dso_findnew(struct machine *machine,
 
 bool dso__is_vdso(struct dso *dso)
 {
-	return !strcmp(dso->short_name, DSO__NAME_VDSO);
+	return !strcmp(dso->short_name, DSO__NAME_VDSO) ||
+	       !strcmp(dso->short_name, DSO__NAME_VDSO32) ||
+	       !strcmp(dso->short_name, DSO__NAME_VDSOX32);
 }
tools/perf/util/vdso.h +3 -1
index af9d692..d97da16 100644
@@ -7,7 +7,9 @@
 
 #define VDSO__MAP_NAME "[vdso]"
 
-#define DSO__NAME_VDSO "[vdso]"
+#define DSO__NAME_VDSO    "[vdso]"
+#define DSO__NAME_VDSO32  "[vdso32]"
+#define DSO__NAME_VDSOX32 "[vdsox32]"
 
 static inline bool is_vdso_map(const char *filename)
 {
Signature · 1 line
1.8.3.2
Acked-by on v1 52/52
#109 lore raw

Re: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs

In reply to Adrian Hunter
Quoted 9 lines · Adrian Hunter

'perf record' post-processes the event stream to create a list of build-ids for object files for which sample events have been recorded. That results in those object files being recorded in the build-id cache.

In the case of VDSO, perf tools reads it from memory and copies it into a temporary file, which as decribed above, gets added to the build-id cache.

Quoted 7 lines

Then when the perf.data file is processed by other tools, the build-id of VDSO is listed in the perf.data file and the VDSO can be read from the build-id cache. In that case the name of the map, the short name of the DSO, and the entry in the build-id cache are all "[vdso]".

heya,
I reviewed vdso changes:

perf tools: Pass machine to vdso__dso_findnew() perf tools: Group VDSO global variables into a structure perf tools: Fix the lifetime of the VDSO temporary file perf tools: Add vdso__new()
perf tools: Separate the VDSO map name from the VDSO dso name perf tools: Build programs to copy 32-bit compatibility VDSOs perf tools: Add dso__type()
perf tools: Add thread parameter to vdso__dso_findnew() perf tools: Add support for 32-bit compatibility VDSOs

apart from small comments for above patches:

Arnaldo,
I can handle those if needed, please let me know

thanks,
jirka

#110 lore raw

Re: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs

Em Wed, Jul 23, 2014 at 03:05:25PM +0200, Jiri Olsa escreveu:

Quoted 31 lines · Adrian Hunter
Quoted 9 lines

'perf record' post-processes the event stream to create a list of build-ids for object files for which sample events have been recorded. That results in those object files being recorded in the build-id cache.

In the case of VDSO, perf tools reads it from memory and copies it into a temporary file, which as decribed above, gets added to the build-id cache.

Quoted 7 lines

Then when the perf.data file is processed by other tools, the build-id of VDSO is listed in the perf.data file and the VDSO can be read from the build-id cache. In that case the name of the map, the short name of the DSO, and the entry in the build-id cache are all "[vdso]".

heya,
I reviewed vdso changes:

perf tools: Pass machine to vdso__dso_findnew() perf tools: Group VDSO global variables into a structure perf tools: Fix the lifetime of the VDSO temporary file perf tools: Add vdso__new()
perf tools: Separate the VDSO map name from the VDSO dso name perf tools: Build programs to copy 32-bit compatibility VDSOs perf tools: Add dso__type()
perf tools: Add thread parameter to vdso__dso_findnew() perf tools: Add support for 32-bit compatibility VDSOs

Quoted 6 lines

apart from small comments for above patches:

Arnaldo,
I can handle those if needed, please let me know

I can take those after I go thru them, will add your acked-by. But since you sayd "I reviewed", wouldn't it be better to s/Acked-by/Reviewed-by/g ?

- Arnaldo

#111 lore raw

Re: [PATCH 52/52] perf tools: Add support for 32-bit compatibility VDSOs

Quoted 34 lines · Arnaldo Carvalho de Melo

Em Wed, Jul 23, 2014 at 03:05:25PM +0200, Jiri Olsa escreveu:

Quoted 33 lines · Adrian Hunter
Quoted 9 lines

'perf record' post-processes the event stream to create a list of build-ids for object files for which sample events have been recorded. That results in those object files being recorded in the build-id cache.

In the case of VDSO, perf tools reads it from memory and copies it into a temporary file, which as decribed above, gets added to the build-id cache.

Quoted 7 lines

Then when the perf.data file is processed by other tools, the build-id of VDSO is listed in the perf.data file and the VDSO can be read from the build-id cache. In that case the name of the map, the short name of the DSO, and the entry in the build-id cache are all "[vdso]".

heya,
I reviewed vdso changes:

perf tools: Pass machine to vdso__dso_findnew() perf tools: Group VDSO global variables into a structure perf tools: Fix the lifetime of the VDSO temporary file perf tools: Add vdso__new()
perf tools: Separate the VDSO map name from the VDSO dso name perf tools: Build programs to copy 32-bit compatibility VDSOs perf tools: Add dso__type()
perf tools: Add thread parameter to vdso__dso_findnew() perf tools: Add support for 32-bit compatibility VDSOs

apart from small comments for above patches:

Quoted 7 lines
Quoted 4 lines

Arnaldo,
I can handle those if needed, please let me know

I can take those after I go thru them, will add your acked-by. But since you sayd "I reviewed", wouldn't it be better to s/Acked-by/Reviewed-by/g

ok, both's fine with me

jirka