Skip to contentSkip to conversation

perf tools: Preparation for call graph from Intel BTS

PATCH In review Adrian Hunter 6 participants 122 messages Jul 14, 2014 – Sep 2, 2014 perf events

lore
Share & tools
lore

Adrian Hunter

author reviewer
#0 lore raw

cover perf tools: Preparation for call graph from Intel BTS

Hi

As we discussed here:

	http://marc.info/?l=linux-kernel&m=140509286032125&w=4

here are a 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 (41):
perf tools: Fix the value used for unknown pids
perf tools: Fix map groups of threads with unknown pids perf script: Display PERF_RECORD_MISC_COMM_EXEC flag perf record: Select comm_exec flag if supported
perf tools: Identify which comms are from exec
perf tools: Add machine__thread_exec_comm()
perf tools: Fix missing kernel map load
perf tools: Fix missing label symbols
perf tools: Fix missing GNU IFUNC symbols
perf inject: Fix build id injection
perf tools: Fix appending a callchain from a previous sample perf tools: Fix leak of 'struct thread' on error path perf tools: Add machine__kernel_ip()
perf buildid-cache: Apply force option to copying kcore perf script: Improve srcline display for BTS
perf script: Do not print dangling '=>' for BTS
perf tools: Record whether a dso is 64-bit
perf tools: Record whether a dso has data
perf tools: Do not attempt to read data from kallsyms 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 tools: Add ability to iterate over a dso's symbols perf session: Flag if the event stream is entirely in memory perf evlist: Pass mmap parameters in a struct
perf tools: Add feature test for __sync_val_compare_and_swap perf tools: Add option macro OPT_CALLBACK_OPTARG
perf evlist: Add perf_evlist__set_tracking_event()
perf evsel: Add 'no_aux_samples' option
perf evsel: Add 'immediate' option
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: Allow TSC conversion on any arch
perf tools: Move rdtsc() function
perf evlist: Add perf_evlist__enable_event_idx()

 tools/perf/Makefile.perf                           |   2 +
 tools/perf/arch/x86/util/tsc.c                     |  31 ++--
 tools/perf/arch/x86/util/tsc.h                     |   3 -
 tools/perf/builtin-buildid-cache.c                 |   8 +-
 tools/perf/builtin-inject.c                        |   4 +
 tools/perf/builtin-sched.c                         |  12 +-
 tools/perf/builtin-script.c                        |  26 ++-
 tools/perf/config/Makefile                         |   6 +
 tools/perf/config/feature-checks/Makefile          |   4 +
 tools/perf/config/feature-checks/test-all.c        |   5 +
 .../feature-checks/test-sync-compare-and-swap.c    |  14 ++
 tools/perf/tests/perf-time-to-tsc.c                |  12 +-
 tools/perf/tests/pmu.c                             |   2 +-
 tools/perf/util/callchain.c                        |   2 +-
 tools/perf/util/comm.c                             |   7 +-
 tools/perf/util/comm.h                             |   6 +-
 tools/perf/util/dso.c                              |   6 +-
 tools/perf/util/dso.h                              |   2 +
 tools/perf/util/event.c                            |  17 +-
 tools/perf/util/event.h                            |  15 ++
 tools/perf/util/evlist.c                           | 184 +++++++++++++++----
 tools/perf/util/evlist.h                           |   5 +
 tools/perf/util/evsel.c                            |  45 ++++-
 tools/perf/util/evsel.h                            |   6 +
 tools/perf/util/header.c                           |  41 +++++
 tools/perf/util/header.h                           |   2 +
 tools/perf/util/machine.c                          | 127 +++++++++++++-
 tools/perf/util/machine.h                          |  26 +++
 tools/perf/util/map.c                              |  14 ++
 tools/perf/util/map.h                              |   1 +
 tools/perf/util/parse-events.c                     |  13 +-
 tools/perf/util/parse-events.y                     |  10 ++
 tools/perf/util/parse-options.h                    |   5 +
 tools/perf/util/pmu.c                              |  92 ++++++++--
 tools/perf/util/pmu.h                              |  13 +-
 tools/perf/util/record.c                           |  18 +-
 tools/perf/util/session.c                          | 194 +++++++++++++++++++--
 tools/perf/util/session.h                          |  18 ++
 tools/perf/util/symbol-elf.c                       |   8 +-
 tools/perf/util/symbol-minimal.c                   |  22 +++
 tools/perf/util/symbol.c                           |  20 ++-
 tools/perf/util/symbol.h                           |   4 +
 tools/perf/util/thread.c                           |  68 +++++++-
 tools/perf/util/thread.h                           |  12 +-
 tools/perf/util/tool.h                             |   3 +-
 tools/perf/util/tsc.c                              |  30 ++++
 tools/perf/util/tsc.h                              |  12 ++
 47 files changed, 1020 insertions(+), 157 deletions(-)
 create mode 100644 tools/perf/config/feature-checks/test-sync-compare-and-swap.c
 create mode 100644 tools/perf/util/tsc.c
 create mode 100644 tools/perf/util/tsc.h

Regards
Adrian

author reviewer
#1 lore raw

PATCH 1/41 perf tools: Fix the value used for unknown pids

The value used for unknown pids cannot be zero because that is used by the "idle" task. Use -1 instead. Also handle the unknown pid case when creating map groups.

Note that, threads with an unknown pid should not occur because fork (or synthesized) events precede the thread's existence.

---
 tools/perf/builtin-sched.c | 12 ++++++------
 tools/perf/util/machine.c  |  6 +++---
 tools/perf/util/session.c  |  5 +++--
 tools/perf/util/thread.c   |  2 +-
 4 files changed, 13 insertions(+), 12 deletions(-)
tools/perf/builtin-sched.c +6 -6
index c38d06c..b7f555a 100644
@@ -935,8 +935,8 @@ static int latency_switch_event(struct perf_sched *sched,
 		return -1;
 	}
 
-	sched_out = machine__findnew_thread(machine, 0, prev_pid);
-	sched_in = machine__findnew_thread(machine, 0, next_pid);
+	sched_out = machine__findnew_thread(machine, -1, prev_pid);
+	sched_in = machine__findnew_thread(machine, -1, next_pid);
 
 	out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
 	if (!out_events) {
@@ -979,7 +979,7 @@ static int latency_runtime_event(struct perf_sched *sched,
 {
 	const u32 pid	   = perf_evsel__intval(evsel, sample, "pid");
 	const u64 runtime  = perf_evsel__intval(evsel, sample, "runtime");
-	struct thread *thread = machine__findnew_thread(machine, 0, pid);
+	struct thread *thread = machine__findnew_thread(machine, -1, pid);
 	struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
 	u64 timestamp = sample->time;
 	int cpu = sample->cpu;
@@ -1012,7 +1012,7 @@ static int latency_wakeup_event(struct perf_sched *sched,
 	struct thread *wakee;
 	u64 timestamp = sample->time;
 
-	wakee = machine__findnew_thread(machine, 0, pid);
+	wakee = machine__findnew_thread(machine, -1, pid);
 	atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
 	if (!atoms) {
 		if (thread_atoms_insert(sched, wakee))
@@ -1072,7 +1072,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
 	if (sched->profile_cpu == -1)
 		return 0;
 
-	migrant = machine__findnew_thread(machine, 0, pid);
+	migrant = machine__findnew_thread(machine, -1, pid);
 	atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
 	if (!atoms) {
 		if (thread_atoms_insert(sched, migrant))
@@ -1290,7 +1290,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
 		return -1;
 	}
 
-	sched_in = machine__findnew_thread(machine, 0, next_pid);
+	sched_in = machine__findnew_thread(machine, -1, next_pid);
 
 	sched->curr_thread[this_cpu] = sched_in;
 
tools/perf/util/machine.c +3 -3
index e9b943a..5b80877 100644
@@ -34,7 +34,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 		return -ENOMEM;
 
 	if (pid != HOST_KERNEL_ID) {
-		struct thread *thread = machine__findnew_thread(machine, 0,
+		struct thread *thread = machine__findnew_thread(machine, -1,
 								pid);
 		char comm[64];
 
@@ -286,7 +286,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 	 * the full rbtree:
 	 */
 	if (machine->last_match && machine->last_match->tid == tid) {
-		if (pid && pid != machine->last_match->pid_)
+		if (pid != -1 && pid != machine->last_match->pid_)
 			machine->last_match->pid_ = pid;
 		return machine->last_match;
 	}
@@ -297,7 +297,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 
 		if (th->tid == tid) {
 			machine->last_match = th;
-			if (pid && pid != th->pid_)
+			if (pid != -1 && pid != th->pid_)
 				th->pid_ = pid;
 			return th;
 		}
tools/perf/util/session.c +3 -2
index 64a186e..c2f4ca9 100644
@@ -1083,13 +1083,14 @@ void perf_event_header__bswap(struct perf_event_header *hdr)
 
 struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
 {
-	return machine__findnew_thread(&session->machines.host, 0, pid);
+	return machine__findnew_thread(&session->machines.host, -1, pid);
 }
 
 static struct thread *perf_session__register_idle_thread(struct perf_session *session)
 {
-	struct thread *thread = perf_session__findnew(session, 0);
+	struct thread *thread;
 
+	thread = machine__findnew_thread(&session->machines.host, 0, 0);
 	if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
 		pr_err("problem inserting idle task.\n");
 		thread = NULL;
tools/perf/util/thread.c +1 -1
index 2fde0d5..7a32f44 100644
@@ -13,7 +13,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
 	struct thread *leader;
 	pid_t pid = thread->pid_;
 
-	if (pid == thread->tid) {
+	if (pid == thread->tid || pid == -1) {
 		thread->mg = map_groups__new();
 	} else {
 		leader = machine__findnew_thread(machine, pid, pid);
Signature · 1 line
1.8.3.2
#2 lore raw

[tip:perf/core] perf machine: Fix the value used for unknown pids

perf machine: Fix the value used for unknown pids
Commit-ID:  1fcb8768636d38cb6fdfeef83a5ee596c4bd9c56
Gitweb:     http://git.kernel.org/tip/1fcb8768636d38cb6fdfeef83a5ee596c4bd9c56
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:25 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:33 -0300

perf machine: Fix the value used for unknown pids

The value used for unknown pids cannot be zero because that is used by the "idle" task.

Use -1 instead. Also handle the unknown pid case when creating map groups.

Note that, threads with an unknown pid should not occur because fork (or synthesized) events precede the thread's existence.

---
 tools/perf/builtin-sched.c | 12 ++++++------
 tools/perf/util/machine.c  |  6 +++---
 tools/perf/util/session.c  |  5 +++--
 tools/perf/util/thread.c   |  2 +-
 4 files changed, 13 insertions(+), 12 deletions(-)
tools/perf/builtin-sched.c +6 -6
index c38d06c..b7f555a 100644
@@ -935,8 +935,8 @@ static int latency_switch_event(struct perf_sched *sched,
 		return -1;
 	}
 
-	sched_out = machine__findnew_thread(machine, 0, prev_pid);
-	sched_in = machine__findnew_thread(machine, 0, next_pid);
+	sched_out = machine__findnew_thread(machine, -1, prev_pid);
+	sched_in = machine__findnew_thread(machine, -1, next_pid);
 
 	out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
 	if (!out_events) {
@@ -979,7 +979,7 @@ static int latency_runtime_event(struct perf_sched *sched,
 {
 	const u32 pid	   = perf_evsel__intval(evsel, sample, "pid");
 	const u64 runtime  = perf_evsel__intval(evsel, sample, "runtime");
-	struct thread *thread = machine__findnew_thread(machine, 0, pid);
+	struct thread *thread = machine__findnew_thread(machine, -1, pid);
 	struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
 	u64 timestamp = sample->time;
 	int cpu = sample->cpu;
@@ -1012,7 +1012,7 @@ static int latency_wakeup_event(struct perf_sched *sched,
 	struct thread *wakee;
 	u64 timestamp = sample->time;
 
-	wakee = machine__findnew_thread(machine, 0, pid);
+	wakee = machine__findnew_thread(machine, -1, pid);
 	atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
 	if (!atoms) {
 		if (thread_atoms_insert(sched, wakee))
@@ -1072,7 +1072,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
 	if (sched->profile_cpu == -1)
 		return 0;
 
-	migrant = machine__findnew_thread(machine, 0, pid);
+	migrant = machine__findnew_thread(machine, -1, pid);
 	atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
 	if (!atoms) {
 		if (thread_atoms_insert(sched, migrant))
@@ -1290,7 +1290,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
 		return -1;
 	}
 
-	sched_in = machine__findnew_thread(machine, 0, next_pid);
+	sched_in = machine__findnew_thread(machine, -1, next_pid);
 
 	sched->curr_thread[this_cpu] = sched_in;
 
tools/perf/util/machine.c +3 -3
index e9b943a..5b80877 100644
@@ -34,7 +34,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 		return -ENOMEM;
 
 	if (pid != HOST_KERNEL_ID) {
-		struct thread *thread = machine__findnew_thread(machine, 0,
+		struct thread *thread = machine__findnew_thread(machine, -1,
 								pid);
 		char comm[64];
 
@@ -286,7 +286,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 	 * the full rbtree:
 	 */
 	if (machine->last_match && machine->last_match->tid == tid) {
-		if (pid && pid != machine->last_match->pid_)
+		if (pid != -1 && pid != machine->last_match->pid_)
 			machine->last_match->pid_ = pid;
 		return machine->last_match;
 	}
@@ -297,7 +297,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 
 		if (th->tid == tid) {
 			machine->last_match = th;
-			if (pid && pid != th->pid_)
+			if (pid != -1 && pid != th->pid_)
 				th->pid_ = pid;
 			return th;
 		}
tools/perf/util/session.c +3 -2
index 64a186e..c2f4ca9 100644
@@ -1083,13 +1083,14 @@ void perf_event_header__bswap(struct perf_event_header *hdr)
 
 struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
 {
-	return machine__findnew_thread(&session->machines.host, 0, pid);
+	return machine__findnew_thread(&session->machines.host, -1, pid);
 }
 
 static struct thread *perf_session__register_idle_thread(struct perf_session *session)
 {
-	struct thread *thread = perf_session__findnew(session, 0);
+	struct thread *thread;
 
+	thread = machine__findnew_thread(&session->machines.host, 0, 0);
 	if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
 		pr_err("problem inserting idle task.\n");
 		thread = NULL;
tools/perf/util/thread.c +1 -1
index 2fde0d5..7a32f44 100644
@@ -13,7 +13,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
 	struct thread *leader;
 	pid_t pid = thread->pid_;
 
-	if (pid == thread->tid) {
+	if (pid == thread->tid || pid == -1) {
 		thread->mg = map_groups__new();
 	} else {
 		leader = machine__findnew_thread(machine, pid, pid);
author reviewer
#3 lore raw

PATCH 2/41 perf tools: Fix map groups of threads with unknown pids

In reply to Adrian Hunter

Events like sched_switch do not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups. Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.

---
 tools/perf/util/machine.c | 22 ++++++++++++++++------
 tools/perf/util/map.c     | 14 ++++++++++++++
 tools/perf/util/map.h     |  1 +
 tools/perf/util/thread.c  | 35 +++++++++++++++++++++++++++++++++++
 tools/perf/util/thread.h  |  1 +
 5 files changed, 67 insertions(+), 6 deletions(-)
tools/perf/util/machine.c +16 -6
index 5b80877..0fa93c1 100644
@@ -272,6 +272,17 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
 	return;
 }
 
+static void machine__update_thread_pid(struct machine *machine,
+				       struct thread *th, pid_t pid)
+{
+	if (pid != th->pid_ && pid != -1 && th->pid_ == -1) {
+		th->pid_ = pid;
+		if (thread__join_map_groups(th, machine))
+			pr_err("Failed to join map groups for %d:%d\n",
+			       th->pid_, th->tid);
+	}
+}
+
 static struct thread *__machine__findnew_thread(struct machine *machine,
 						pid_t pid, pid_t tid,
 						bool create)
@@ -285,10 +296,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 	 * so most of the time we dont have to look up
 	 * the full rbtree:
 	 */
-	if (machine->last_match && machine->last_match->tid == tid) {
-		if (pid != -1 && pid != machine->last_match->pid_)
-			machine->last_match->pid_ = pid;
-		return machine->last_match;
+	th = machine->last_match;
+	if (th && th->tid == tid) {
+		machine__update_thread_pid(machine, th, pid);
+		return th;
 	}
 
 	while (*p != NULL) {
@@ -297,8 +308,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 
 		if (th->tid == tid) {
 			machine->last_match = th;
-			if (pid != -1 && pid != th->pid_)
-				th->pid_ = pid;
+			machine__update_thread_pid(machine, th, pid);
 			return th;
 		}
 
tools/perf/util/map.c +14 -0
index 25c571f..7af1480 100644
@@ -454,6 +454,20 @@ void map_groups__exit(struct map_groups *mg)
 	}
 }
 
+bool map_groups__empty(struct map_groups *mg)
+{
+	int i;
+
+	for (i = 0; i < MAP__NR_TYPES; ++i) {
+		if (maps__first(&mg->maps[i]))
+			return false;
+		if (!list_empty(&mg->removed_maps[i]))
+			return false;
+	}
+
+	return true;
+}
+
 struct map_groups *map_groups__new(void)
 {
 	struct map_groups *mg = malloc(sizeof(*mg));
tools/perf/util/map.h +1 -0
index 7758c72..5806a90 100644
@@ -66,6 +66,7 @@ struct map_groups {
 
 struct map_groups *map_groups__new(void);
 void map_groups__delete(struct map_groups *mg);
+bool map_groups__empty(struct map_groups *mg);
 
 static inline struct map_groups *map_groups__get(struct map_groups *mg)
 {
tools/perf/util/thread.c +35 -0
index 7a32f44..ca94295 100644
@@ -24,6 +24,41 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
 	return thread->mg ? 0 : -1;
 }
 
+int thread__join_map_groups(struct thread *thread, struct machine *machine)
+{
+	struct thread *leader;
+	pid_t pid = thread->pid_;
+
+	if (pid == thread->tid)
+		return 0;
+
+	leader = machine__findnew_thread(machine, pid, pid);
+	if (!leader)
+		return -ENOMEM;
+
+	if (!leader->mg)
+		leader->mg = map_groups__new();
+
+	if (!leader->mg)
+		return -ENOMEM;
+
+	if (thread->mg) {
+		/*
+		 * Maps are created from MMAP events which provide the pid and
+		 * tid.  Consequently there never should be any maps on a thread
+		 * with an unknown pid.  Just print an error if there are.
+		 */
+		if (!map_groups__empty(thread->mg))
+			pr_err("Discarding thread maps for %d:%d\n",
+			       thread->pid_, thread->tid);
+		map_groups__delete(thread->mg);
+	}
+
+	thread->mg = map_groups__get(leader->mg);
+
+	return 0;
+}
+
 struct thread *thread__new(pid_t pid, pid_t tid)
 {
 	char *comm_str;
tools/perf/util/thread.h +1 -0
index 3c0c272..9de0629 100644
@@ -31,6 +31,7 @@ struct comm;
 
 struct thread *thread__new(pid_t pid, pid_t tid);
 int thread__init_map_groups(struct thread *thread, struct machine *machine);
+int thread__join_map_groups(struct thread *thread, struct machine *machine);
 void thread__delete(struct thread *thread);
 static inline void thread__exited(struct thread *thread)
 {
Signature · 1 line
1.8.3.2
#4 lore raw

Re: [PATCH 02/41] perf tools: Fix map groups of threads with unknown pids

Em Mon, Jul 14, 2014 at 01:02:26PM +0300, Adrian Hunter escreveu:

Quoted 25 lines

Events like sched_switch do not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups. Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.

---
 tools/perf/util/machine.c | 22 ++++++++++++++++------
 tools/perf/util/map.c     | 14 ++++++++++++++
 tools/perf/util/map.h     |  1 +
 tools/perf/util/thread.c  | 35 +++++++++++++++++++++++++++++++++++
 tools/perf/util/thread.h  |  1 +
 5 files changed, 67 insertions(+), 6 deletions(-)
tools/perf/util/machine.c +1 -0
index 5b80877..0fa93c1 100644
@@ -272,6 +272,17 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
 	return;
 }
 
+static void machine__update_thread_pid(struct machine *machine,

tools/perf/util/machine.c void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) · line 285

Quoted 10 lines
tools/perf/util/machine.c +10 -0
+				       struct thread *th, pid_t pid)
+{
+	if (pid != th->pid_ && pid != -1 && th->pid_ == -1) {
+		th->pid_ = pid;
+		if (thread__join_map_groups(th, machine))
+			pr_err("Failed to join map groups for %d:%d\n",
+			       th->pid_, th->tid);
+	}
+}
+

I think you should combine the above function with thread__join_map_groups, and I think that the method belongs to the 'machine' class, see below for further comments on this...

Quoted 90 lines
tools/perf/util/machine.c +5 -6
 static struct thread *__machine__findnew_thread(struct machine *machine,
 						pid_t pid, pid_t tid,
 						bool create)
@@ -285,10 +296,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 	 * so most of the time we dont have to look up
 	 * the full rbtree:
 	 */
-	if (machine->last_match && machine->last_match->tid == tid) {
-		if (pid != -1 && pid != machine->last_match->pid_)
-			machine->last_match->pid_ = pid;
-		return machine->last_match;
+	th = machine->last_match;
+	if (th && th->tid == tid) {
+		machine__update_thread_pid(machine, th, pid);
+		return th;
 	}
 
 	while (*p != NULL) {
@@ -297,8 +308,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 
 		if (th->tid == tid) {
 			machine->last_match = th;
-			if (pid != -1 && pid != th->pid_)
-				th->pid_ = pid;
+			machine__update_thread_pid(machine, th, pid);
 			return th;
 		}
 
tools/perf/util/map.c +14 -0
index 25c571f..7af1480 100644
@@ -454,6 +454,20 @@ void map_groups__exit(struct map_groups *mg)
 	}
 }
 
+bool map_groups__empty(struct map_groups *mg)
+{
+	int i;
+
+	for (i = 0; i < MAP__NR_TYPES; ++i) {
+		if (maps__first(&mg->maps[i]))
+			return false;
+		if (!list_empty(&mg->removed_maps[i]))
+			return false;
+	}
+
+	return true;
+}
+
 struct map_groups *map_groups__new(void)
 {
 	struct map_groups *mg = malloc(sizeof(*mg));
tools/perf/util/map.h +1 -0
index 7758c72..5806a90 100644
@@ -66,6 +66,7 @@ struct map_groups {
 
 struct map_groups *map_groups__new(void);
 void map_groups__delete(struct map_groups *mg);
+bool map_groups__empty(struct map_groups *mg);
 
 static inline struct map_groups *map_groups__get(struct map_groups *mg)
 {
tools/perf/util/thread.c +17 -0
index 7a32f44..ca94295 100644
@@ -24,6 +24,41 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
 	return thread->mg ? 0 : -1;
 }
 
+int thread__join_map_groups(struct thread *thread, struct machine *machine)
+{
+	struct thread *leader;
+	pid_t pid = thread->pid_;
+
+	if (pid == thread->tid)
+		return 0;
+
+	leader = machine__findnew_thread(machine, pid, pid);
+	if (!leader)
+		return -ENOMEM;
+
+	if (!leader->mg)
+		leader->mg = map_groups__new();
+
+	if (!leader->mg)
+		return -ENOMEM;

tools/perf/util/thread.c int thread__init_map_groups(struct thread *thread, struct machine *machine) · line 53

Quoted 10 lines
tools/perf/util/thread.c +10 -0
+
+	if (thread->mg) {
+		/*
+		 * Maps are created from MMAP events which provide the pid and
+		 * tid.  Consequently there never should be any maps on a thread
+		 * with an unknown pid.  Just print an error if there are.
+		 */
+		if (!map_groups__empty(thread->mg))
+			pr_err("Discarding thread maps for %d:%d\n",
+			       thread->pid_, thread->tid);

Because there is nothing in this function (thread__join_map_groups), checking if it is operating on a thread that has an unknown pid.

So, please consider merging this and its sole caller, machine__update_thread_pid, so that the test is in the same function as the assumption that it is operating on a thread with an unknown pid.

Continuing to look at the other patches...

Quoted 25 lines
tools/perf/util/thread.c +8 -0
+		map_groups__delete(thread->mg);
+	}
+
+	thread->mg = map_groups__get(leader->mg);
+
+	return 0;
+}
+
 struct thread *thread__new(pid_t pid, pid_t tid)
 {
 	char *comm_str;
tools/perf/util/thread.h +1 -0
index 3c0c272..9de0629 100644
@@ -31,6 +31,7 @@ struct comm;
 
 struct thread *thread__new(pid_t pid, pid_t tid);
 int thread__init_map_groups(struct thread *thread, struct machine *machine);
+int thread__join_map_groups(struct thread *thread, struct machine *machine);
 void thread__delete(struct thread *thread);
 static inline void thread__exited(struct thread *thread)
 {
Signature · 1 line
1.8.3.2
author reviewer
#5 lore raw

Re: [PATCH 02/41] perf tools: Fix map groups of threads with unknown pids

Quoted 80 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 14, 2014 at 01:02:26PM +0300, Adrian Hunter escreveu:

Quoted 25 lines

Events like sched_switch do not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups. Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.

---
 tools/perf/util/machine.c | 22 ++++++++++++++++------
 tools/perf/util/map.c     | 14 ++++++++++++++
 tools/perf/util/map.h     |  1 +
 tools/perf/util/thread.c  | 35 +++++++++++++++++++++++++++++++++++
 tools/perf/util/thread.h  |  1 +
 5 files changed, 67 insertions(+), 6 deletions(-)
tools/perf/util/machine.c +1 -0
index 5b80877..0fa93c1 100644
@@ -272,6 +272,17 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
 	return;
 }
 
+static void machine__update_thread_pid(struct machine *machine,

tools/perf/util/machine.c void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) · line 285

Quoted 10 lines
tools/perf/util/machine.c +10 -0
+				       struct thread *th, pid_t pid)
+{
+	if (pid != th->pid_ && pid != -1 && th->pid_ == -1) {
+		th->pid_ = pid;
+		if (thread__join_map_groups(th, machine))
+			pr_err("Failed to join map groups for %d:%d\n",
+			       th->pid_, th->tid);
+	}
+}
+

I think you should combine the above function with thread__join_map_groups, and I think that the method belongs to the 'machine' class, see below for further comments on this...

Quoted 25 lines
tools/perf/util/thread.c +17 -0
index 7a32f44..ca94295 100644
@@ -24,6 +24,41 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
 	return thread->mg ? 0 : -1;
 }
 
+int thread__join_map_groups(struct thread *thread, struct machine *machine)
+{
+	struct thread *leader;
+	pid_t pid = thread->pid_;
+
+	if (pid == thread->tid)
+		return 0;
+
+	leader = machine__findnew_thread(machine, pid, pid);
+	if (!leader)
+		return -ENOMEM;
+
+	if (!leader->mg)
+		leader->mg = map_groups__new();
+
+	if (!leader->mg)
+		return -ENOMEM;

tools/perf/util/thread.c int thread__init_map_groups(struct thread *thread, struct machine *machine) · line 53

Quoted 10 lines
tools/perf/util/thread.c +10 -0
+
+	if (thread->mg) {
+		/*
+		 * Maps are created from MMAP events which provide the pid and
+		 * tid.  Consequently there never should be any maps on a thread
+		 * with an unknown pid.  Just print an error if there are.
+		 */
+		if (!map_groups__empty(thread->mg))
+			pr_err("Discarding thread maps for %d:%d\n",
+			       thread->pid_, thread->tid);

Because there is nothing in this function (thread__join_map_groups), checking if it is operating on a thread that has an unknown pid.

Quoted 3 lines

So, please consider merging this and its sole caller, machine__update_thread_pid, so that the test is in the same function as the assumption that it is operating on a thread with an unknown pid.

You have it in your tree now. Do you want another patch to do that?

#6 lore raw

Re: [PATCH 02/41] perf tools: Fix map groups of threads with unknown pids

Em Tue, Jul 15, 2014 at 02:33:01PM +0300, Adrian Hunter escreveu:

Quoted 10 lines · Arnaldo Carvalho de Melo
Quoted 6 lines

Because there is nothing in this function (thread__join_map_groups), checking if it is operating on a thread that has an unknown pid.

So, please consider merging this and its sole caller, machine__update_thread_pid, so that the test is in the same function as the assumption that it is operating on a thread with an unknown pid.

You have it in your tree now. Do you want another patch to do that?

Sorry, ended up push it together with the rest, fixed up now, removed it and added some more from your kit, please work from there.

Let me know if you find any problem with the merge process so far.

Thanks,

- Arnaldo

author reviewer
#7 lore raw

PATCH v2 2/41 perf tools: Fix map groups of threads with unknown pids

Events like sched_switch do not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups. Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.

---
 tools/perf/util/machine.c | 57 ++++++++++++++++++++++++++++++++++++++++++-----
 tools/perf/util/map.c     | 14 ++++++++++++
 tools/perf/util/map.h     |  1 +
 3 files changed, 66 insertions(+), 6 deletions(-)
tools/perf/util/machine.c +51 -6
index b75af25..93c8b6f 100644
@@ -272,6 +272,52 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
 	return;
 }
 
+static void machine__update_thread_pid(struct machine *machine,
+				       struct thread *th, pid_t pid)
+{
+	struct thread *leader;
+
+	if (pid == th->pid_ || pid == -1 || th->pid_ != -1)
+		return;
+
+	th->pid_ = pid;
+
+	if (th->pid_ == th->tid)
+		return;
+
+	leader = machine__findnew_thread(machine, th->pid_, th->pid_);
+	if (!leader)
+		goto out_err;
+
+	if (!leader->mg)
+		leader->mg = map_groups__new();
+
+	if (!leader->mg)
+		goto out_err;
+
+	if (th->mg == leader->mg)
+		return;
+
+	if (th->mg) {
+		/*
+		 * Maps are created from MMAP events which provide the pid and
+		 * tid.  Consequently there never should be any maps on a thread
+		 * with an unknown pid.  Just print an error if there are.
+		 */
+		if (!map_groups__empty(th->mg))
+			pr_err("Discarding thread maps for %d:%d\n",
+			       th->pid_, th->tid);
+		map_groups__delete(th->mg);
+	}
+
+	th->mg = map_groups__get(leader->mg);
+
+	return;
+
+out_err:
+	pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
+}
+
 static struct thread *__machine__findnew_thread(struct machine *machine,
 						pid_t pid, pid_t tid,
 						bool create)
@@ -285,10 +331,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 	 * so most of the time we dont have to look up
 	 * the full rbtree:
 	 */
-	if (machine->last_match && machine->last_match->tid == tid) {
-		if (pid != -1 && pid != machine->last_match->pid_)
-			machine->last_match->pid_ = pid;
-		return machine->last_match;
+	th = machine->last_match;
+	if (th && th->tid == tid) {
+		machine__update_thread_pid(machine, th, pid);
+		return th;
 	}
 
 	while (*p != NULL) {
@@ -297,8 +343,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 
 		if (th->tid == tid) {
 			machine->last_match = th;
-			if (pid != -1 && pid != th->pid_)
-				th->pid_ = pid;
+			machine__update_thread_pid(machine, th, pid);
 			return th;
 		}
 
tools/perf/util/map.c +14 -0
index 25c571f..7af1480 100644
@@ -454,6 +454,20 @@ void map_groups__exit(struct map_groups *mg)
 	}
 }
 
+bool map_groups__empty(struct map_groups *mg)
+{
+	int i;
+
+	for (i = 0; i < MAP__NR_TYPES; ++i) {
+		if (maps__first(&mg->maps[i]))
+			return false;
+		if (!list_empty(&mg->removed_maps[i]))
+			return false;
+	}
+
+	return true;
+}
+
 struct map_groups *map_groups__new(void)
 {
 	struct map_groups *mg = malloc(sizeof(*mg));
tools/perf/util/map.h +1 -0
index 7758c72..5806a90 100644
@@ -66,6 +66,7 @@ struct map_groups {
 
 struct map_groups *map_groups__new(void);
 void map_groups__delete(struct map_groups *mg);
+bool map_groups__empty(struct map_groups *mg);
 
 static inline struct map_groups *map_groups__get(struct map_groups *mg)
 {
Signature · 1 line
1.8.3.2
#8 lore raw

[tip:perf/core] perf machine: Fix map groups of threads with unknown pids

perf machine: Fix map groups of threads with unknown pids
Commit-ID:  29ce36121e6738012aaf00d983d25260627f2b0d
Gitweb:     http://git.kernel.org/tip/29ce36121e6738012aaf00d983d25260627f2b0d
Author:     Adrian Hunter <[email protected]>
AuthorDate: Wed, 16 Jul 2014 11:07:13 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 17 Jul 2014 10:31:02 -0300

perf machine: Fix map groups of threads with unknown pids

Events like sched_switch do not provide a pid (tgid) which can result in threads with an unknown pid. If the pid is later discovered, join the map groups.

Note the thread's map groups should be empty because they are populated by MMAP events which do provide the pid and tid.

---
 tools/perf/util/machine.c | 57 ++++++++++++++++++++++++++++++++++++++++++-----
 tools/perf/util/map.c     | 14 ++++++++++++
 tools/perf/util/map.h     |  1 +
 3 files changed, 66 insertions(+), 6 deletions(-)
tools/perf/util/machine.c +51 -6
index 5b80877..5484fa4 100644
@@ -272,6 +272,52 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
 	return;
 }
 
+static void machine__update_thread_pid(struct machine *machine,
+				       struct thread *th, pid_t pid)
+{
+	struct thread *leader;
+
+	if (pid == th->pid_ || pid == -1 || th->pid_ != -1)
+		return;
+
+	th->pid_ = pid;
+
+	if (th->pid_ == th->tid)
+		return;
+
+	leader = machine__findnew_thread(machine, th->pid_, th->pid_);
+	if (!leader)
+		goto out_err;
+
+	if (!leader->mg)
+		leader->mg = map_groups__new();
+
+	if (!leader->mg)
+		goto out_err;
+
+	if (th->mg == leader->mg)
+		return;
+
+	if (th->mg) {
+		/*
+		 * Maps are created from MMAP events which provide the pid and
+		 * tid.  Consequently there never should be any maps on a thread
+		 * with an unknown pid.  Just print an error if there are.
+		 */
+		if (!map_groups__empty(th->mg))
+			pr_err("Discarding thread maps for %d:%d\n",
+			       th->pid_, th->tid);
+		map_groups__delete(th->mg);
+	}
+
+	th->mg = map_groups__get(leader->mg);
+
+	return;
+
+out_err:
+	pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
+}
+
 static struct thread *__machine__findnew_thread(struct machine *machine,
 						pid_t pid, pid_t tid,
 						bool create)
@@ -285,10 +331,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 	 * so most of the time we dont have to look up
 	 * the full rbtree:
 	 */
-	if (machine->last_match && machine->last_match->tid == tid) {
-		if (pid != -1 && pid != machine->last_match->pid_)
-			machine->last_match->pid_ = pid;
-		return machine->last_match;
+	th = machine->last_match;
+	if (th && th->tid == tid) {
+		machine__update_thread_pid(machine, th, pid);
+		return th;
 	}
 
 	while (*p != NULL) {
@@ -297,8 +343,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 
 		if (th->tid == tid) {
 			machine->last_match = th;
-			if (pid != -1 && pid != th->pid_)
-				th->pid_ = pid;
+			machine__update_thread_pid(machine, th, pid);
 			return th;
 		}
 
tools/perf/util/map.c +14 -0
index 25c571f..7af1480 100644
@@ -454,6 +454,20 @@ void map_groups__exit(struct map_groups *mg)
 	}
 }
 
+bool map_groups__empty(struct map_groups *mg)
+{
+	int i;
+
+	for (i = 0; i < MAP__NR_TYPES; ++i) {
+		if (maps__first(&mg->maps[i]))
+			return false;
+		if (!list_empty(&mg->removed_maps[i]))
+			return false;
+	}
+
+	return true;
+}
+
 struct map_groups *map_groups__new(void)
 {
 	struct map_groups *mg = malloc(sizeof(*mg));
tools/perf/util/map.h +1 -0
index 7758c72..5806a90 100644
@@ -66,6 +66,7 @@ struct map_groups {
 
 struct map_groups *map_groups__new(void);
 void map_groups__delete(struct map_groups *mg);
+bool map_groups__empty(struct map_groups *mg);
 
 static inline struct map_groups *map_groups__get(struct map_groups *mg)
 {
author reviewer
#9 lore raw

PATCH 3/41 perf script: Display PERF_RECORD_MISC_COMM_EXEC flag

In reply to Adrian Hunter
---
 tools/perf/util/event.c | 9 ++++++++-
 tools/perf/util/evsel.c | 3 ++-
 2 files changed, 10 insertions(+), 2 deletions(-)
tools/perf/util/event.c +8 -1
index d0281bd..198c4cc 100644
@@ -603,7 +603,14 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
 
 size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
 {
-	return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid);
+	const char *s;
+
+	if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC)
+		s = " exec";
+	else
+		s = "";
+
+	return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid);
 }
 
 int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
tools/perf/util/evsel.c +2 -1
index 8606175..b760d32 100644
@@ -960,6 +960,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
 	ret += PRINT_ATTR2(exclude_user, exclude_kernel);
 	ret += PRINT_ATTR2(exclude_hv, exclude_idle);
 	ret += PRINT_ATTR2(mmap, comm);
+	ret += PRINT_ATTR2(mmap2, comm_exec);
 	ret += PRINT_ATTR2(freq, inherit_stat);
 	ret += PRINT_ATTR2(enable_on_exec, task);
 	ret += PRINT_ATTR2(watermark, precise_ip);
@@ -967,7 +968,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
 	ret += PRINT_ATTR2(exclude_host, exclude_guest);
 	ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
 			    "excl.callchain_user", exclude_callchain_user);
-	ret += PRINT_ATTR_U32(mmap2);
 
 	ret += PRINT_ATTR_U32(wakeup_events);
 	ret += PRINT_ATTR_U32(wakeup_watermark);
@@ -1940,6 +1940,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
 		if_print(mmap);
 		if_print(mmap2);
 		if_print(comm);
+		if_print(comm_exec);
 		if_print(freq);
 		if_print(inherit_stat);
 		if_print(enable_on_exec);
Signature · 1 line
1.8.3.2
#10 lore raw

[tip:perf/core] perf script: Display PERF_RECORD_MISC_COMM_EXEC flag

perf script: Display PERF_RECORD_MISC_COMM_EXEC flag
Commit-ID:  022c50d09c2c2bc31506ad16c4bcba7fb418ce34
Gitweb:     http://git.kernel.org/tip/022c50d09c2c2bc31506ad16c4bcba7fb418ce34
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:27 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:34 -0300

perf script: Display PERF_RECORD_MISC_COMM_EXEC flag

---
 tools/perf/util/event.c | 9 ++++++++-
 tools/perf/util/evsel.c | 3 ++-
 2 files changed, 10 insertions(+), 2 deletions(-)
tools/perf/util/event.c +8 -1
index d0281bd..198c4cc 100644
@@ -603,7 +603,14 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
 
 size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
 {
-	return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid);
+	const char *s;
+
+	if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC)
+		s = " exec";
+	else
+		s = "";
+
+	return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid);
 }
 
 int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
tools/perf/util/evsel.c +2 -1
index 8606175..b760d32 100644
@@ -960,6 +960,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
 	ret += PRINT_ATTR2(exclude_user, exclude_kernel);
 	ret += PRINT_ATTR2(exclude_hv, exclude_idle);
 	ret += PRINT_ATTR2(mmap, comm);
+	ret += PRINT_ATTR2(mmap2, comm_exec);
 	ret += PRINT_ATTR2(freq, inherit_stat);
 	ret += PRINT_ATTR2(enable_on_exec, task);
 	ret += PRINT_ATTR2(watermark, precise_ip);
@@ -967,7 +968,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
 	ret += PRINT_ATTR2(exclude_host, exclude_guest);
 	ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
 			    "excl.callchain_user", exclude_callchain_user);
-	ret += PRINT_ATTR_U32(mmap2);
 
 	ret += PRINT_ATTR_U32(wakeup_events);
 	ret += PRINT_ATTR_U32(wakeup_watermark);
@@ -1940,6 +1940,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
 		if_print(mmap);
 		if_print(mmap2);
 		if_print(comm);
+		if_print(comm_exec);
 		if_print(freq);
 		if_print(inherit_stat);
 		if_print(enable_on_exec);
author reviewer
#11 lore raw

PATCH 4/41 perf record: Select comm_exec flag if supported

In reply to Adrian Hunter

The comm_exec flag on the attribute can later
be found in the perf.data file allowing a
tool to know in advance if the captured data
has the flag.

---
 tools/perf/util/record.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
tools/perf/util/record.c +17 -1
index 049e0a0..1657231 100644
@@ -69,15 +69,26 @@ static void perf_probe_sample_identifier(struct perf_evsel *evsel)
 	evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
 }
 
+static void perf_probe_comm_exec(struct perf_evsel *evsel)
+{
+	evsel->attr.comm_exec = 1;
+}
+
 bool perf_can_sample_identifier(void)
 {
 	return perf_probe_api(perf_probe_sample_identifier);
 }
 
+static bool perf_can_comm_exec(void)
+{
+	return perf_probe_api(perf_probe_comm_exec);
+}
+
 void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 {
 	struct perf_evsel *evsel;
 	bool use_sample_identifier = false;
+	bool use_comm_exec;
 
 	/*
 	 * Set the evsel leader links before we configure attributes,
@@ -89,8 +100,13 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 	if (evlist->cpus->map[0] < 0)
 		opts->no_inherit = true;
 
-	evlist__for_each(evlist, evsel)
+	use_comm_exec = perf_can_comm_exec();
+
+	evlist__for_each(evlist, evsel) {
 		perf_evsel__config(evsel, opts);
+		if (!evsel->idx && use_comm_exec)
+			evsel->attr.comm_exec = 1;
+	}
 
 	if (evlist->nr_entries > 1) {
 		struct perf_evsel *first = perf_evlist__first(evlist);
Signature · 1 line
1.8.3.2
#12 lore raw

[tip:perf/core] perf record: Select comm_exec flag if supported

perf record: Select comm_exec flag if supported
Commit-ID:  39e09d40bea440d9cfe645b55aff251294318669
Gitweb:     http://git.kernel.org/tip/39e09d40bea440d9cfe645b55aff251294318669
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:28 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:34 -0300

perf record: Select comm_exec flag if supported

The comm_exec flag on the attribute can later be found in the perf.data file allowing a tool to know in advance if the captured data has the flag.

---
 tools/perf/util/record.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
tools/perf/util/record.c +17 -1
index 049e0a0..1657231 100644
@@ -69,15 +69,26 @@ static void perf_probe_sample_identifier(struct perf_evsel *evsel)
 	evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
 }
 
+static void perf_probe_comm_exec(struct perf_evsel *evsel)
+{
+	evsel->attr.comm_exec = 1;
+}
+
 bool perf_can_sample_identifier(void)
 {
 	return perf_probe_api(perf_probe_sample_identifier);
 }
 
+static bool perf_can_comm_exec(void)
+{
+	return perf_probe_api(perf_probe_comm_exec);
+}
+
 void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 {
 	struct perf_evsel *evsel;
 	bool use_sample_identifier = false;
+	bool use_comm_exec;
 
 	/*
 	 * Set the evsel leader links before we configure attributes,
@@ -89,8 +100,13 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 	if (evlist->cpus->map[0] < 0)
 		opts->no_inherit = true;
 
-	evlist__for_each(evlist, evsel)
+	use_comm_exec = perf_can_comm_exec();
+
+	evlist__for_each(evlist, evsel) {
 		perf_evsel__config(evsel, opts);
+		if (!evsel->idx && use_comm_exec)
+			evsel->attr.comm_exec = 1;
+	}
 
 	if (evlist->nr_entries > 1) {
 		struct perf_evsel *first = perf_evlist__first(evlist);
author reviewer
#13 lore raw

PATCH 5/41 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 0fa93c1..2513204 100644
@@ -360,11 +360,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 ca94295..149e417 100644
@@ -76,7 +76,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;
@@ -113,19 +113,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 9de0629..b4269af 100644
@@ -38,9 +38,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
#14 lore raw

Re: [PATCH 05/41] perf tools: Identify which comms are from exec

Em Mon, Jul 14, 2014 at 01:02:29PM +0300, Adrian Hunter escreveu:

Quoted 40 lines
---
 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 +3 -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;
 

tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111

Quoted 5 lines
tools/perf/util/comm.c +2 -0
@@ -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;

Why do you need the !comm->exec test?

Quoted 99 lines
tools/perf/util/comm.c +0 -0
 	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 0fa93c1..2513204 100644
@@ -360,11 +360,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 ca94295..149e417 100644
@@ -76,7 +76,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;
@@ -113,19 +113,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 +0 -0
index 9de0629..b4269af 100644
@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread)
 	thread->dead = true;
 }

tools/perf/util/thread.h static inline void thread__exited(struct thread *thread) · line 48

Quoted 10 lines
tools/perf/util/thread.h +8 -1
 
-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);
+}
+

So this is nice, you leave the existing function, setting exec to false, so that you don't have to change the existing codepaths where it is not from 'exec', and provide a __ prefixed variant where 'exec' can be set.

Why not to do the same thing for comm__new() ? No uses, i.e. in all cases you will need to pass 'exec' as a variable?

I thought about doing the same thing for that machine__findnew_thread, i.e. provide a variant where tid and pid is passed and one where just the tid is passed, because the pid is unknown.

BTW, I'll update my perf/core branch with the set of patches that I merged, so that you can have where to look for a consolidated tree with the things already processed.

- Arnaldo

Quoted 8 lines
tools/perf/util/thread.h +1 -0
 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
#15 lore raw

Re: [PATCH 05/41] perf tools: Identify which comms are from exec

Quoted 40 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 14, 2014 at 01:02:29PM +0300, Adrian Hunter escreveu:

Quoted 39 lines
---
 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 +3 -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;
 
Quoted 8 lines

tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111

Quoted 6 lines
tools/perf/util/comm.c +2 -0
@@ -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;

Why do you need the !comm->exec test?

Dunno

Quoted 115 lines
Quoted 100 lines
tools/perf/util/comm.c +0 -0
 	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 0fa93c1..2513204 100644
@@ -360,11 +360,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 ca94295..149e417 100644
@@ -76,7 +76,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;
@@ -113,19 +113,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 +0 -0
index 9de0629..b4269af 100644
@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread)
 	thread->dead = true;
 }

tools/perf/util/thread.h static inline void thread__exited(struct thread *thread) · line 48

Quoted 10 lines
tools/perf/util/thread.h +8 -1
 
-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);
+}
+

So this is nice, you leave the existing function, setting exec to false, so that you don't have to change the existing codepaths where it is not from 'exec', and provide a __ prefixed variant where 'exec' can be set.

Quoted 2 lines

Why not to do the same thing for comm__new() ? No uses, i.e. in all cases you will need to pass 'exec' as a variable?

There are only 2 comm__new() callers, and they are in files I am changing anyway.

Quoted 4 lines

I thought about doing the same thing for that machine__findnew_thread, i.e. provide a variant where tid and pid is passed and one where just the tid is passed, because the pid is unknown.

But you don't want people using the "unknown" variant if they do know the pid, so forcing them to pass something maybe better.

Quoted 4 lines

BTW, I'll update my perf/core branch with the set of patches that I merged, so that you can have where to look for a consolidated tree with the things already processed.

Thanks!

#16 lore raw

Re: [PATCH 05/41] perf tools: Identify which comms are from exec

Em Tue, Jul 15, 2014 at 02:43:08PM +0300, Adrian Hunter escreveu:

Quoted 10 lines
Quoted 8 lines

tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111

Quoted 6 lines
tools/perf/util/comm.c +2 -0
@@ -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;

Why do you need the !comm->exec test?

Dunno

I saw that you kept it in the last patchkit submitted, I'll just drop it, needless obfuscation.

- Arnaldo

#17 lore raw

Re: [PATCH 05/41] perf tools: Identify which comms are from exec

Em Wed, Jul 23, 2014 at 11:07:52AM -0300, Arnaldo Carvalho de Melo escreveu:

Quoted 10 lines

Em Tue, Jul 15, 2014 at 02:43:08PM +0300, Adrian Hunter escreveu:

Quoted 8 lines
Quoted 8 lines

tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111

Quoted 6 lines
tools/perf/util/comm.c +2 -0
@@ -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;

Why do you need the !comm->exec test?

Quoted 4 lines
Quoted 1 line

Dunno

I saw that you kept it in the last patchkit submitted, I'll just drop it, needless obfuscation.

Also why do you need to "identify which comms are from exec", was it good for?

- Arnaldo

author reviewer
#18 lore raw

Re: [PATCH 05/41] perf tools: Identify which comms are from exec

Quoted 15 lines · Arnaldo Carvalho de Melo

Em Wed, Jul 23, 2014 at 11:07:52AM -0300, Arnaldo Carvalho de Melo escreveu:

Quoted 14 lines

Em Tue, Jul 15, 2014 at 02:43:08PM +0300, Adrian Hunter escreveu:

Quoted 10 lines
Quoted 8 lines

tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111

Quoted 6 lines
tools/perf/util/comm.c +2 -0
@@ -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;

Why do you need the !comm->exec test?

Dunno

I saw that you kept it in the last patchkit submitted, I'll just drop it, needless obfuscation.

Sorry I forgot.

Quoted 3 lines

Also why do you need to "identify which comms are from exec", was it good for?

It is for grouping together all the data from a single execution, which is needed for pairing calls and returns e.g. any outstanding calls when a process exec's will never return.

#19 lore raw

Re: [PATCH 05/41] perf tools: Identify which comms are from exec

Em Wed, Jul 23, 2014 at 07:46:43PM +0300, Adrian Hunter escreveu:

Quoted 17 lines · Arnaldo Carvalho de Melo
Quoted 15 lines

Em Wed, Jul 23, 2014 at 11:07:52AM -0300, Arnaldo Carvalho de Melo escreveu:

Quoted 14 lines

Em Tue, Jul 15, 2014 at 02:43:08PM +0300, Adrian Hunter escreveu:

Quoted 10 lines
Quoted 8 lines

tools/perf/util/comm.c int comm__override(struct comm *comm, const char *str, u64 timestamp) · line 111

Quoted 6 lines
tools/perf/util/comm.c +2 -0
@@ -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;

Why do you need the !comm->exec test?

Dunno

I saw that you kept it in the last patchkit submitted, I'll just drop it, needless obfuscation.

Quoted 8 lines

Sorry I forgot.

Quoted 2 lines

Also why do you need to "identify which comms are from exec", was it good for?

It is for grouping together all the data from a single execution, which is needed for pairing calls and returns e.g. any outstanding calls when a process exec's will never return.

Ok, thanks, I'll add it to the patch log, as I did with some others.

I'll continue after lunch, what I have so far is in the tmp.perf/core in my tree, at git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git

- Arnaldo

author reviewer
#20 lore raw

PATCH 6/41 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 2513204..c1c5ca3 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;
@@ -354,6 +368,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)
 {
@@ -362,6 +385,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 c2f4ca9..c1abe6b 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
#21 lore raw

PATCH 7/41 perf tools: Fix missing kernel map load

In reply to Adrian Hunter

thread__find_addr_map() falls back to trying the kernel maps if the address is negative and is not found in userspace maps. As commented in the code, the kernel maps must be "loaded" before use. This patch ensures that happens under the fallback condition also.

---
 tools/perf/util/event.c | 1 +
 1 file changed, 1 insertion(+)
tools/perf/util/event.c +1 -0
index 198c4cc..7e0e8ae 100644
@@ -788,6 +788,7 @@ try_again:
 		    cpumode == PERF_RECORD_MISC_USER &&
 		    machine && mg != &machine->kmaps) {
 			mg = &machine->kmaps;
+			load_map = true;
 			goto try_again;
 		}
 	} else {
Signature · 1 line
1.8.3.2
#22 lore raw

[tip:perf/core] perf tools: Fix missing kernel map load

perf tools: Fix missing kernel map load
Commit-ID:  1f2a7069b6e895487b1d9229f5f62799cc4ea0aa
Gitweb:     http://git.kernel.org/tip/1f2a7069b6e895487b1d9229f5f62799cc4ea0aa
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:31 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:34 -0300

perf tools: Fix missing kernel map load

thread__find_addr_map() falls back to trying the kernel maps if the address is negative and is not found in userspace maps. As commented in the code, the kernel maps must be "loaded" before use. This patch ensures that happens under the fallback condition also.

---
 tools/perf/util/event.c | 1 +
 1 file changed, 1 insertion(+)
tools/perf/util/event.c +1 -0
index 198c4cc..7e0e8ae 100644
@@ -788,6 +788,7 @@ try_again:
 		    cpumode == PERF_RECORD_MISC_USER &&
 		    machine && mg != &machine->kmaps) {
 			mg = &machine->kmaps;
+			load_map = true;
 			goto try_again;
 		}
 	} else {
author reviewer
#23 lore raw

PATCH 8/41 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 6864661..8c96817 100644
@@ -732,7 +732,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
#24 lore raw

Re: [PATCH 08/41] perf tools: Fix missing label symbols

Em Mon, Jul 14, 2014 at 01:02:32PM +0300, Adrian Hunter escreveu:

Quoted 8 lines

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.

Would be great to have a 'perf test' entry that fail when looking for those 'label symbols', i.e. looking for one such symbol in vmlinux that we know is always there, in some written in stone area of the kernel, where this label vanishing is unlikely to happen.

Can you elaborate on the case that fails? So that I can test it here, and then after the fix, check that it indeed fixes the problem? I may well write that test myself and insert it in my branch just before this one.

- Arnaldo

Quoted 20 lines
---
 tools/perf/util/symbol-elf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +1 -1
index 6864661..8c96817 100644
@@ -732,7 +732,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
#25 lore raw

Re: [PATCH 08/41] perf tools: Fix missing label symbols

Quoted 15 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 14, 2014 at 01:02:32PM +0300, Adrian Hunter escreveu:

Quoted 8 lines

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.

Would be great to have a 'perf test' entry that fail when looking for those 'label symbols', i.e. looking for one such symbol in vmlinux that we know is always there, in some written in stone area of the kernel, where this label vanishing is unlikely to happen.

Quoted 4 lines

Can you elaborate on the case that fails? So that I can test it here, and then after the fix, check that it indeed fixes the problem? I may well write that test myself and insert it in my branch just before this one.

It fails with "_start" which is a label in /lib/x86_64-linux-gnu/ld-2.17.so. It is where the program starts so it is not a function, and it is the first user space address of an exec'ed process.

If you do:

	perf record --per-thread -T -e branches:u -c1 -d -- uname

Then, assuming the old BTS driver doesn't lose the data, it should be pretty much the first branch.

pref script | head

Quoted 25 lines

- Arnaldo

Quoted 20 lines
---
 tools/perf/util/symbol-elf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +1 -1
index 6864661..8c96817 100644
@@ -732,7 +732,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
#26 lore raw

PATCH 9/41 perf tools: Fix missing GNU IFUNC symbols

In reply to Adrian Hunter

Symbols of type STT_GNU_IFUNC are functions
so accept them as such.

---
 tools/perf/util/symbol-elf.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +2 -1
index 8c96817..477596c 100644
@@ -49,7 +49,8 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym)
 
 static inline int elf_sym__is_function(const GElf_Sym *sym)
 {
-	return elf_sym__type(sym) == STT_FUNC &&
+	return (elf_sym__type(sym) == STT_FUNC ||
+		elf_sym__type(sym) == STT_GNU_IFUNC) &&
 	       sym->st_name != 0 &&
 	       sym->st_shndx != SHN_UNDEF;
 }
Signature · 1 line
1.8.3.2
#27 lore raw

[tip:perf/core] perf symbols: Fix missing GNU IFUNC symbols

perf symbols: Fix missing GNU IFUNC symbols
Commit-ID:  a2f3b6bf0adadcb5f9383c60aa1355e0f9cba3da
Gitweb:     http://git.kernel.org/tip/a2f3b6bf0adadcb5f9383c60aa1355e0f9cba3da
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:33 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:34 -0300

perf symbols: Fix missing GNU IFUNC symbols

Symbols of type STT_GNU_IFUNC are functions so accept them as such.

---
 tools/perf/util/symbol-elf.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +2 -1
index 6864661..dce5ccf 100644
@@ -49,7 +49,8 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym)
 
 static inline int elf_sym__is_function(const GElf_Sym *sym)
 {
-	return elf_sym__type(sym) == STT_FUNC &&
+	return (elf_sym__type(sym) == STT_FUNC ||
+		elf_sym__type(sym) == STT_GNU_IFUNC) &&
 	       sym->st_name != 0 &&
 	       sym->st_shndx != SHN_UNDEF;
 }
author reviewer
#28 lore raw

PATCH 10/41 perf inject: Fix build id injection

In reply to Adrian Hunter

Build Ids won't be injected unless the build id
feature flag is set.

---
 tools/perf/builtin-inject.c | 3 +++
 1 file changed, 3 insertions(+)
tools/perf/builtin-inject.c +3 -0
index 16c7c11..cf6a605 100644
@@ -389,6 +389,9 @@ static int __cmd_inject(struct perf_inject *inject)
 	ret = perf_session__process_events(session, &inject->tool);
 
 	if (!file_out->is_pipe) {
+		if (inject->build_ids)
+			perf_header__set_feat(&session->header,
+					      HEADER_BUILD_ID);
 		session->header.data_size = inject->bytes_written;
 		perf_session__write_header(session, session->evlist, file_out->fd, true);
 	}
Signature · 1 line
1.8.3.2
#29 lore raw

[tip:perf/core] perf inject: Fix build id injection

perf inject: Fix build id injection
Commit-ID:  e38b43c3f3fd8ebe6f558400d1647a923bc19d44
Gitweb:     http://git.kernel.org/tip/e38b43c3f3fd8ebe6f558400d1647a923bc19d44
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:34 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:34 -0300

perf inject: Fix build id injection

Build Ids won't be injected unless the build id feature flag is set.

---
 tools/perf/builtin-inject.c | 3 +++
 1 file changed, 3 insertions(+)
tools/perf/builtin-inject.c +3 -0
index 16c7c11..cf6a605 100644
@@ -389,6 +389,9 @@ static int __cmd_inject(struct perf_inject *inject)
 	ret = perf_session__process_events(session, &inject->tool);
 
 	if (!file_out->is_pipe) {
+		if (inject->build_ids)
+			perf_header__set_feat(&session->header,
+					      HEADER_BUILD_ID);
 		session->header.data_size = inject->bytes_written;
 		perf_session__write_header(session, session->evlist, file_out->fd, true);
 	}
author reviewer
#30 lore raw

PATCH 11/41 perf tools: Fix appending a callchain from a previous sample

In reply to Adrian Hunter

hist_entry__append_callchain() must check if the sample has a callcahin or it will append the callchain from a previous sample.

---
 tools/perf/util/callchain.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/callchain.c +1 -1
index 48b6d3f..437ee09 100644
@@ -626,7 +626,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
 
 int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
 {
-	if (!symbol_conf.use_callchain)
+	if (!symbol_conf.use_callchain || sample->callchain == NULL)
 		return 0;
 	return callchain_append(he->callchain, &callchain_cursor, sample->period);
 }
Signature · 1 line
1.8.3.2
#31 lore raw

[tip:perf/core] perf callchain: Fix appending a callchain from a previous sample

perf callchain: Fix appending a callchain from a previous sample
Commit-ID:  4d40b051b1ac41ecbc818deed27750b4c1697520
Gitweb:     http://git.kernel.org/tip/4d40b051b1ac41ecbc818deed27750b4c1697520
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:35 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:35 -0300

perf callchain: Fix appending a callchain from a previous sample

hist_entry__append_callchain() must check if the sample has a callcahin or it will append the callchain from a previous sample.

---
 tools/perf/util/callchain.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/callchain.c +1 -1
index 48b6d3f..437ee09 100644
@@ -626,7 +626,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
 
 int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
 {
-	if (!symbol_conf.use_callchain)
+	if (!symbol_conf.use_callchain || sample->callchain == NULL)
 		return 0;
 	return callchain_append(he->callchain, &callchain_cursor, sample->period);
 }
author reviewer
#32 lore raw

PATCH 12/41 perf tools: Fix leak of 'struct thread' on error path

In reply to Adrian Hunter

__machine__findnew_thread() creates a 'struct thread' but does not free it on the error path.

---
 tools/perf/util/machine.c | 4 +++-
 tools/perf/util/thread.c  | 6 ++++--
 2 files changed, 7 insertions(+), 3 deletions(-)
tools/perf/util/machine.c +3 -1
index c1c5ca3..18eaf31 100644
@@ -349,8 +349,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 		 * within thread__init_map_groups to find the thread
 		 * leader and that would screwed the rb tree.
 		 */
-		if (thread__init_map_groups(th, machine))
+		if (thread__init_map_groups(th, machine)) {
+			thread__delete(th);
 			return NULL;
+		}
 	}
 
 	return th;
tools/perf/util/thread.c +4 -2
index 149e417..b9a3ee4 100644
@@ -95,8 +95,10 @@ void thread__delete(struct thread *thread)
 {
 	struct comm *comm, *tmp;
 
-	map_groups__put(thread->mg);
-	thread->mg = NULL;
+	if (thread->mg) {
+		map_groups__put(thread->mg);
+		thread->mg = NULL;
+	}
 	list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
 		list_del(&comm->list);
 		comm__free(comm);
Signature · 1 line
1.8.3.2
#33 lore raw

Re: [PATCH 12/41] perf tools: Fix leak of 'struct thread' on error path

Em Mon, Jul 14, 2014 at 01:02:36PM +0300, Adrian Hunter escreveu:

Quoted 2 lines

__machine__findnew_thread() creates a 'struct thread' but does not free it on the error path.

Ok, but that second one is a separate bug, i.e. its not fixing the described leak, please break this into two patches with separate commit messages.

- Arnaldo

Quoted 41 lines
---
 tools/perf/util/machine.c | 4 +++-
 tools/perf/util/thread.c  | 6 ++++--
 2 files changed, 7 insertions(+), 3 deletions(-)
tools/perf/util/machine.c +3 -1
index c1c5ca3..18eaf31 100644
@@ -349,8 +349,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 		 * within thread__init_map_groups to find the thread
 		 * leader and that would screwed the rb tree.
 		 */
-		if (thread__init_map_groups(th, machine))
+		if (thread__init_map_groups(th, machine)) {
+			thread__delete(th);
 			return NULL;
+		}
 	}
 
 	return th;
tools/perf/util/thread.c +4 -2
index 149e417..b9a3ee4 100644
@@ -95,8 +95,10 @@ void thread__delete(struct thread *thread)
 {
 	struct comm *comm, *tmp;
 
-	map_groups__put(thread->mg);
-	thread->mg = NULL;
+	if (thread->mg) {
+		map_groups__put(thread->mg);
+		thread->mg = NULL;
+	}
 	list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
 		list_del(&comm->list);
 		comm__free(comm);
Signature · 1 line
1.8.3.2
author reviewer
#34 lore raw

v2 cover perf tools: Allow deletion of a thread with no map groups

Hi

Here is the patch split in two.

Regards
Adrian

author reviewer
#35 lore raw

PATCH v2 1/2 perf tools: Allow deletion of a thread with no map groups

It needs to be possible to call thread__delete() on a thread with no map groups. This is needed for a subsequent patch which deletes a thread on the error path before map groups have been attached.

---
 tools/perf/util/thread.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
tools/perf/util/thread.c +4 -2
index 7a32f44..b9c36ef 100644
@@ -60,8 +60,10 @@ void thread__delete(struct thread *thread)
 {
 	struct comm *comm, *tmp;
 
-	map_groups__put(thread->mg);
-	thread->mg = NULL;
+	if (thread->mg) {
+		map_groups__put(thread->mg);
+		thread->mg = NULL;
+	}
 	list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
 		list_del(&comm->list);
 		comm__free(comm);
Signature · 1 line
1.8.3.2
#36 lore raw

[tip:perf/core] perf thread: Allow deletion of a thread with no map groups

perf thread: Allow deletion of a thread with no map groups
Commit-ID:  9608b84e4dd95341b88cad646b114811f5bccbba
Gitweb:     http://git.kernel.org/tip/9608b84e4dd95341b88cad646b114811f5bccbba
Author:     Adrian Hunter <[email protected]>
AuthorDate: Wed, 16 Jul 2014 10:19:43 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 17 Jul 2014 10:32:35 -0300

perf thread: Allow deletion of a thread with no map groups

It needs to be possible to call thread__delete() on a thread with no map groups.

This is needed for a subsequent patch which deletes a thread on the error path before map groups have been attached.

---
 tools/perf/util/thread.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
tools/perf/util/thread.c +4 -2
index 7a32f44..b9c36ef 100644
@@ -60,8 +60,10 @@ void thread__delete(struct thread *thread)
 {
 	struct comm *comm, *tmp;
 
-	map_groups__put(thread->mg);
-	thread->mg = NULL;
+	if (thread->mg) {
+		map_groups__put(thread->mg);
+		thread->mg = NULL;
+	}
 	list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
 		list_del(&comm->list);
 		comm__free(comm);
author reviewer
#37 lore raw

PATCH v2 2/2 perf tools: Fix leak of 'struct thread' on error path

In reply to Adrian Hunter

__machine__findnew_thread() creates a 'struct thread' but does not free it on the error path.

---
 tools/perf/util/machine.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +3 -1
index 5b80877..b75af25 100644
@@ -325,8 +325,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 		 * within thread__init_map_groups to find the thread
 		 * leader and that would screwed the rb tree.
 		 */
-		if (thread__init_map_groups(th, machine))
+		if (thread__init_map_groups(th, machine)) {
+			thread__delete(th);
 			return NULL;
+		}
 	}
 
 	return th;
Signature · 1 line
1.8.3.2
#38 lore raw

[tip:perf/core] perf machine: Fix leak of 'struct thread' on error path

perf machine: Fix leak of 'struct thread' on error path
Commit-ID:  418029b7324f8b90ac1dfbc8a44555d6905be761
Gitweb:     http://git.kernel.org/tip/418029b7324f8b90ac1dfbc8a44555d6905be761
Author:     Adrian Hunter <[email protected]>
AuthorDate: Wed, 16 Jul 2014 10:19:44 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 17 Jul 2014 10:34:07 -0300

perf machine: Fix leak of 'struct thread' on error path

__machine__findnew_thread() creates a 'struct thread' but does not free it on the error path. Fix it.

---
 tools/perf/util/machine.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +3 -1
index 5484fa4..93c8b6f 100644
@@ -370,8 +370,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 		 * within thread__init_map_groups to find the thread
 		 * leader and that would screwed the rb tree.
 		 */
-		if (thread__init_map_groups(th, machine))
+		if (thread__init_map_groups(th, machine)) {
+			thread__delete(th);
 			return NULL;
+		}
 	}
 
 	return th;
#39 lore raw

Re: [PATCH 12/41] perf tools: Fix leak of 'struct thread' on error path

In reply to Adrian Hunter
Quoted 30 lines · Adrian Hunter

__machine__findnew_thread() creates a 'struct thread' but does not free it on the error path.

---
 tools/perf/util/machine.c | 4 +++-
 tools/perf/util/thread.c  | 6 ++++--
 2 files changed, 7 insertions(+), 3 deletions(-)
tools/perf/util/machine.c +3 -1
index c1c5ca3..18eaf31 100644
@@ -349,8 +349,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
 		 * within thread__init_map_groups to find the thread
 		 * leader and that would screwed the rb tree.
 		 */
-		if (thread__init_map_groups(th, machine))
+		if (thread__init_map_groups(th, machine)) {
+			thread__delete(th);
 			return NULL;
+		}
 	}
 
 	return th;
tools/perf/util/thread.c +0 -0
index 149e417..b9a3ee4 100644

tools/perf/util/thread.c void thread__delete(struct thread *thread) · line 101

Quoted 9 lines
tools/perf/util/thread.c +4 -2
@@ -95,8 +95,10 @@ void thread__delete(struct thread *thread)
 {
 	struct comm *comm, *tmp;
 
-	map_groups__put(thread->mg);
-	thread->mg = NULL;
+	if (thread->mg) {
+		map_groups__put(thread->mg);
+		thread->mg = NULL;
+	}

I dont think this is ^^^ needed.. each thread has ->mg defined

jirka

author reviewer
#40 lore raw

Re: [PATCH 12/41] perf tools: Fix leak of 'struct thread' on error path

Quoted 34 lines · Jiri Olsa
Quoted 33 lines · Adrian Hunter

__machine__findnew_thread() creates a 'struct thread' but does not free it on the error path.

---
  tools/perf/util/machine.c | 4 +++-
  tools/perf/util/thread.c  | 6 ++++--
  2 files changed, 7 insertions(+), 3 deletions(-)
tools/perf/util/machine.c +3 -1
index c1c5ca3..18eaf31 100644
@@ -349,8 +349,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
  		 * within thread__init_map_groups to find the thread
  		 * leader and that would screwed the rb tree.
  		 */
-		if (thread__init_map_groups(th, machine))
+		if (thread__init_map_groups(th, machine)) {
+			thread__delete(th);
  			return NULL;
+		}
  	}
 
  	return th;
tools/perf/util/thread.c +0 -0
index 149e417..b9a3ee4 100644
@@ -95,8 +95,10 @@ void thread__delete(struct thread *thread)
  {
  	struct comm *comm, *tmp;
 
Quoted 8 lines

tools/perf/util/thread.c void thread__delete(struct thread *thread) · line 101

Quoted 6 lines
tools/perf/util/thread.c +4 -2
-	map_groups__put(thread->mg);
-	thread->mg = NULL;
+	if (thread->mg) {
+		map_groups__put(thread->mg);
+		thread->mg = NULL;
+	}

I dont think this is ^^^ needed.. each thread has ->mg defined

On the error path the thread does not yet have an mg.

author reviewer
#41 lore raw

PATCH 13/41 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 18eaf31..347ac65 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)
@@ -1474,3 +1475,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
#42 lore raw

Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()

On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:

SNIP

Quoted 12 lines
tools/perf/util/machine.c +12 -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

tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499

Quoted 10 lines
tools/perf/util/machine.c +10 -0
+	 * 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;
+}

we just recently got machine__get_kernel_start_addr function, I think we want just one function for this

jirka

author reviewer
#43 lore raw

Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()

Quoted 21 lines · Jiri Olsa

On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:

SNIP

Quoted 17 lines
tools/perf/util/machine.c +17 -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);
Quoted 8 lines

tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499

Quoted 5 lines
tools/perf/util/machine.c +5 -0
+		if (map->start)
+			machine->kernel_start = map->start;
+	}
+	return err;
+}

we just recently got machine__get_kernel_start_addr function, I think we want just one function for this

They do quite different things.

#44 lore raw

Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()

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

On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:

SNIP

Quoted 17 lines
tools/perf/util/machine.c +17 -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);
Quoted 8 lines

tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499

Quoted 5 lines
tools/perf/util/machine.c +5 -0
+		if (map->start)
+			machine->kernel_start = map->start;
+	}
+	return err;
+}

we just recently got machine__get_kernel_start_addr function, I think we want just one function for this

Quoted 2 lines

They do quite different things.

so one of those two should have different name

jirka

author reviewer
#45 lore raw

Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()

Quoted 32 lines · Jiri Olsa
Quoted 31 lines · Adrian Hunter
Quoted 29 lines · Jiri Olsa

On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:

SNIP

Quoted 12 lines
tools/perf/util/machine.c +12 -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

tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499

Quoted 10 lines
tools/perf/util/machine.c +10 -0
+	 * 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;
+}

we just recently got machine__get_kernel_start_addr function, I think we want just one function for this

Quoted 4 lines
Quoted 2 lines

They do quite different things.

so one of those two should have different name

Such as?

#46 lore raw

Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()

Quoted 33 lines · Adrian Hunter
Quoted 32 lines · Jiri Olsa
Quoted 31 lines · Adrian Hunter
Quoted 29 lines · Jiri Olsa

On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:

SNIP

Quoted 12 lines
tools/perf/util/machine.c +12 -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

tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499

Quoted 10 lines
tools/perf/util/machine.c +10 -0
+	 * 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;
+}

we just recently got machine__get_kernel_start_addr function, I think we want just one function for this

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

They do quite different things.

so one of those two should have different name

Such as?

dont know ;-) but if they do 'quite different things' as u said, I expect to see that at least in the function name

jirka

author reviewer
#47 lore raw

Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()

Quoted 37 lines · Jiri Olsa
Quoted 36 lines · Adrian Hunter
Quoted 35 lines · Jiri Olsa
Quoted 33 lines · Adrian Hunter
Quoted 21 lines · Jiri Olsa

On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:

SNIP

Quoted 17 lines
tools/perf/util/machine.c +17 -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);
Quoted 8 lines

tools/perf/util/machine.c int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too · line 1499

Quoted 5 lines
tools/perf/util/machine.c +5 -0
+		if (map->start)
+			machine->kernel_start = map->start;
+	}
+	return err;
+}

we just recently got machine__get_kernel_start_addr function, I think we want just one function for this

They do quite different things.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

so one of those two should have different name

Such as?

dont know ;-) but if they do 'quite different things' as u said, I expect to see that at least in the function name

How about:

	machine__get_kernel_start_addr -> machine__get_running_kernel_start
#48 lore raw

Re: [PATCH 13/41] perf tools: Add machine__kernel_ip()

Quoted 40 lines · Adrian Hunter
Quoted 39 lines · Jiri Olsa
Quoted 38 lines · Adrian Hunter
Quoted 36 lines · Jiri Olsa
Quoted 31 lines · Adrian Hunter
Quoted 21 lines · Jiri Olsa

On Mon, Jul 14, 2014 at 01:02:37PM +0300, Adrian Hunter wrote:

SNIP

Quoted 17 lines
(quoted diff) +17 -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);
Quoted 8 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+		if (map->start)
+			machine->kernel_start = map->start;
+	}
+	return err;
+}

we just recently got machine__get_kernel_start_addr function, I think we want just one function for this

Quoted 2 lines

They do quite different things.

so one of those two should have different name

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

Such as?

dont know ;-) but if they do 'quite different things' as u said, I expect to see that at least in the function name

How about:

	machine__get_kernel_start_addr -> machine__get_running_kernel_start

sounds good

jirka

author reviewer
#49 lore raw

PATCH 14/41 perf buildid-cache: Apply force option to copying kcore

In reply to Adrian Hunter

Currently a copy of kcore is not made if there is one already with the same modules at the same addresses. Change this to make a copy anyway if the force (-f) option is also used.

---
 tools/perf/builtin-buildid-cache.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
tools/perf/builtin-buildid-cache.c +5 -3
index b22dbb1..2a2c78f 100644
@@ -125,7 +125,8 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
 	return ret;
 }
 
-static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
+static int build_id_cache__add_kcore(const char *filename, const char *debugdir,
+				     bool force)
 {
 	char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
 	char from_dir[PATH_MAX], to_dir[PATH_MAX];
@@ -144,7 +145,8 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
 	scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
 		  debugdir, sbuildid);
 
-	if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
+	if (!force &&
+	    !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
 		pr_debug("same kcore found in %s\n", to_dir);
 		return 0;
 	}
@@ -389,7 +391,7 @@ int cmd_buildid_cache(int argc, const char **argv,
 	}
 
 	if (kcore_filename &&
-	    build_id_cache__add_kcore(kcore_filename, debugdir))
+	    build_id_cache__add_kcore(kcore_filename, debugdir, force))
 		pr_warning("Couldn't add %s\n", kcore_filename);
 
 	return ret;
Signature · 1 line
1.8.3.2
#50 lore raw

[tip:perf/core] perf buildid-cache: Apply force option to copying kcore

perf buildid-cache: Apply force option to copying kcore
Commit-ID:  5173fbb8a11b2857aeec9e5f4e9568d4e1b84dbd
Gitweb:     http://git.kernel.org/tip/5173fbb8a11b2857aeec9e5f4e9568d4e1b84dbd
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:38 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:35 -0300

perf buildid-cache: Apply force option to copying kcore

Currently a copy of kcore is not made if there is one already with the same modules at the same addresses.

Change this to make a copy anyway if the force (-f) option is also used.

---
 tools/perf/builtin-buildid-cache.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
tools/perf/builtin-buildid-cache.c +5 -3
index b22dbb1..2a2c78f 100644
@@ -125,7 +125,8 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
 	return ret;
 }
 
-static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
+static int build_id_cache__add_kcore(const char *filename, const char *debugdir,
+				     bool force)
 {
 	char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
 	char from_dir[PATH_MAX], to_dir[PATH_MAX];
@@ -144,7 +145,8 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
 	scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
 		  debugdir, sbuildid);
 
-	if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
+	if (!force &&
+	    !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
 		pr_debug("same kcore found in %s\n", to_dir);
 		return 0;
 	}
@@ -389,7 +391,7 @@ int cmd_buildid_cache(int argc, const char **argv,
 	}
 
 	if (kcore_filename &&
-	    build_id_cache__add_kcore(kcore_filename, debugdir))
+	    build_id_cache__add_kcore(kcore_filename, debugdir, force))
 		pr_warning("Couldn't add %s\n", kcore_filename);
 
 	return ret;
author reviewer
#51 lore raw

PATCH 15/41 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
#52 lore raw

Re: [PATCH 15/41] perf script: Improve srcline display for BTS

Em Mon, Jul 14, 2014 at 01:02:39PM +0300, Adrian Hunter escreveu:

Quoted 10 lines

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

David,

Can I have your acked-by?

Adrian,

Can you elaborate on why this is an improvement?

- Arnaldo

Quoted 49 lines
---
 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
author reviewer
#53 lore raw

Re: [PATCH 15/41] perf script: Improve srcline display for BTS

Quoted 12 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 14, 2014 at 01:02:39PM +0300, Adrian Hunter escreveu:

Quoted 10 lines

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

Quoted 7 lines

David,

Can I have your acked-by?

Adrian,

Can you elaborate on why this is an improvement?

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.

Quoted 52 lines

- Arnaldo

Quoted 49 lines
---
  tools/perf/builtin-script.c | 20 +++++++++++++++-----
  1 file changed, 15 insertions(+), 5 deletions(-)
tools/perf/builtin-script.c +15 -6
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");
  }
 
--

1.8.3.2

#54 lore raw

Re: [PATCH 15/41] perf script: Improve srcline display for BTS

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

Em Mon, Jul 14, 2014 at 01:02:39PM +0300, Adrian Hunter escreveu:

Quoted 6 lines

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)

Quoted 8 lines
Quoted 4 lines

new format:

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

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

David,

Can I have your acked-by?

I believe Stephane is the one who wrote print_sample_bts and bts analysis pieces.

David

author reviewer
#55 lore raw

PATCH 16/41 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
author reviewer
#56 lore raw

PATCH 17/41 perf tools: Record whether a dso is 64-bit

In reply to Adrian Hunter

Add a flag to 'struct dso' to record if the dso is 64-bit or not. Update the flag when reading the ELF.

This is needed for instruction decoding. For example, x86 instruction decoding depends on whether or not the 64-bit instruction set is used.

---
 tools/perf/util/dso.c            |  1 +
 tools/perf/util/dso.h            |  1 +
 tools/perf/util/symbol-elf.c     |  3 +++
 tools/perf/util/symbol-minimal.c | 22 ++++++++++++++++++++++
 tools/perf/util/symbol.c         |  1 +
 tools/perf/util/symbol.h         |  1 +
 6 files changed, 29 insertions(+)
tools/perf/util/dso.c +1 -0
index 819f104..fc006fe 100644
@@ -703,6 +703,7 @@ struct dso *dso__new(const char *name)
 		dso->data.fd = -1;
 		dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
 		dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
+		dso->is_64_bit = (sizeof(void *) == 8);
 		dso->loaded = 0;
 		dso->rel = 0;
 		dso->sorted_by_name = 0;
tools/perf/util/dso.h +1 -0
index ad553ba..c239e86 100644
@@ -90,6 +90,7 @@ struct dso {
 	u8		 annotate_warned:1;
 	u8		 short_name_allocated:1;
 	u8		 long_name_allocated:1;
+	u8		 is_64_bit:1;
 	u8		 sorted_by_name;
 	u8		 loaded;
 	u8		 rel;
tools/perf/util/symbol-elf.c +3 -0
index 477596c..84f5e2a 100644
@@ -599,6 +599,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 			goto out_elf_end;
 	}
 
+	ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
+
 	ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab",
 			NULL);
 	if (ss->symshdr.sh_type != SHT_SYMTAB)
@@ -699,6 +701,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
 	bool remap_kernel = false, adjust_kernel_syms = false;
 
 	dso->symtab_type = syms_ss->type;
+	dso->is_64_bit = syms_ss->is_64_bit;
 	dso->rel = syms_ss->ehdr.e_type == ET_REL;
 
 	/*
tools/perf/util/symbol-minimal.c +22 -0
index bd15f49..101f55d 100644
@@ -288,6 +288,23 @@ int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
 	return 0;
 }
 
+static int fd__is_64_bit(int fd)
+{
+	u8 e_ident[EI_NIDENT];
+
+	if (lseek(fd, 0, SEEK_SET))
+		return -1;
+
+	if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
+		return -1;
+
+	if (memcmp(e_ident, ELFMAG, SELFMAG) ||
+	    e_ident[EI_VERSION] != EV_CURRENT)
+		return -1;
+
+	return e_ident[EI_CLASS] == ELFCLASS64;
+}
+
 int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
 		  struct symsrc *ss,
 		  struct symsrc *runtime_ss __maybe_unused,
@@ -295,6 +312,11 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
 		  int kmodule __maybe_unused)
 {
 	unsigned char *build_id[BUILD_ID_SIZE];
+	int ret;
+
+	ret = fd__is_64_bit(ss->fd);
+	if (ret >= 0)
+		dso->is_64_bit = ret;
 
 	if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
 		dso__set_build_id(dso, build_id);
tools/perf/util/symbol.c +1 -0
index 7b9096f..be7b0df 100644
@@ -1064,6 +1064,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
 			      &is_64_bit);
 	if (err)
 		goto out_err;
+	dso->is_64_bit = is_64_bit;
 
 	if (list_empty(&md.maps)) {
 		err = -EINVAL;
tools/perf/util/symbol.h +1 -0
index 615c752..6ba8a22 100644
@@ -215,6 +215,7 @@ struct symsrc {
 	GElf_Shdr dynshdr;
 
 	bool adjust_symbols;
+	bool is_64_bit;
 #endif
 };
 
Signature · 1 line
1.8.3.2
#57 lore raw

[tip:perf/core] perf symbols: Record whether a dso is 64-bit

perf symbols: Record whether a dso is 64-bit
Commit-ID:  c6d8f2a4a0c5e366330a6a2a94c06b652f4ca554
Gitweb:     http://git.kernel.org/tip/c6d8f2a4a0c5e366330a6a2a94c06b652f4ca554
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:41 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:35 -0300

perf symbols: Record whether a dso is 64-bit

Add a flag to 'struct dso' to record if the dso is 64-bit or not. Update the flag when reading the ELF.

This is needed for instruction decoding. For example, x86 instruction decoding depends on whether or not the 64-bit instruction set is used.

---
 tools/perf/util/dso.c            |  1 +
 tools/perf/util/dso.h            |  1 +
 tools/perf/util/symbol-elf.c     |  3 +++
 tools/perf/util/symbol-minimal.c | 22 ++++++++++++++++++++++
 tools/perf/util/symbol.c         |  1 +
 tools/perf/util/symbol.h         |  1 +
 6 files changed, 29 insertions(+)
tools/perf/util/dso.c +1 -0
index 819f104..fc006fe 100644
@@ -703,6 +703,7 @@ struct dso *dso__new(const char *name)
 		dso->data.fd = -1;
 		dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
 		dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
+		dso->is_64_bit = (sizeof(void *) == 8);
 		dso->loaded = 0;
 		dso->rel = 0;
 		dso->sorted_by_name = 0;
tools/perf/util/dso.h +1 -0
index ad553ba..c239e86 100644
@@ -90,6 +90,7 @@ struct dso {
 	u8		 annotate_warned:1;
 	u8		 short_name_allocated:1;
 	u8		 long_name_allocated:1;
+	u8		 is_64_bit:1;
 	u8		 sorted_by_name;
 	u8		 loaded;
 	u8		 rel;
tools/perf/util/symbol-elf.c +3 -0
index dce5ccf..cef8f42 100644
@@ -599,6 +599,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 			goto out_elf_end;
 	}
 
+	ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
+
 	ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab",
 			NULL);
 	if (ss->symshdr.sh_type != SHT_SYMTAB)
@@ -699,6 +701,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
 	bool remap_kernel = false, adjust_kernel_syms = false;
 
 	dso->symtab_type = syms_ss->type;
+	dso->is_64_bit = syms_ss->is_64_bit;
 	dso->rel = syms_ss->ehdr.e_type == ET_REL;
 
 	/*
tools/perf/util/symbol-minimal.c +22 -0
index bd15f49..101f55d 100644
@@ -288,6 +288,23 @@ int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
 	return 0;
 }
 
+static int fd__is_64_bit(int fd)
+{
+	u8 e_ident[EI_NIDENT];
+
+	if (lseek(fd, 0, SEEK_SET))
+		return -1;
+
+	if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
+		return -1;
+
+	if (memcmp(e_ident, ELFMAG, SELFMAG) ||
+	    e_ident[EI_VERSION] != EV_CURRENT)
+		return -1;
+
+	return e_ident[EI_CLASS] == ELFCLASS64;
+}
+
 int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
 		  struct symsrc *ss,
 		  struct symsrc *runtime_ss __maybe_unused,
@@ -295,6 +312,11 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
 		  int kmodule __maybe_unused)
 {
 	unsigned char *build_id[BUILD_ID_SIZE];
+	int ret;
+
+	ret = fd__is_64_bit(ss->fd);
+	if (ret >= 0)
+		dso->is_64_bit = ret;
 
 	if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
 		dso__set_build_id(dso, build_id);
tools/perf/util/symbol.c +1 -0
index 2e6a2e2..ae2e446 100644
@@ -1065,6 +1065,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
 			      &is_64_bit);
 	if (err)
 		goto out_err;
+	dso->is_64_bit = is_64_bit;
 
 	if (list_empty(&md.maps)) {
 		err = -EINVAL;
tools/perf/util/symbol.h +1 -0
index a81877b..436169d 100644
@@ -216,6 +216,7 @@ struct symsrc {
 	GElf_Shdr dynshdr;
 
 	bool adjust_symbols;
+	bool is_64_bit;
 #endif
 };
 
author reviewer
#58 lore raw

PATCH 18/41 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) as follows:

	dso->data_status	meaning
	----------------------------------
	0			don't know
	-1			no data
	1			has data
---
 tools/perf/util/dso.c | 5 ++++-
 tools/perf/util/dso.h | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/dso.c +4 -1
index fc006fe..91a4eb4 100644
@@ -556,8 +556,11 @@ static ssize_t data_read_offset(struct dso *dso, u64 offset,
 ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
 			      u64 offset, u8 *data, ssize_t size)
 {
-	if (dso__data_fd(dso, machine) < 0)
+	if (dso__data_fd(dso, machine) < 0) {
+		dso->data.data_status = -1;
 		return -1;
+	}
+	dso->data.data_status = 1;
 
 	return data_read_offset(dso, offset, data, size);
 }
tools/perf/util/dso.h +1 -0
index c239e86..c5257aa 100644
@@ -104,6 +104,7 @@ struct dso {
 	struct {
 		struct rb_root	 cache;
 		int		 fd;
+		int		 data_status;
 		size_t		 file_size;
 		struct list_head open_entry;
 	} data;
Signature · 1 line
1.8.3.2
#59 lore raw

Re: [PATCH 18/41] perf tools: Record whether a dso has data

Quoted 8 lines · Adrian Hunter

Add 'data_status' to record whether a dso has data (i.e. an object file) as follows:

	dso->data_status	meaning
	----------------------------------
	0			don't know
	-1			no data
	1			has data

please add enum for this

Quoted 12 lines
---
 tools/perf/util/dso.c | 5 ++++-
 tools/perf/util/dso.h | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/dso.c +0 -0
index fc006fe..91a4eb4 100644

tools/perf/util/dso.c static ssize_t data_read_offset(struct dso *dso, u64 offset, · line 563

Quoted 9 lines
tools/perf/util/dso.c +4 -1
@@ -556,8 +556,11 @@ static ssize_t data_read_offset(struct dso *dso, u64 offset,
 ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
 			      u64 offset, u8 *data, ssize_t size)
 {
-	if (dso__data_fd(dso, machine) < 0)
+	if (dso__data_fd(dso, machine) < 0) {
+		dso->data.data_status = -1;
 		return -1;
+	}
+	dso->data.data_status = 1;

we have more callers to dso__data_fd, so I think we want to setup dso->data.data_status within dso__data_fd

jirka

author reviewer
#60 lore raw

cover perf tools: Fix incorrect fd error comparison

Quoted 10 lines · Adrian Hunter
Quoted 8 lines

Add 'data_status' to record whether a dso has data (i.e. an object file) as follows:

	dso->data_status	meaning
	----------------------------------
	0			don't know
	-1			no data
	1			has data

please add enum for this

Ok

Quoted 17 lines
Quoted 17 lines
---
 tools/perf/util/dso.c | 5 ++++-
 tools/perf/util/dso.h | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/dso.c +0 -1
index fc006fe..91a4eb4 100644
@@ -556,8 +556,11 @@ static ssize_t data_read_offset(struct dso *dso, u64 offset,
 ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
 			      u64 offset, u8 *data, ssize_t size)
 {
-	if (dso__data_fd(dso, machine) < 0)
Quoted 8 lines

tools/perf/util/dso.c static ssize_t data_read_offset(struct dso *dso, u64 offset, · line 563

Quoted 5 lines
tools/perf/util/dso.c +4 -0
+	if (dso__data_fd(dso, machine) < 0) {
+		dso->data.data_status = -1;
 		return -1;
+	}
+	dso->data.data_status = 1;

we have more callers to dso__data_fd, so I think we want to setup dso->data.data_status within dso__data_fd

Ok. Here are 2 patches because I noticed another thing.

Adrian Hunter (2):
perf tools: Fix incorrect fd error comparison perf tools: Record whether a dso has data

 tools/perf/util/dso.c | 27 +++++++++++++++++----------
 tools/perf/util/dso.h |  7 +++++++
 2 files changed, 24 insertions(+), 10 deletions(-)
author reviewer
#61 lore raw

PATCH 1/2 perf tools: Fix incorrect fd error comparison

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
#63 lore raw

[tip:perf/core] perf tools: Fix incorrect fd error comparison

In reply to Adrian Hunter
perf tools: Fix incorrect fd error comparison
Commit-ID:  a6f6ae99f12e8154d5cde6e8366fc228f68d6ae5
Gitweb:     http://git.kernel.org/tip/a6f6ae99f12e8154d5cde6e8366fc228f68d6ae5
Author:     Adrian Hunter <[email protected]>
AuthorDate: Thu, 17 Jul 2014 11:43:09 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 22 Jul 2014 10:18:57 -0300

perf tools: Fix incorrect fd error comparison

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
author reviewer
#64 lore raw

PATCH v2 2/2 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) as follows:

	dso->data_status	meaning
	----------------------------------
	0			don't know
	-1			no data
	1			has data
---
 tools/perf/util/dso.c | 25 ++++++++++++++++---------
 tools/perf/util/dso.h |  7 +++++++
 2 files changed, 23 insertions(+), 9 deletions(-)
tools/perf/util/dso.c +16 -9
index 28cf747..af274f0 100644
@@ -332,25 +332,28 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
 	int i = 0;
 
 	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.data_status = DSO_DATA_STATUS_OK;
+	else
+		dso->data.data_status = DSO_DATA_STATUS_ERROR;
 
-	return -EINVAL;
+	return dso->data.fd;
 }
 
 static void
@@ -556,8 +559,11 @@ static ssize_t data_read_offset(struct dso *dso, u64 offset,
 ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
 			      u64 offset, u8 *data, ssize_t size)
 {
-	if (dso__data_fd(dso, machine) < 0)
+	if (dso__data_fd(dso, machine) < 0) {
+		dso->data.data_status = -1;
 		return -1;
+	}
+	dso->data.data_status = 1;
 
 	return data_read_offset(dso, offset, data, size);
 }
@@ -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.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..07d0a58 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		 data_status;
 		size_t		 file_size;
 		struct list_head open_entry;
 	} data;
Signature · 1 line
1.8.3.2
author reviewer
#65 lore raw

PATCH v3 1/1 perf tools: Record whether a dso has data

Add 'data_status' to record whether a dso has data (i.e. an object file)

---
 tools/perf/util/dso.c | 20 ++++++++++++--------
 tools/perf/util/dso.h |  7 +++++++
 2 files changed, 19 insertions(+), 8 deletions(-)
tools/perf/util/dso.c +12 -8
index 28cf747..08eb028 100644
@@ -332,25 +332,28 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
 	int i = 0;
 
 	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.data_status = DSO_DATA_STATUS_OK;
+	else
+		dso->data.data_status = DSO_DATA_STATUS_ERROR;
 
-	return -EINVAL;
+	return dso->data.fd;
 }
 
 static void
@@ -701,6 +704,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.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..07d0a58 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		 data_status;
 		size_t		 file_size;
 		struct list_head open_entry;
 	} data;
Signature · 1 line
1.8.3.2
#66 lore raw

Re: [PATCH V3] perf tools: Record whether a dso has data

Quoted 2 lines · Adrian Hunter

Add 'data_status' to record whether a dso has data (i.e. an object file)

I might have seen it in your last patsent, but forgot.. what is this data_status going to be used for?

SNIP

Quoted 18 lines
tools/perf/util/dso.h +6 -0
index c239e86..07d0a58 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;				\

tools/perf/util/dso.h struct dso { · line 113

Quoted 4 lines
tools/perf/util/dso.h +1 -0
@@ -104,6 +110,7 @@ struct dso {
 	struct {
 		struct rb_root	 cache;
 		int		 fd;
+		int		 data_status;

also please call it just 'status' it's already in 'data' struct

thanks,
jirka

author reviewer
#67 lore raw

Re: [PATCH V3] perf tools: Record whether a dso has data

Quoted 6 lines · Jiri Olsa
Quoted 2 lines · Adrian Hunter

Add 'data_status' to record whether a dso has data (i.e. an object file)

I might have seen it in your last patsent, but forgot.. what is this data_status going to be used for?

I have changed it a bit in the latest posting. It was originally for two purposes:
1. to prevent repeatedly attempting to open a file that
was not there (very time consuming if you do it millions of times)
2. to report the error exactly once

But I realized it did not meet the 2nd objective so I have added another patch that does. See "perf tools: Add dso__data_status_seen()"

Quoted 11 lines

SNIP

Quoted 8 lines
tools/perf/util/dso.h +0 -0
index c239e86..07d0a58 100644
@@ -40,6 +40,12 @@ enum dso_swap_type {
 	DSO_SWAP__YES,
 };
 
Quoted 16 lines
Quoted 10 lines
tools/perf/util/dso.h +6 -0
+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;				\

tools/perf/util/dso.h struct dso { · line 113

Quoted 4 lines
tools/perf/util/dso.h +1 -0
@@ -104,6 +110,7 @@ struct dso {
 	struct {
 		struct rb_root	 cache;
 		int		 fd;
+		int		 data_status;

also please call it just 'status' it's already in 'data' struct

I made that change too.

author reviewer
#68 lore raw

PATCH 19/41 perf tools: Do not attempt to read data from kallsyms

In reply to Adrian Hunter

Record kallsyms binary type so that tools will not attempt to read binary data from it.

---
 tools/perf/util/symbol.c | 2 ++
 1 file changed, 2 insertions(+)
tools/perf/util/symbol.c +2 -0
index be7b0df..21b2e45 100644
@@ -1663,6 +1663,7 @@ do_kallsyms:
 	free(kallsyms_allocated_filename);
 
 	if (err > 0 && !dso__is_kcore(dso)) {
+		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
 		dso__set_long_name(dso, "[kernel.kallsyms]", false);
 		map__fixup_start(map);
 		map__fixup_end(map);
@@ -1710,6 +1711,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
 	if (err > 0)
 		pr_debug("Using %s for symbols\n", kallsyms_filename);
 	if (err > 0 && !dso__is_kcore(dso)) {
+		dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
 		machine__mmap_name(machine, path, sizeof(path));
 		dso__set_long_name(dso, strdup(path), true);
 		map__fixup_start(map);
Signature · 1 line
1.8.3.2
#69 lore raw

[tip:perf/core] perf symbols: Do not attempt to read data from kallsyms

perf symbols: Do not attempt to read data from kallsyms
Commit-ID:  bdac0bcf779250e89b96d4a3f381ebaf02c2f4a9
Gitweb:     http://git.kernel.org/tip/bdac0bcf779250e89b96d4a3f381ebaf02c2f4a9
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:43 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:35 -0300

perf symbols: Do not attempt to read data from kallsyms

Record kallsyms binary type so that tools will not attempt to read binary data from it.

---
 tools/perf/util/symbol.c | 2 ++
 1 file changed, 2 insertions(+)
tools/perf/util/symbol.c +2 -0
index ae2e446..156ae36 100644
@@ -1664,6 +1664,7 @@ do_kallsyms:
 	free(kallsyms_allocated_filename);
 
 	if (err > 0 && !dso__is_kcore(dso)) {
+		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
 		dso__set_long_name(dso, "[kernel.kallsyms]", false);
 		map__fixup_start(map);
 		map__fixup_end(map);
@@ -1711,6 +1712,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
 	if (err > 0)
 		pr_debug("Using %s for symbols\n", kallsyms_filename);
 	if (err > 0 && !dso__is_kcore(dso)) {
+		dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
 		machine__mmap_name(machine, path, sizeof(path));
 		dso__set_long_name(dso, strdup(path), true);
 		map__fixup_start(map);
author reviewer
#70 lore raw

PATCH 20/41 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
#71 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

Quoted 10 lines · 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.

I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?

thanks,
jirka

author reviewer
#72 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

Quoted 7 lines · Jiri Olsa
Quoted 6 lines · Adrian Hunter

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

	pmu//

which is effectively the same as:

Quoted 7 lines
Quoted 4 lines
	pmu/config=0/

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

I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?

Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.

#73 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

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

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

	pmu//

which is effectively the same as:

	pmu/config=0/
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

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

I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?

Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.

right, so why do we want to parse 'pmu//' as an event string? ;-)

jirka

author reviewer
#74 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

Quoted 14 lines · Jiri Olsa
Quoted 13 lines · Adrian Hunter
Quoted 12 lines · Jiri Olsa
Quoted 10 lines · 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.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?

Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.

right, so why do we want to parse 'pmu//' as an event string? ;-)

I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'

The parser uses various tricks to decide what kind of event the event name actually is e.g. colons indicate a tracepoint.

If you are asking why the parser isn't smart enough to know the event name is a PMU name, I guess it is either to keep the namespaces separate, or because it was easier to program it that way.

#75 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

Quoted 18 lines · Adrian Hunter
Quoted 17 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 14 lines · Jiri Olsa
Quoted 10 lines · 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.

I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.

right, so why do we want to parse 'pmu//' as an event string? ;-)

I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'

so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//

which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/

I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:

krava alias: "tsc=1,noretcomp=0"

-e intel_pt/krava/

which gives the same result

thanks,
jirka

author reviewer
#76 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

Quoted 35 lines · Jiri Olsa
Quoted 18 lines · Adrian Hunter
Quoted 17 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 14 lines · Jiri Olsa
Quoted 10 lines · 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.

I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.

right, so why do we want to parse 'pmu//' as an event string? ;-)

I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'

so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//

which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/

Quoted 8 lines

I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:

krava alias: "tsc=1,noretcomp=0"

-e intel_pt/krava/

which gives the same result

The default value must be provided by perf tools not the kernel e.g. an older version of perf tools will not be aware of new hardware features that the kernel may know about. If the kernel enables new features by default then the tool may fail. Thus the default value has to be under the control of the tools not the kernel, so a sysfs alias will not work.

#77 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

Quoted 43 lines · Adrian Hunter
Quoted 42 lines · Jiri Olsa
Quoted 18 lines · Adrian Hunter
Quoted 17 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 14 lines · Jiri Olsa
Quoted 10 lines · 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.

I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.

right, so why do we want to parse 'pmu//' as an event string? ;-)

I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'

so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//

which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/

I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:

krava alias: "tsc=1,noretcomp=0"

-e intel_pt/krava/

Quoted 9 lines
Quoted 1 line

which gives the same result

The default value must be provided by perf tools not the kernel e.g. an older version of perf tools will not be aware of new hardware features that the kernel may know about. If the kernel enables new features by default then the tool may fail. Thus the default value has to be under the control of the tools not the kernel, so a sysfs alias will not work.

I dont follow, could u provide some example?

why the tool needs to understand.. it will just take the alias and apply/use it? The alias follows the format logic, which tells how to apply values on perf_event_attr.. and the kernel knows best what's supported in its version..

jirka

author reviewer
#78 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

Quoted 54 lines · Jiri Olsa
Quoted 43 lines · Adrian Hunter
Quoted 42 lines · Jiri Olsa
Quoted 18 lines · Adrian Hunter
Quoted 17 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 14 lines · Jiri Olsa
Quoted 10 lines · 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.

I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.

right, so why do we want to parse 'pmu//' as an event string? ;-)

I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'

so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//

which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/

I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:

krava alias: "tsc=1,noretcomp=0"

-e intel_pt/krava/

Quoted 9 lines
Quoted 1 line

which gives the same result

The default value must be provided by perf tools not the kernel e.g. an older version of perf tools will not be aware of new hardware features that the kernel may know about. If the kernel enables new features by default then the tool may fail. Thus the default value has to be under the control of the tools not the kernel, so a sysfs alias will not work.

Quoted 1 line

I dont follow, could u provide some example?

Imagine that the 'tsc' term did not exist. Intel PT trace data would not contain TSC packets, and the decoder would not know how to decode them. Then imagine that a new version of the hardware adds 'tsc'. It is such a useful feature that we want it by default, but older versions of the tools don't know how to decode it, so the kernel cannot turn it on by default.

Quoted 5 lines

why the tool needs to understand.. it will just take the alias and apply/use it? The alias follows the format logic, which tells how to apply values on perf_event_attr.. and the kernel knows best what's supported in its version..

It is similar to why the kernel does not select mmap2 by default. The kernel doesn't know whether the tool supports it.

#79 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

On Tue, Sep 02, 2014 at 08:39:56AM +0300, Adrian Hunter wrote:

SNIP

Quoted 29 lines
Quoted 19 lines
Quoted 9 lines
Quoted 9 lines

-e intel_pt/tsc=1,noretcomp=0/

I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:

krava alias: "tsc=1,noretcomp=0"

-e intel_pt/krava/

Quoted 9 lines
Quoted 1 line

which gives the same result

The default value must be provided by perf tools not the kernel e.g. an older version of perf tools will not be aware of new hardware features that the kernel may know about. If the kernel enables new features by default then the tool may fail. Thus the default value has to be under the control of the tools not the kernel, so a sysfs alias will not work.

Quoted 1 line

I dont follow, could u provide some example?

Imagine that the 'tsc' term did not exist. Intel PT trace data would not contain TSC packets, and the decoder would not know how to decode them. Then imagine that a new version of the hardware adds 'tsc'. It is such a useful feature that we want it by default, but older versions of the tools don't know how to decode it, so the kernel cannot turn it on by default.

Quoted 1 line
Quoted 8 lines
Quoted 4 lines

why the tool needs to understand.. it will just take the alias and apply/use it? The alias follows the format logic, which tells how to apply values on perf_event_attr.. and the kernel knows best what's supported in its version..

It is similar to why the kernel does not select mmap2 by default. The kernel doesn't know whether the tool supports it.

ook, could you please add some kind of this explanation to the changelog?

thanks,
jirka

#80 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

In reply to Jiri Olsa

Em Sat, Aug 30, 2014 at 10:53:10AM +0200, Jiri Olsa escreveu:

Quoted 35 lines · Adrian Hunter
Quoted 18 lines · Jiri Olsa
Quoted 16 lines · Adrian Hunter
Quoted 15 lines · Jiri Olsa
Quoted 14 lines · Adrian Hunter
Quoted 10 lines

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.

I understand the need for default config, but could you please elaborate why do we want to parse 'pmu//' as an event string string?

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Currently the parser requires the slashes to identify a PMU event as opposed to a hardware or other kind of event.

right, so why do we want to parse 'pmu//' as an event string? ;-)

I am not sure what you mean. Here I am using 'pmu' as a placeholder for a real PMU name. So actual event strings are 'intel_bts//' or 'intel_pt//' or 'intel_pt/tsc=0,noretcomp=1/'

so the consequence of default arguments is that you can specify event just by the pmu name, like:
-e intel_pt//

which means (with default attributes):
-e intel_pt/tsc=1,noretcomp=0/

Quoted 8 lines

I guess I wanted to hear more elaboration why is this better than the current way we have by defining an alias, like:

krava alias: "tsc=1,noretcomp=0"

-e intel_pt/krava/

which gives the same result

So you propose that we start maintaining some table of aliases that would be installed by default, etc? "krava" would not be a good name, I think (:-)), so in this case we would have something like:

	defaults_intel_pt: "tsc=1,noretcomp=0"

	-e intel_pt/defaults_intel_pt/

Which of course gets redundant/long, so, using what Adrian suggests, we would instead not pass anything between the slashes, and that would mean "default_" concatenated with the name of the PMU used, so it would become:

	-e intel_pt//

that would be equivalent to:

-e intel_pt/defaults_intel_pt/

and also to:

	-e intel_pt/tsc=1,noretcomp=0/

?

I have not looked at the implementation, this is all just from the information I skimmed in this thread.

- Arnaldo

#81 lore raw

Re: [PATCH 20/41] perf tools: Let a user specify a PMU event without any config terms

On Mon, Sep 01, 2014 at 12:51:42PM -0300, Arnaldo Carvalho de Melo wrote:

SNIP

Quoted 25 lines
Quoted 5 lines

krava alias: "tsc=1,noretcomp=0"

-e intel_pt/krava/

which gives the same result

So you propose that we start maintaining some table of aliases that would be installed by default, etc? "krava" would not be a good name, I think (:-)), so in this case we would have something like:

	defaults_intel_pt: "tsc=1,noretcomp=0"

	-e intel_pt/defaults_intel_pt/

Which of course gets redundant/long, so, using what Adrian suggests, we would instead not pass anything between the slashes, and that would mean "default_" concatenated with the name of the PMU used, so it would become:

	-e intel_pt//

that would be equivalent to:

-e intel_pt/defaults_intel_pt/

Quoted 8 lines

and also to:

	-e intel_pt/tsc=1,noretcomp=0/

?

I have not looked at the implementation, this is all just from the information I skimmed in this thread.

well I meant that we already have following directory:
/sys/devices/cpu/events

for aliases.. files with format definitions (even partial) I can imagine 'default' file there doing the same job for the default format set

but I just could be missing something which is not apparent from changelog ;-)

jirka

author reviewer
#82 lore raw

PATCH 21/41 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
#83 lore raw

PATCH 22/41 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
author reviewer
#84 lore raw

PATCH 23/41 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
author reviewer
#85 lore raw

PATCH 24/41 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 b9a3ee4..2f8c0c1 100644
@@ -69,6 +69,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 b4269af..e4920ff 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
#86 lore raw

Re: [PATCH 24/41] perf tools: Add cpu to struct thread

Em Mon, Jul 14, 2014 at 01:02:48PM +0300, Adrian Hunter escreveu:

Quoted 6 lines

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.

Humm, is this the last cpu we got some event telling the cpu was running on? Continuing looking at the patches...

- Arnaldo

Quoted 32 lines
---
 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 b9a3ee4..2f8c0c1 100644
@@ -69,6 +69,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 b4269af..e4920ff 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
author reviewer
#87 lore raw

Re: [PATCH 24/41] perf tools: Add cpu to struct thread

Quoted 10 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 14, 2014 at 01:02:48PM +0300, Adrian Hunter escreveu:

Quoted 6 lines

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.

Humm, is this the last cpu we got some event telling the cpu was running on? Continuing looking at the patches...

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

Quoted 35 lines

- Arnaldo

Quoted 32 lines
---
  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 b9a3ee4..2f8c0c1 100644
@@ -69,6 +69,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 -1
index b4269af..e4920ff 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 */
--

1.8.3.2

author reviewer
#88 lore raw

PATCH 25/41 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 347ac65..8d9e4a7 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)
@@ -1497,3 +1500,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
author reviewer
#89 lore raw

PATCH 26/41 perf tools: Add ability to iterate over a dso's symbols

In reply to Adrian Hunter

Expose dso__first_symbol() and dso__next_symbol() to make it possible to iterate over a dso's symbols.

---
 tools/perf/util/symbol.c | 17 ++++++++++++++++-
 tools/perf/util/symbol.h |  3 +++
 2 files changed, 19 insertions(+), 1 deletion(-)
tools/perf/util/symbol.c +16 -1
index 21b2e45..d5dc547 100644
@@ -341,6 +341,16 @@ static struct symbol *symbols__first(struct rb_root *symbols)
 	return NULL;
 }
 
+static struct symbol *symbols__next(struct symbol *sym)
+{
+	struct rb_node *n = rb_next(&sym->rb_node);
+
+	if (n)
+		return rb_entry(n, struct symbol, rb_node);
+
+	return NULL;
+}
+
 struct symbol_name_rb_node {
 	struct rb_node	rb_node;
 	struct symbol	sym;
@@ -411,11 +421,16 @@ struct symbol *dso__find_symbol(struct dso *dso,
 	return symbols__find(&dso->symbols[type], addr);
 }
 
-static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
+struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
 {
 	return symbols__first(&dso->symbols[type]);
 }
 
+struct symbol *dso__next_symbol(struct symbol *sym)
+{
+	return symbols__next(sym);
+}
+
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
 					const char *name)
 {
tools/perf/util/symbol.h +3 -0
index 6ba8a22..e1350bc 100644
@@ -239,6 +239,9 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
 					const char *name);
 
+struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
+struct symbol *dso__next_symbol(struct symbol *sym);
+
 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
#90 lore raw

[tip:perf/core] perf symbols: Add ability to iterate over a dso' s symbols

perf symbols: Add ability to iterate over a dso's symbols
Commit-ID:  9c00a81b6aafc4ed375a43e7a54e6cf2d720c7c6
Gitweb:     http://git.kernel.org/tip/9c00a81b6aafc4ed375a43e7a54e6cf2d720c7c6
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:50 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:35 -0300

perf symbols: Add ability to iterate over a dso's symbols

Expose dso__first_symbol() and dso__next_symbol() to make it possible to iterate over a dso's symbols.

---
 tools/perf/util/symbol.c | 17 ++++++++++++++++-
 tools/perf/util/symbol.h |  3 +++
 2 files changed, 19 insertions(+), 1 deletion(-)
tools/perf/util/symbol.c +16 -1
index 156ae36..eb06746 100644
@@ -342,6 +342,16 @@ static struct symbol *symbols__first(struct rb_root *symbols)
 	return NULL;
 }
 
+static struct symbol *symbols__next(struct symbol *sym)
+{
+	struct rb_node *n = rb_next(&sym->rb_node);
+
+	if (n)
+		return rb_entry(n, struct symbol, rb_node);
+
+	return NULL;
+}
+
 struct symbol_name_rb_node {
 	struct rb_node	rb_node;
 	struct symbol	sym;
@@ -412,11 +422,16 @@ struct symbol *dso__find_symbol(struct dso *dso,
 	return symbols__find(&dso->symbols[type], addr);
 }
 
-static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
+struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
 {
 	return symbols__first(&dso->symbols[type]);
 }
 
+struct symbol *dso__next_symbol(struct symbol *sym)
+{
+	return symbols__next(sym);
+}
+
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
 					const char *name)
 {
tools/perf/util/symbol.h +3 -0
index 436169d..ee2d3cc 100644
@@ -240,6 +240,9 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
 					const char *name);
 
+struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
+struct symbol *dso__next_symbol(struct symbol *sym);
+
 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
#91 lore raw

PATCH 27/41 perf session: Flag if the event stream is entirely in memory

In reply to Adrian Hunter

Flag if the event stream is a file that has been mmapped in one go.

This is useful, for example, if a tool needs to keep an event for later reference. If the new flag is set, a pointer to the event can be retained, otherwise the event must be copied.

---
 tools/perf/util/session.c | 9 ++++++++-
 tools/perf/util/session.h | 3 +++
 2 files changed, 11 insertions(+), 1 deletion(-)
tools/perf/util/session.c +8 -1
index c1abe6b..7b0fb03 100644
@@ -1319,8 +1319,10 @@ int __perf_session__process_events(struct perf_session *session,
 	ui_progress__init(&prog, file_size, "Processing events...");
 
 	mmap_size = MMAP_SIZE;
-	if (mmap_size > file_size)
+	if (mmap_size > file_size) {
 		mmap_size = file_size;
+		session->one_mmap = true;
+	}
 
 	memset(mmaps, 0, sizeof(mmaps));
 
@@ -1342,6 +1344,10 @@ remap:
 	mmaps[map_idx] = buf;
 	map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1);
 	file_pos = file_offset + head;
+	if (session->one_mmap) {
+		session->one_mmap_addr = buf;
+		session->one_mmap_offset = file_offset;
+	}
 
 more:
 	event = fetch_mmaped_event(session, head, mmap_size, buf);
@@ -1387,6 +1393,7 @@ out_err:
 	ui_progress__finish();
 	perf_session__warn_about_errors(session, tool);
 	perf_session_free_sample_buffers(session);
+	session->one_mmap = false;
 	return err;
 }
 
tools/perf/util/session.h +3 -0
index 3140f8a..0321013 100644
@@ -36,6 +36,9 @@ struct perf_session {
 	struct trace_event	tevent;
 	struct events_stats	stats;
 	bool			repipe;
+	bool			one_mmap;
+	void			*one_mmap_addr;
+	u64			one_mmap_offset;
 	struct ordered_samples	ordered_samples;
 	struct perf_data_file	*file;
 };
Signature · 1 line
1.8.3.2
#92 lore raw

[tip:perf/core] perf session: Flag if the event stream is entirely in memory

perf session: Flag if the event stream is entirely in memory
Commit-ID:  919d86d3a3109d7d4f0d7347f34711ee2f8e6609
Gitweb:     http://git.kernel.org/tip/919d86d3a3109d7d4f0d7347f34711ee2f8e6609
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:51 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:36 -0300

perf session: Flag if the event stream is entirely in memory

Flag if the event stream is a file that has been mmapped in one go.

This is useful, for example, if a tool needs to keep an event for later reference. If the new flag is set, a pointer to the event can be retained, otherwise the event must be copied.

---
 tools/perf/util/session.c | 9 ++++++++-
 tools/perf/util/session.h | 3 +++
 2 files changed, 11 insertions(+), 1 deletion(-)
tools/perf/util/session.c +8 -1
index c2f4ca9..eac14ce 100644
@@ -1297,8 +1297,10 @@ int __perf_session__process_events(struct perf_session *session,
 	ui_progress__init(&prog, file_size, "Processing events...");
 
 	mmap_size = MMAP_SIZE;
-	if (mmap_size > file_size)
+	if (mmap_size > file_size) {
 		mmap_size = file_size;
+		session->one_mmap = true;
+	}
 
 	memset(mmaps, 0, sizeof(mmaps));
 
@@ -1320,6 +1322,10 @@ remap:
 	mmaps[map_idx] = buf;
 	map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1);
 	file_pos = file_offset + head;
+	if (session->one_mmap) {
+		session->one_mmap_addr = buf;
+		session->one_mmap_offset = file_offset;
+	}
 
 more:
 	event = fetch_mmaped_event(session, head, mmap_size, buf);
@@ -1365,6 +1371,7 @@ out_err:
 	ui_progress__finish();
 	perf_session__warn_about_errors(session, tool);
 	perf_session_free_sample_buffers(session);
+	session->one_mmap = false;
 	return err;
 }
 
tools/perf/util/session.h +3 -0
index 3140f8a..0321013 100644
@@ -36,6 +36,9 @@ struct perf_session {
 	struct trace_event	tevent;
 	struct events_stats	stats;
 	bool			repipe;
+	bool			one_mmap;
+	void			*one_mmap_addr;
+	u64			one_mmap_offset;
 	struct ordered_samples	ordered_samples;
 	struct perf_data_file	*file;
 };
author reviewer
#93 lore raw

PATCH 28/41 perf evlist: Pass mmap parameters in a struct

In reply to Adrian Hunter

In preparation for adding more mmap parameters, pass existing parameters in a struct.

---
 tools/perf/util/evlist.c | 46 ++++++++++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 20 deletions(-)
tools/perf/util/evlist.c +26 -20
index c51223a..814e954 100644
@@ -606,12 +606,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 	return evlist->mmap != NULL ? 0 : -ENOMEM;
 }
 
-static int __perf_evlist__mmap(struct perf_evlist *evlist,
-			       int idx, int prot, int mask, int fd)
+struct mmap_params {
+	int prot;
+	int mask;
+};
+
+static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
+			       struct mmap_params *mp, int fd)
 {
 	evlist->mmap[idx].prev = 0;
-	evlist->mmap[idx].mask = mask;
-	evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
+	evlist->mmap[idx].mask = mp->mask;
+	evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
 				      MAP_SHARED, fd, 0);
 	if (evlist->mmap[idx].base == MAP_FAILED) {
 		pr_debug2("failed to mmap perf event ring buffer, error %d\n",
@@ -625,8 +630,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
 }
 
 static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
-				       int prot, int mask, int cpu, int thread,
-				       int *output)
+				       struct mmap_params *mp, int cpu,
+				       int thread, int *output)
 {
 	struct perf_evsel *evsel;
 
@@ -635,8 +640,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
 
 		if (*output == -1) {
 			*output = fd;
-			if (__perf_evlist__mmap(evlist, idx, prot, mask,
-						*output) < 0)
+			if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0)
 				return -1;
 		} else {
 			if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
@@ -651,8 +655,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
 	return 0;
 }
 
-static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
-				     int mask)
+static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
+				     struct mmap_params *mp)
 {
 	int cpu, thread;
 	int nr_cpus = cpu_map__nr(evlist->cpus);
@@ -663,8 +667,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
 		int output = -1;
 
 		for (thread = 0; thread < nr_threads; thread++) {
-			if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask,
-							cpu, thread, &output))
+			if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
+							thread, &output))
 				goto out_unmap;
 		}
 	}
@@ -677,8 +681,8 @@ out_unmap:
 	return -1;
 }
 
-static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
-					int mask)
+static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
+					struct mmap_params *mp)
 {
 	int thread;
 	int nr_threads = thread_map__nr(evlist->threads);
@@ -687,8 +691,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
 	for (thread = 0; thread < nr_threads; thread++) {
 		int output = -1;
 
-		if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0,
-						thread, &output))
+		if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
+						&output))
 			goto out_unmap;
 	}
 
@@ -793,7 +797,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	struct perf_evsel *evsel;
 	const struct cpu_map *cpus = evlist->cpus;
 	const struct thread_map *threads = evlist->threads;
-	int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
+	struct mmap_params mp = {
+		.prot = PROT_READ | (overwrite ? 0 : PROT_WRITE),
+	};
 
 	if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
 		return -ENOMEM;
@@ -804,7 +810,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	evlist->overwrite = overwrite;
 	evlist->mmap_len = perf_evlist__mmap_size(pages);
 	pr_debug("mmap size %zuB\n", evlist->mmap_len);
-	mask = evlist->mmap_len - page_size - 1;
+	mp.mask = evlist->mmap_len - page_size - 1;
 
 	evlist__for_each(evlist, evsel) {
 		if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -814,9 +820,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	}
 
 	if (cpu_map__empty(cpus))
-		return perf_evlist__mmap_per_thread(evlist, prot, mask);
+		return perf_evlist__mmap_per_thread(evlist, &mp);
 
-	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
+	return perf_evlist__mmap_per_cpu(evlist, &mp);
 }
 
 int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
Signature · 1 line
1.8.3.2
#94 lore raw

[tip:perf/core] perf evlist: Pass mmap parameters in a struct

perf evlist: Pass mmap parameters in a struct
Commit-ID:  a8a8f3eb5de55aeaf007c18572668e8ec463547b
Gitweb:     http://git.kernel.org/tip/a8a8f3eb5de55aeaf007c18572668e8ec463547b
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:52 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:36 -0300

perf evlist: Pass mmap parameters in a struct

In preparation for adding more mmap parameters, pass existing parameters in a struct.

---
 tools/perf/util/evlist.c | 46 ++++++++++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 20 deletions(-)
tools/perf/util/evlist.c +26 -20
index c51223a..814e954 100644
@@ -606,12 +606,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 	return evlist->mmap != NULL ? 0 : -ENOMEM;
 }
 
-static int __perf_evlist__mmap(struct perf_evlist *evlist,
-			       int idx, int prot, int mask, int fd)
+struct mmap_params {
+	int prot;
+	int mask;
+};
+
+static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
+			       struct mmap_params *mp, int fd)
 {
 	evlist->mmap[idx].prev = 0;
-	evlist->mmap[idx].mask = mask;
-	evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
+	evlist->mmap[idx].mask = mp->mask;
+	evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
 				      MAP_SHARED, fd, 0);
 	if (evlist->mmap[idx].base == MAP_FAILED) {
 		pr_debug2("failed to mmap perf event ring buffer, error %d\n",
@@ -625,8 +630,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
 }
 
 static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
-				       int prot, int mask, int cpu, int thread,
-				       int *output)
+				       struct mmap_params *mp, int cpu,
+				       int thread, int *output)
 {
 	struct perf_evsel *evsel;
 
@@ -635,8 +640,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
 
 		if (*output == -1) {
 			*output = fd;
-			if (__perf_evlist__mmap(evlist, idx, prot, mask,
-						*output) < 0)
+			if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0)
 				return -1;
 		} else {
 			if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
@@ -651,8 +655,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
 	return 0;
 }
 
-static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
-				     int mask)
+static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
+				     struct mmap_params *mp)
 {
 	int cpu, thread;
 	int nr_cpus = cpu_map__nr(evlist->cpus);
@@ -663,8 +667,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
 		int output = -1;
 
 		for (thread = 0; thread < nr_threads; thread++) {
-			if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask,
-							cpu, thread, &output))
+			if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
+							thread, &output))
 				goto out_unmap;
 		}
 	}
@@ -677,8 +681,8 @@ out_unmap:
 	return -1;
 }
 
-static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
-					int mask)
+static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
+					struct mmap_params *mp)
 {
 	int thread;
 	int nr_threads = thread_map__nr(evlist->threads);
@@ -687,8 +691,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
 	for (thread = 0; thread < nr_threads; thread++) {
 		int output = -1;
 
-		if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0,
-						thread, &output))
+		if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
+						&output))
 			goto out_unmap;
 	}
 
@@ -793,7 +797,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	struct perf_evsel *evsel;
 	const struct cpu_map *cpus = evlist->cpus;
 	const struct thread_map *threads = evlist->threads;
-	int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
+	struct mmap_params mp = {
+		.prot = PROT_READ | (overwrite ? 0 : PROT_WRITE),
+	};
 
 	if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
 		return -ENOMEM;
@@ -804,7 +810,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	evlist->overwrite = overwrite;
 	evlist->mmap_len = perf_evlist__mmap_size(pages);
 	pr_debug("mmap size %zuB\n", evlist->mmap_len);
-	mask = evlist->mmap_len - page_size - 1;
+	mp.mask = evlist->mmap_len - page_size - 1;
 
 	evlist__for_each(evlist, evsel) {
 		if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -814,9 +820,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	}
 
 	if (cpu_map__empty(cpus))
-		return perf_evlist__mmap_per_thread(evlist, prot, mask);
+		return perf_evlist__mmap_per_thread(evlist, &mp);
 
-	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
+	return perf_evlist__mmap_per_cpu(evlist, &mp);
 }
 
 int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
author reviewer
#95 lore raw

PATCH 29/41 perf tools: Add feature test for __sync_val_compare_and_swap

In reply to Adrian Hunter

Add a feature test for __sync_val_compare_and_swap() and __sync_bool_compare_and_swap()

---
 tools/perf/config/Makefile                                 |  6 ++++++
 tools/perf/config/feature-checks/Makefile                  |  4 ++++
 tools/perf/config/feature-checks/test-all.c                |  5 +++++
 .../config/feature-checks/test-sync-compare-and-swap.c     | 14 ++++++++++++++
 4 files changed, 29 insertions(+)
 create mode 100644 tools/perf/config/feature-checks/test-sync-compare-and-swap.c
tools/perf/config/Makefile +6 -0
index 346bdb6..a0e1329 100644
@@ -164,6 +164,7 @@ CORE_FEATURE_TESTS =			\
 	backtrace			\
 	dwarf				\
 	fortify-source			\
+	sync-compare-and-swap		\
 	glibc				\
 	gtk2				\
 	gtk2-infobar			\
@@ -199,6 +200,7 @@ LIB_FEATURE_TESTS =			\
 VF_FEATURE_TESTS =			\
 	backtrace			\
 	fortify-source			\
+	sync-compare-and-swap		\
 	gtk2-infobar			\
 	libelf-getphdrnum		\
 	libelf-mmap			\
@@ -272,6 +274,10 @@ CFLAGS += -I$(LIB_INCLUDE)
 
 CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 
+ifeq ($(feature-sync-compare-and-swap), 1)
+  CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT
+endif
+
 ifndef NO_BIONIC
   $(call feature_check,bionic)
   ifeq ($(feature-bionic), 1)
tools/perf/config/feature-checks/Makefile +4 -0
index 64c84e5..6088f8d 100644
@@ -5,6 +5,7 @@ FILES=					\
 	test-bionic.bin			\
 	test-dwarf.bin			\
 	test-fortify-source.bin		\
+	test-sync-compare-and-swap.bin	\
 	test-glibc.bin			\
 	test-gtk2.bin			\
 	test-gtk2-infobar.bin		\
@@ -141,6 +142,9 @@ test-timerfd.bin:
 test-libdw-dwarf-unwind.bin:
 	$(BUILD)
 
+test-sync-compare-and-swap.bin:
+	$(BUILD) -Werror
+
 -include *.d
 
 ###############################
tools/perf/config/feature-checks/test-all.c +5 -0
index fe5c1e5..a7d022e 100644
@@ -89,6 +89,10 @@
 # include "test-libdw-dwarf-unwind.c"
 #undef main
 
+#define main main_test_sync_compare_and_swap
+# include "test-sync-compare-and-swap.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
 	main_test_libpython();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])
 	main_test_timerfd();
 	main_test_stackprotector_all();
 	main_test_libdw_dwarf_unwind();
+	main_test_sync_compare_and_swap(argc, argv);
 
 	return 0;
 }
tools/perf/config/feature-checks/test-sync-compare-and-swap.c new file +14 -0
new file mode 100644
index 0000000..c34d4ca
@@ -0,0 +1,14 @@
+#include <stdint.h>
+
+volatile uint64_t x;
+
+int main(int argc, char *argv[])
+{
+	uint64_t old, new = argc;
+
+	argv = argv;
+	do {
+		old = __sync_val_compare_and_swap(&x, 0, 0);
+	} while (!__sync_bool_compare_and_swap(&x, old, new));
+	return old == new;
+}
Signature · 1 line
1.8.3.2
#96 lore raw

[tip:perf/core] perf tools: Add feature test for __sync_val_compare_and_swap

perf tools: Add feature test for __sync_val_compare_and_swap
Commit-ID:  f6d313699a9612a30fabe05bf2c9302c1408b5cf
Gitweb:     http://git.kernel.org/tip/f6d313699a9612a30fabe05bf2c9302c1408b5cf
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:53 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:36 -0300

perf tools: Add feature test for __sync_val_compare_and_swap

Add a feature test for __sync_val_compare_and_swap() and __sync_bool_compare_and_swap()

---
 tools/perf/config/Makefile                                 |  6 ++++++
 tools/perf/config/feature-checks/Makefile                  |  4 ++++
 tools/perf/config/feature-checks/test-all.c                |  5 +++++
 .../config/feature-checks/test-sync-compare-and-swap.c     | 14 ++++++++++++++
 4 files changed, 29 insertions(+)
tools/perf/config/Makefile +6 -0
index b7f42d5..1f67aa0 100644
@@ -164,6 +164,7 @@ CORE_FEATURE_TESTS =			\
 	backtrace			\
 	dwarf				\
 	fortify-source			\
+	sync-compare-and-swap		\
 	glibc				\
 	gtk2				\
 	gtk2-infobar			\
@@ -199,6 +200,7 @@ LIB_FEATURE_TESTS =			\
 VF_FEATURE_TESTS =			\
 	backtrace			\
 	fortify-source			\
+	sync-compare-and-swap		\
 	gtk2-infobar			\
 	libelf-getphdrnum		\
 	libelf-mmap			\
@@ -272,6 +274,10 @@ CFLAGS += -I$(LIB_INCLUDE)
 
 CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 
+ifeq ($(feature-sync-compare-and-swap), 1)
+  CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT
+endif
+
 ifndef NO_BIONIC
   $(call feature_check,bionic)
   ifeq ($(feature-bionic), 1)
tools/perf/config/feature-checks/Makefile +4 -0
index 64c84e5..6088f8d 100644
@@ -5,6 +5,7 @@ FILES=					\
 	test-bionic.bin			\
 	test-dwarf.bin			\
 	test-fortify-source.bin		\
+	test-sync-compare-and-swap.bin	\
 	test-glibc.bin			\
 	test-gtk2.bin			\
 	test-gtk2-infobar.bin		\
@@ -141,6 +142,9 @@ test-timerfd.bin:
 test-libdw-dwarf-unwind.bin:
 	$(BUILD)
 
+test-sync-compare-and-swap.bin:
+	$(BUILD) -Werror
+
 -include *.d
 
 ###############################
tools/perf/config/feature-checks/test-all.c +5 -0
index fe5c1e5..a7d022e 100644
@@ -89,6 +89,10 @@
 # include "test-libdw-dwarf-unwind.c"
 #undef main
 
+#define main main_test_sync_compare_and_swap
+# include "test-sync-compare-and-swap.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
 	main_test_libpython();
@@ -111,6 +115,7 @@ int main(int argc, char *argv[])
 	main_test_timerfd();
 	main_test_stackprotector_all();
 	main_test_libdw_dwarf_unwind();
+	main_test_sync_compare_and_swap(argc, argv);
 
 	return 0;
 }
tools/perf/config/feature-checks/test-sync-compare-and-swap.c new file +14 -0
new file mode 100644
index 0000000..c34d4ca
@@ -0,0 +1,14 @@
+#include <stdint.h>
+
+volatile uint64_t x;
+
+int main(int argc, char *argv[])
+{
+	uint64_t old, new = argc;
+
+	argv = argv;
+	do {
+		old = __sync_val_compare_and_swap(&x, 0, 0);
+	} while (!__sync_bool_compare_and_swap(&x, old, new));
+	return old == new;
+}
author reviewer
#97 lore raw

PATCH 30/41 perf tools: Add option macro OPT_CALLBACK_OPTARG

In reply to Adrian Hunter

Add an option macro that is the same as OPT_CALLBACK except that the argument is optional and it is possible to associate additional data with it.

---
 tools/perf/util/parse-options.h | 5 +++++
 1 file changed, 5 insertions(+)
tools/perf/util/parse-options.h +5 -0
index d8dac8a..b59ba85 100644
@@ -98,6 +98,7 @@ struct option {
 	parse_opt_cb *callback;
 	intptr_t defval;
 	bool *set;
+	void *data;
 };
 
 #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
@@ -131,6 +132,10 @@ struct option {
 	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
 	.value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
 	.flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
+#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
+	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
+	  .value = (v), (a), .help = (h), .callback = (f), \
+	  .flags = PARSE_OPT_OPTARG, .data = (d) }
 
 /* parse_options() will filter out the processed options and leave the
  * non-option argments in argv[].
Signature · 1 line
1.8.3.2
#98 lore raw

[tip:perf/core] perf tools: Add option macro OPT_CALLBACK_OPTARG

perf tools: Add option macro OPT_CALLBACK_OPTARG
Commit-ID:  ea8e08a16a1e6566be3f775c0bd351fa52ab6b9d
Gitweb:     http://git.kernel.org/tip/ea8e08a16a1e6566be3f775c0bd351fa52ab6b9d
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:54 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:36 -0300

perf tools: Add option macro OPT_CALLBACK_OPTARG

Add an option macro that is the same as OPT_CALLBACK except that the argument is optional and it is possible to associate additional data with it.

---
 tools/perf/util/parse-options.h | 5 +++++
 1 file changed, 5 insertions(+)
tools/perf/util/parse-options.h +5 -0
index d8dac8a..b59ba85 100644
@@ -98,6 +98,7 @@ struct option {
 	parse_opt_cb *callback;
 	intptr_t defval;
 	bool *set;
+	void *data;
 };
 
 #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
@@ -131,6 +132,10 @@ struct option {
 	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
 	.value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
 	.flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
+#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
+	{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
+	  .value = (v), (a), .help = (h), .callback = (f), \
+	  .flags = PARSE_OPT_OPTARG, .data = (d) }
 
 /* parse_options() will filter out the processed options and leave the
  * non-option argments in argv[].
author reviewer
#99 lore raw

PATCH 31/41 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
author reviewer
#100 lore raw

PATCH 32/41 perf evsel: Add 'no_aux_samples' option

In reply to Adrian Hunter

Add an option to prevent additional samples being added to a selected event by perf_evsel__config().

This is needed when using the sched_switch tracepoint to follow object code execution. Since sched_switch will be used only for switch information, additional sampling is wasteful.

---
 tools/perf/util/evsel.c | 6 +++---
 tools/perf/util/evsel.h | 1 +
 2 files changed, 4 insertions(+), 3 deletions(-)
tools/perf/util/evsel.c +3 -3
index b760d32..40626e5 100644
@@ -623,7 +623,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 		attr->mmap_data = track;
 	}
 
-	if (opts->call_graph_enabled)
+	if (opts->call_graph_enabled && !evsel->no_aux_samples)
 		perf_evsel__config_callgraph(evsel, opts);
 
 	if (target__has_cpu(&opts->target))
@@ -637,7 +637,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 	     target__has_cpu(&opts->target) || per_cpu))
 		perf_evsel__set_sample_bit(evsel, TIME);
 
-	if (opts->raw_samples) {
+	if (opts->raw_samples && !evsel->no_aux_samples) {
 		perf_evsel__set_sample_bit(evsel, TIME);
 		perf_evsel__set_sample_bit(evsel, RAW);
 		perf_evsel__set_sample_bit(evsel, CPU);
@@ -650,7 +650,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 		attr->watermark = 0;
 		attr->wakeup_events = 1;
 	}
-	if (opts->branch_stack) {
+	if (opts->branch_stack && !evsel->no_aux_samples) {
 		perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
 		attr->branch_sample_type = opts->branch_stack;
 	}
tools/perf/util/evsel.h +1 -0
index a52e9a5..8dfec05 100644
@@ -83,6 +83,7 @@ struct perf_evsel {
 	int			is_pos;
 	bool 			supported;
 	bool 			needs_swap;
+	bool			no_aux_samples;
 	/* parse modifier helper */
 	int			exclude_GH;
 	int			nr_members;
Signature · 1 line
1.8.3.2
#101 lore raw

[tip:perf/core] perf evsel: Add 'no_aux_samples' option

perf evsel: Add 'no_aux_samples' option
Commit-ID:  6ff1ce763921f605aaf98c7a828b7df24d6923dc
Gitweb:     http://git.kernel.org/tip/6ff1ce763921f605aaf98c7a828b7df24d6923dc
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:56 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:36 -0300

perf evsel: Add 'no_aux_samples' option

Add an option to prevent additional samples being added to a selected event by perf_evsel__config().

This is needed when using the sched_switch tracepoint to follow object code execution. Since sched_switch will be used only for switch information, additional sampling is wasteful.

---
 tools/perf/util/evsel.c | 6 +++---
 tools/perf/util/evsel.h | 1 +
 2 files changed, 4 insertions(+), 3 deletions(-)
tools/perf/util/evsel.c +3 -3
index b760d32..40626e5 100644
@@ -623,7 +623,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 		attr->mmap_data = track;
 	}
 
-	if (opts->call_graph_enabled)
+	if (opts->call_graph_enabled && !evsel->no_aux_samples)
 		perf_evsel__config_callgraph(evsel, opts);
 
 	if (target__has_cpu(&opts->target))
@@ -637,7 +637,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 	     target__has_cpu(&opts->target) || per_cpu))
 		perf_evsel__set_sample_bit(evsel, TIME);
 
-	if (opts->raw_samples) {
+	if (opts->raw_samples && !evsel->no_aux_samples) {
 		perf_evsel__set_sample_bit(evsel, TIME);
 		perf_evsel__set_sample_bit(evsel, RAW);
 		perf_evsel__set_sample_bit(evsel, CPU);
@@ -650,7 +650,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 		attr->watermark = 0;
 		attr->wakeup_events = 1;
 	}
-	if (opts->branch_stack) {
+	if (opts->branch_stack && !evsel->no_aux_samples) {
 		perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
 		attr->branch_sample_type = opts->branch_stack;
 	}
tools/perf/util/evsel.h +1 -0
index a52e9a5..8dfec05 100644
@@ -83,6 +83,7 @@ struct perf_evsel {
 	int			is_pos;
 	bool 			supported;
 	bool 			needs_swap;
+	bool			no_aux_samples;
 	/* parse modifier helper */
 	int			exclude_GH;
 	int			nr_members;
author reviewer
#102 lore raw

PATCH 33/41 perf evsel: Add 'immediate' option

In reply to Adrian Hunter

Add an option to cause a selected event to be enabled immediately when configured by perf_evsel__config().

This is needed when using the sched_switch tracepoint to follow object code execution. By having sched_switch enabled immediately the first sched_switch event precedes the start of other tracing.

---
 tools/perf/util/evsel.c | 5 +++++
 tools/perf/util/evsel.h | 1 +
 2 files changed, 6 insertions(+)
tools/perf/util/evsel.c +5 -0
index 40626e5..90f58cd 100644
@@ -681,6 +681,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 	if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) &&
 		!opts->initial_delay)
 		attr->enable_on_exec = 1;
+
+	if (evsel->immediate) {
+		attr->disabled = 0;
+		attr->enable_on_exec = 0;
+	}
 }
 
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
tools/perf/util/evsel.h +1 -0
index 8dfec05..d7f93ce 100644
@@ -84,6 +84,7 @@ struct perf_evsel {
 	bool 			supported;
 	bool 			needs_swap;
 	bool			no_aux_samples;
+	bool			immediate;
 	/* parse modifier helper */
 	int			exclude_GH;
 	int			nr_members;
Signature · 1 line
1.8.3.2
#103 lore raw

[tip:perf/core] perf evsel: Add 'immediate' option

perf evsel: Add 'immediate' option
Commit-ID:  2afd2bcfc3a026d6e4c2184bf41ccd74eb05758b
Gitweb:     http://git.kernel.org/tip/2afd2bcfc3a026d6e4c2184bf41ccd74eb05758b
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:02:57 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 16 Jul 2014 17:57:37 -0300

perf evsel: Add 'immediate' option

Add an option to cause a selected event to be enabled immediately when configured by perf_evsel__config().

This is needed when using the sched_switch tracepoint to follow object code execution. By having sched_switch enabled immediately the first sched_switch event precedes the start of other tracing.

---
 tools/perf/util/evsel.c | 5 +++++
 tools/perf/util/evsel.h | 1 +
 2 files changed, 6 insertions(+)
tools/perf/util/evsel.c +5 -0
index 40626e5..90f58cd 100644
@@ -681,6 +681,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 	if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) &&
 		!opts->initial_delay)
 		attr->enable_on_exec = 1;
+
+	if (evsel->immediate) {
+		attr->disabled = 0;
+		attr->enable_on_exec = 0;
+	}
 }
 
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
tools/perf/util/evsel.h +1 -0
index 8dfec05..d7f93ce 100644
@@ -84,6 +84,7 @@ struct perf_evsel {
 	bool 			supported;
 	bool 			needs_swap;
 	bool			no_aux_samples;
+	bool			immediate;
 	/* parse modifier helper */
 	int			exclude_GH;
 	int			nr_members;
author reviewer
#104 lore raw

PATCH 34/41 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 90f58cd..7540b5f 100644
@@ -691,6 +691,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) {
@@ -709,6 +713,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),
@@ -739,6 +746,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;
@@ -783,6 +793,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));
@@ -871,6 +884,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++) {
@@ -993,13 +1009,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 = 0;
 	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) {
@@ -1021,10 +1042,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);
@@ -1094,7 +1115,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
#105 lore raw

Re: [PATCH 34/41] perf evlist: Add 'system_wide' option

Em Mon, Jul 14, 2014 at 01:02:58PM +0300, Adrian Hunter escreveu:

Quoted 4 lines

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

Quoted 9 lines

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.

clever, but humm, need to be judicious when allocating things like the pollfd, I think, more below...

... after going thru the whole patch, its not clear how pollfd usage takes into account the fact that some of the evsels don't have thread_map->nr entries, but just one, will continue reading...

Quoted 79 lines
---
 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 +19 -4
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);
 

tools/perf/util/evlist.c int perf_evlist__enable_event(struct perf_evlist *evlist, · line 350

Quoted 10 lines
tools/perf/util/evlist.c +2 -2
 	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)

All the above seems ok, the threads (x axis) array is flat when syswide, ok.

Quoted 4 lines
tools/perf/util/evlist.c +0 -0
@@ -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);

tools/perf/util/evlist.c static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) · line 369

Quoted 10 lines
tools/perf/util/evlist.c +9 -1
-	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;
+	}

But here looks tricky, will look how the evlist->pollfd is used...

tools/perf/util/evlist.c static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, · line 666

Quoted 13 lines
tools/perf/util/evlist.c +5 -1
+
 	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;

Discard after thread 0, i.e. the first, ok.

Quoted 10 lines
tools/perf/util/evlist.c +2 -0
+
+		fd = FD(evsel, cpu, thread);
 
 		if (*output == -1) {
 			*output = fd;
tools/perf/util/evsel.c +0 -0
index 90f58cd..7540b5f 100644

tools/perf/util/evsel.c void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) · line 696

Quoted 6 lines
tools/perf/util/evsel.c +3 -0
@@ -691,6 +691,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;

flatten it, ok

tools/perf/util/evsel.c static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea · line 718

Quoted 11 lines
tools/perf/util/evsel.c +4 -0
+
 	evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
 
 	if (evsel->fd) {
@@ -709,6 +713,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
 {
 	int cpu, thread;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+

Ditto.

tools/perf/util/evsel.c int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) · line 752

Quoted 11 lines
tools/perf/util/evsel.c +3 -0
 	for (cpu = 0; cpu < ncpus; cpu++) {
 		for (thread = 0; thread < nthreads; thread++) {
 			int fd = FD(evsel, cpu, thread),
@@ -739,6 +746,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));

These are per evsel, so can be flattened when we get to it,
evlist->pollfd is per evlist, so mixes syswide with !syswide, that is why I'm scratching my head at this point...

Quoted 79 lines
tools/perf/util/evsel.c +16 -5
 	if (evsel->sample_id == NULL)
 		return -ENOMEM;
@@ -783,6 +793,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));
@@ -871,6 +884,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++) {
@@ -993,13 +1009,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 = 0;
 	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) {
@@ -1021,10 +1042,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);
@@ -1094,7 +1115,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
#106 lore raw

Re: [PATCH 34/41] perf evlist: Add 'system_wide' option

Quoted 185 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 14, 2014 at 01:02:58PM +0300, Adrian Hunter escreveu:

Quoted 4 lines

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

Quoted 9 lines

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.

clever, but humm, need to be judicious when allocating things like the pollfd, I think, more below...

... after going thru the whole patch, its not clear how pollfd usage takes into account the fact that some of the evsels don't have thread_map->nr entries, but just one, will continue reading...

Quoted 79 lines
---
  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 +19 -4
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);
 

tools/perf/util/evlist.c int perf_evlist__enable_event(struct perf_evlist *evlist, · line 350

Quoted 10 lines
tools/perf/util/evlist.c +2 -2
  	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)

All the above seems ok, the threads (x axis) array is flat when syswide, ok.

Quoted 4 lines
tools/perf/util/evlist.c +0 -0
@@ -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);

tools/perf/util/evlist.c static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) · line 369

Quoted 10 lines
tools/perf/util/evlist.c +9 -1
-	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;
+	}

But here looks tricky, will look how the evlist->pollfd is used...

tools/perf/util/evlist.c static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, · line 666

Quoted 13 lines
tools/perf/util/evlist.c +5 -1
+
  	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;

Discard after thread 0, i.e. the first, ok.

Quoted 10 lines
tools/perf/util/evlist.c +2 -0
+
+		fd = FD(evsel, cpu, thread);
 
  		if (*output == -1) {
  			*output = fd;
tools/perf/util/evsel.c +0 -0
index 90f58cd..7540b5f 100644

tools/perf/util/evsel.c void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) · line 696

Quoted 6 lines
tools/perf/util/evsel.c +3 -0
@@ -691,6 +691,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;

flatten it, ok

tools/perf/util/evsel.c static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea · line 718

Quoted 11 lines
tools/perf/util/evsel.c +4 -0
+
  	evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
 
  	if (evsel->fd) {
@@ -709,6 +713,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
  {
  	int cpu, thread;
 
+	if (evsel->system_wide)
+		nthreads = 1;
+

Ditto.

Quoted 5 lines
tools/perf/util/evsel.c +0 -0
  	for (cpu = 0; cpu < ncpus; cpu++) {
  		for (thread = 0; thread < nthreads; thread++) {
  			int fd = FD(evsel, cpu, thread),
@@ -739,6 +746,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
 
Quoted 10 lines

tools/perf/util/evsel.c int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) · line 752

Quoted 6 lines
tools/perf/util/evsel.c +3 -0
  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));

These are per evsel, so can be flattened when we get to it,
evlist->pollfd is per evlist, so mixes syswide with !syswide, that is why I'm scratching my head at this point...

pollfd is not a 2-dimensional array. It is just a 1-dimensional array. So it just needs to be the right length.

Quoted 80 lines
Quoted 80 lines
tools/perf/util/evsel.c +16 -5
  	if (evsel->sample_id == NULL)
  		return -ENOMEM;
@@ -783,6 +793,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));
@@ -871,6 +884,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++) {
@@ -993,13 +1009,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 = 0;
  	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) {
@@ -1021,10 +1042,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);
@@ -1094,7 +1115,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 -1
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;
--

1.8.3.2

#107 lore raw

Re: [PATCH 34/41] perf evlist: Add 'system_wide' option

In reply to Adrian Hunter
Quoted 27 lines · 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 +0 -0
index 282e83e..c295b7b 100644
@@ -265,17 +265,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
 	return 0;

tools/perf/util/evlist.c int perf_evlist__add_newtp(struct perf_evlist *evlist, · line 275

Quoted 10 lines
tools/perf/util/evlist.c +8 -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);
+}

how is 'evsel->system_wide' set?

jirka

author reviewer
#108 lore raw

Re: [PATCH 34/41] perf evlist: Add 'system_wide' option

Quoted 30 lines · Jiri Olsa
Quoted 29 lines · 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 +0 -0
index 282e83e..c295b7b 100644
@@ -265,17 +265,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
 	return 0;
 }
 
Quoted 10 lines

tools/perf/util/evlist.c int perf_evlist__add_newtp(struct perf_evlist *evlist, · line 275

Quoted 8 lines
tools/perf/util/evlist.c +8 -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);
+}

how is 'evsel->system_wide' set?

Intel PT sets it for the sched_switch event.

author reviewer
#109 lore raw

PATCH 35/41 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
#110 lore raw

PATCH 36/41 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
#111 lore raw

PATCH 37/41 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
author reviewer
#112 lore raw

PATCH 38/41 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
#113 lore raw

Re: [PATCH 38/41] perf session: Add perf_session__deliver_synth_event()

Em Mon, Jul 14, 2014 at 01:03:02PM +0300, Adrian Hunter escreveu:

Quoted 2 lines

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

Why not put this in perf_session_deliver_event (and fix its naming, renaming it to perf_session__deliver_event)?

The way you did makes me wonder why you want to fallback to perf_session_deliver_event, i.e. would a normal event come thru a function which name implies it should be used only for synth events?

Also that events_stats__inc() looks suspicious there :-\

- Arnaldo

Quoted 49 lines
---
 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
#114 lore raw

Re: [PATCH 38/41] perf session: Add perf_session__deliver_synth_event()

Quoted 4 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 14, 2014 at 01:03:02PM +0300, Adrian Hunter escreveu:

Quoted 2 lines

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

Quoted 8 lines

Why not put this in perf_session_deliver_event (and fix its naming, renaming it to perf_session__deliver_event)?

The way you did makes me wonder why you want to fallback to perf_session_deliver_event, i.e. would a normal event come thru a function which name implies it should be used only for synth events?

Also that events_stats__inc() looks suspicious there :-\

What happens is Intel PT (or Intel BTS) data is decoded which results in (mostly) branch data. So "branches" events are synthesized and injected into the event stream using perf_session__deliver_synth_event().

The structure of perf_session__deliver_synth_event() reflects the fact that "user" events (not from the kernel) are processed differently to "real" events (from the kernel or synthesized).

The synthesized branches events are then consumed by the tools just as though they came directly from the perf.data file
- so updating stats is normal.

Quoted 52 lines

- Arnaldo

Quoted 49 lines
---
  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 -1
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);
--

1.8.3.2

author reviewer
#115 lore raw

PATCH 39/41 perf tools: Allow TSC conversion on any arch

In reply to Adrian Hunter

It is possible to record a perf.data file on
one architecture and process it on another.
Consequently, TSC conversion functions need
to be moved out of the arch directory.

---
 tools/perf/Makefile.perf            |  2 ++
 tools/perf/arch/x86/util/tsc.c      | 22 +---------------------
 tools/perf/arch/x86/util/tsc.h      |  3 ---
 tools/perf/tests/perf-time-to-tsc.c |  3 +--
 tools/perf/util/tsc.c               | 25 +++++++++++++++++++++++++
 tools/perf/util/tsc.h               | 11 +++++++++++
 6 files changed, 40 insertions(+), 26 deletions(-)
 create mode 100644 tools/perf/util/tsc.c
 create mode 100644 tools/perf/util/tsc.h
tools/perf/Makefile.perf +2 -0
index 9670a16..abca577 100644
@@ -295,6 +295,7 @@ LIB_H += util/intlist.h
 LIB_H += util/perf_regs.h
 LIB_H += util/unwind.h
 LIB_H += util/vdso.h
+LIB_H += util/tsc.h
 LIB_H += ui/helpline.h
 LIB_H += ui/progress.h
 LIB_H += ui/util.h
@@ -373,6 +374,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
 LIB_OBJS += $(OUTPUT)util/record.o
 LIB_OBJS += $(OUTPUT)util/srcline.o
 LIB_OBJS += $(OUTPUT)util/data.o
+LIB_OBJS += $(OUTPUT)util/tsc.o
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/arch/x86/util/tsc.c +1 -21
index 40021fa..3655f24 100644
@@ -6,29 +6,9 @@
 #include "../../perf.h"
 #include <linux/types.h>
 #include "../../util/debug.h"
+#include "../../util/tsc.h"
 #include "tsc.h"
 
-u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
-{
-	u64 t, quot, rem;
-
-	t = ns - tc->time_zero;
-	quot = t / tc->time_mult;
-	rem  = t % tc->time_mult;
-	return (quot << tc->time_shift) +
-	       (rem << tc->time_shift) / tc->time_mult;
-}
-
-u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
-{
-	u64 quot, rem;
-
-	quot = cyc >> tc->time_shift;
-	rem  = cyc & ((1 << tc->time_shift) - 1);
-	return tc->time_zero + quot * tc->time_mult +
-	       ((rem * tc->time_mult) >> tc->time_shift);
-}
-
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc)
 {
tools/perf/arch/x86/util/tsc.h +0 -3
index 2affe03..2edc4d3 100644
@@ -14,7 +14,4 @@ struct perf_event_mmap_page;
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc);
 
-u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
-u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
-
 #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/tests/perf-time-to-tsc.c +1 -2
index 3b7cd4d..0372f6e 100644
@@ -8,10 +8,9 @@
 #include "evsel.h"
 #include "thread_map.h"
 #include "cpumap.h"
+#include "tsc.h"
 #include "tests.h"
 
-#include "../arch/x86/util/tsc.h"
-
 #define CHECK__(x) {				\
 	while ((x) < 0) {			\
 		pr_debug(#x " failed!\n");	\
tools/perf/util/tsc.c new file +25 -0
new file mode 100644
index 0000000..ef4749836
@@ -0,0 +1,25 @@
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#include "tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
+{
+	u64 t, quot, rem;
+
+	t = ns - tc->time_zero;
+	quot = t / tc->time_mult;
+	rem  = t % tc->time_mult;
+	return (quot << tc->time_shift) +
+	       (rem << tc->time_shift) / tc->time_mult;
+}
+
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
+{
+	u64 quot, rem;
+
+	quot = cyc >> tc->time_shift;
+	rem  = cyc & ((1 << tc->time_shift) - 1);
+	return tc->time_zero + quot * tc->time_mult +
+	       ((rem * tc->time_mult) >> tc->time_shift);
+}
tools/perf/util/tsc.h new file +11 -0
new file mode 100644
index 0000000..4eca848
@@ -0,0 +1,11 @@
+#ifndef __PERF_TSC_H
+#define __PERF_TSC_H
+
+#include <linux/types.h>
+
+#include "../arch/x86/util/tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
+
+#endif
Signature · 1 line
1.8.3.2
#116 lore raw

Re: [PATCH 39/41] perf tools: Allow TSC conversion on any arch

Em Mon, Jul 14, 2014 at 01:03:03PM +0300, Adrian Hunter escreveu:

Quoted 4 lines

It is possible to record a perf.data file on
one architecture and process it on another.
Consequently, TSC conversion functions need
to be moved out of the arch directory.

Can you state where a TSC is stored in perf.data, and how in the !x86 arch this will be detected so that those functions will be used?

- Arnaldo

Quoted 145 lines
---
 tools/perf/Makefile.perf            |  2 ++
 tools/perf/arch/x86/util/tsc.c      | 22 +---------------------
 tools/perf/arch/x86/util/tsc.h      |  3 ---
 tools/perf/tests/perf-time-to-tsc.c |  3 +--
 tools/perf/util/tsc.c               | 25 +++++++++++++++++++++++++
 tools/perf/util/tsc.h               | 11 +++++++++++
 6 files changed, 40 insertions(+), 26 deletions(-)
 create mode 100644 tools/perf/util/tsc.c
 create mode 100644 tools/perf/util/tsc.h
tools/perf/Makefile.perf +2 -0
index 9670a16..abca577 100644
@@ -295,6 +295,7 @@ LIB_H += util/intlist.h
 LIB_H += util/perf_regs.h
 LIB_H += util/unwind.h
 LIB_H += util/vdso.h
+LIB_H += util/tsc.h
 LIB_H += ui/helpline.h
 LIB_H += ui/progress.h
 LIB_H += ui/util.h
@@ -373,6 +374,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
 LIB_OBJS += $(OUTPUT)util/record.o
 LIB_OBJS += $(OUTPUT)util/srcline.o
 LIB_OBJS += $(OUTPUT)util/data.o
+LIB_OBJS += $(OUTPUT)util/tsc.o
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/arch/x86/util/tsc.c +1 -21
index 40021fa..3655f24 100644
@@ -6,29 +6,9 @@
 #include "../../perf.h"
 #include <linux/types.h>
 #include "../../util/debug.h"
+#include "../../util/tsc.h"
 #include "tsc.h"
 
-u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
-{
-	u64 t, quot, rem;
-
-	t = ns - tc->time_zero;
-	quot = t / tc->time_mult;
-	rem  = t % tc->time_mult;
-	return (quot << tc->time_shift) +
-	       (rem << tc->time_shift) / tc->time_mult;
-}
-
-u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
-{
-	u64 quot, rem;
-
-	quot = cyc >> tc->time_shift;
-	rem  = cyc & ((1 << tc->time_shift) - 1);
-	return tc->time_zero + quot * tc->time_mult +
-	       ((rem * tc->time_mult) >> tc->time_shift);
-}
-
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc)
 {
tools/perf/arch/x86/util/tsc.h +0 -3
index 2affe03..2edc4d3 100644
@@ -14,7 +14,4 @@ struct perf_event_mmap_page;
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc);
 
-u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
-u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
-
 #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/tests/perf-time-to-tsc.c +1 -2
index 3b7cd4d..0372f6e 100644
@@ -8,10 +8,9 @@
 #include "evsel.h"
 #include "thread_map.h"
 #include "cpumap.h"
+#include "tsc.h"
 #include "tests.h"
 
-#include "../arch/x86/util/tsc.h"
-
 #define CHECK__(x) {				\
 	while ((x) < 0) {			\
 		pr_debug(#x " failed!\n");	\
tools/perf/util/tsc.c new file +25 -0
new file mode 100644
index 0000000..ef4749836
@@ -0,0 +1,25 @@
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#include "tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
+{
+	u64 t, quot, rem;
+
+	t = ns - tc->time_zero;
+	quot = t / tc->time_mult;
+	rem  = t % tc->time_mult;
+	return (quot << tc->time_shift) +
+	       (rem << tc->time_shift) / tc->time_mult;
+}
+
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
+{
+	u64 quot, rem;
+
+	quot = cyc >> tc->time_shift;
+	rem  = cyc & ((1 << tc->time_shift) - 1);
+	return tc->time_zero + quot * tc->time_mult +
+	       ((rem * tc->time_mult) >> tc->time_shift);
+}
tools/perf/util/tsc.h new file +11 -0
new file mode 100644
index 0000000..4eca848
@@ -0,0 +1,11 @@
+#ifndef __PERF_TSC_H
+#define __PERF_TSC_H
+
+#include <linux/types.h>
+
+#include "../arch/x86/util/tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
+
+#endif
Signature · 1 line
1.8.3.2
maintainer
#117 lore raw

Re: [PATCH 39/41] perf tools: Allow TSC conversion on any arch

Quoted 8 lines · Arnaldo Carvalho de Melo

Em Mon, Jul 14, 2014 at 01:03:03PM +0300, Adrian Hunter escreveu:

Quoted 4 lines

It is possible to record a perf.data file on one architecture and process it on another. Consequently, TSC conversion functions need to be moved out of the arch directory.

Can you state where a TSC is stored in perf.data, and how in the !x86 arch this will be detected so that those functions will be used?

So there's nothing intrinsically x86/tsc about the perf interface here, although that's currently the only one implementing this thing.

Other archs could equally expose their 'cycle' counter etc..

author reviewer
#118 lore raw

Re: [PATCH 39/41] perf tools: Allow TSC conversion on any arch

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

Em Mon, Jul 14, 2014 at 01:03:03PM +0300, Adrian Hunter escreveu:

Quoted 4 lines

It is possible to record a perf.data file on
one architecture and process it on another.
Consequently, TSC conversion functions need
to be moved out of the arch directory.

Can you state where a TSC is stored in perf.data, and how in the !x86 arch this will be detected so that those functions will be used?

Intel PT has packets that contain 7-bytes of TSC. 'perf record' adds a reference TSC to the ITRACE event so that the full TSC is known.

So this is the possibility that you record a perf.data file on x86 recording Intel PT and then take that file to another machine with a different architecture. It should still be possible to read the file there.

Quoted 148 lines

- Arnaldo

Quoted 145 lines
---
  tools/perf/Makefile.perf            |  2 ++
  tools/perf/arch/x86/util/tsc.c      | 22 +---------------------
  tools/perf/arch/x86/util/tsc.h      |  3 ---
  tools/perf/tests/perf-time-to-tsc.c |  3 +--
  tools/perf/util/tsc.c               | 25 +++++++++++++++++++++++++
  tools/perf/util/tsc.h               | 11 +++++++++++
  6 files changed, 40 insertions(+), 26 deletions(-)

create mode 100644 tools/perf/util/tsc.c
create mode 100644 tools/perf/util/tsc.h

tools/perf/Makefile.perf +2 -0
index 9670a16..abca577 100644
@@ -295,6 +295,7 @@ LIB_H += util/intlist.h
  LIB_H += util/perf_regs.h
  LIB_H += util/unwind.h
  LIB_H += util/vdso.h
+LIB_H += util/tsc.h
  LIB_H += ui/helpline.h
  LIB_H += ui/progress.h
  LIB_H += ui/util.h
@@ -373,6 +374,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
  LIB_OBJS += $(OUTPUT)util/record.o
  LIB_OBJS += $(OUTPUT)util/srcline.o
  LIB_OBJS += $(OUTPUT)util/data.o
+LIB_OBJS += $(OUTPUT)util/tsc.o
 
  LIB_OBJS += $(OUTPUT)ui/setup.o
  LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/arch/x86/util/tsc.c +1 -21
index 40021fa..3655f24 100644
@@ -6,29 +6,9 @@
  #include "../../perf.h"
  #include <linux/types.h>
  #include "../../util/debug.h"
+#include "../../util/tsc.h"
  #include "tsc.h"
 
-u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
-{
-	u64 t, quot, rem;
-
-	t = ns - tc->time_zero;
-	quot = t / tc->time_mult;
-	rem  = t % tc->time_mult;
-	return (quot << tc->time_shift) +
-	       (rem << tc->time_shift) / tc->time_mult;
-}
-
-u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
-{
-	u64 quot, rem;
-
-	quot = cyc >> tc->time_shift;
-	rem  = cyc & ((1 << tc->time_shift) - 1);
-	return tc->time_zero + quot * tc->time_mult +
-	       ((rem * tc->time_mult) >> tc->time_shift);
-}
-
  int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
  			     struct perf_tsc_conversion *tc)
  {
tools/perf/arch/x86/util/tsc.h +0 -3
index 2affe03..2edc4d3 100644
@@ -14,7 +14,4 @@ struct perf_event_mmap_page;
  int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
  			     struct perf_tsc_conversion *tc);
 
-u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
-u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
-
  #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/tests/perf-time-to-tsc.c +1 -2
index 3b7cd4d..0372f6e 100644
@@ -8,10 +8,9 @@
  #include "evsel.h"
  #include "thread_map.h"
  #include "cpumap.h"
+#include "tsc.h"
  #include "tests.h"
 
-#include "../arch/x86/util/tsc.h"
-
  #define CHECK__(x) {				\
  	while ((x) < 0) {			\
  		pr_debug(#x " failed!\n");	\
tools/perf/util/tsc.c new file +25 -0
new file mode 100644
index 0000000..ef4749836
@@ -0,0 +1,25 @@
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#include "tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
+{
+	u64 t, quot, rem;
+
+	t = ns - tc->time_zero;
+	quot = t / tc->time_mult;
+	rem  = t % tc->time_mult;
+	return (quot << tc->time_shift) +
+	       (rem << tc->time_shift) / tc->time_mult;
+}
+
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
+{
+	u64 quot, rem;
+
+	quot = cyc >> tc->time_shift;
+	rem  = cyc & ((1 << tc->time_shift) - 1);
+	return tc->time_zero + quot * tc->time_mult +
+	       ((rem * tc->time_mult) >> tc->time_shift);
+}
tools/perf/util/tsc.h new file +11 -1
new file mode 100644
index 0000000..4eca848
@@ -0,0 +1,11 @@
+#ifndef __PERF_TSC_H
+#define __PERF_TSC_H
+
+#include <linux/types.h>
+
+#include "../arch/x86/util/tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
+
+#endif
--

1.8.3.2

#119 lore raw

[tip:perf/core] perf tools: Allow TSC conversion on any arch

In reply to Adrian Hunter
perf tools: Allow TSC conversion on any arch
Commit-ID:  0b437860818dc717f6a9e8a5089223a8414f5fff
Gitweb:     http://git.kernel.org/tip/0b437860818dc717f6a9e8a5089223a8414f5fff
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 14 Jul 2014 13:03:03 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 17 Jul 2014 12:59:00 -0300

perf tools: Allow TSC conversion on any arch

It is possible to record a perf.data file on one architecture and process it on another.

Consequently, TSC conversion functions need to be moved out of the arch directory.

---
 tools/perf/Makefile.perf            |  2 ++
 tools/perf/arch/x86/util/tsc.c      | 22 +---------------------
 tools/perf/arch/x86/util/tsc.h      |  3 ---
 tools/perf/tests/perf-time-to-tsc.c |  3 +--
 tools/perf/util/tsc.c               | 25 +++++++++++++++++++++++++
 tools/perf/util/tsc.h               | 11 +++++++++++
 6 files changed, 40 insertions(+), 26 deletions(-)
tools/perf/Makefile.perf +2 -0
index 90c4983..3308b22 100644
@@ -295,6 +295,7 @@ LIB_H += util/intlist.h
 LIB_H += util/perf_regs.h
 LIB_H += util/unwind.h
 LIB_H += util/vdso.h
+LIB_H += util/tsc.h
 LIB_H += ui/helpline.h
 LIB_H += ui/progress.h
 LIB_H += ui/util.h
@@ -374,6 +375,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
 LIB_OBJS += $(OUTPUT)util/record.o
 LIB_OBJS += $(OUTPUT)util/srcline.o
 LIB_OBJS += $(OUTPUT)util/data.o
+LIB_OBJS += $(OUTPUT)util/tsc.o
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
tools/perf/arch/x86/util/tsc.c +1 -21
index 40021fa..3655f24 100644
@@ -6,29 +6,9 @@
 #include "../../perf.h"
 #include <linux/types.h>
 #include "../../util/debug.h"
+#include "../../util/tsc.h"
 #include "tsc.h"
 
-u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
-{
-	u64 t, quot, rem;
-
-	t = ns - tc->time_zero;
-	quot = t / tc->time_mult;
-	rem  = t % tc->time_mult;
-	return (quot << tc->time_shift) +
-	       (rem << tc->time_shift) / tc->time_mult;
-}
-
-u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
-{
-	u64 quot, rem;
-
-	quot = cyc >> tc->time_shift;
-	rem  = cyc & ((1 << tc->time_shift) - 1);
-	return tc->time_zero + quot * tc->time_mult +
-	       ((rem * tc->time_mult) >> tc->time_shift);
-}
-
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc)
 {
tools/perf/arch/x86/util/tsc.h +0 -3
index 2affe03..2edc4d3 100644
@@ -14,7 +14,4 @@ struct perf_event_mmap_page;
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc);
 
-u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
-u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
-
 #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/tests/perf-time-to-tsc.c +1 -2
index 3b7cd4d..0372f6e 100644
@@ -8,10 +8,9 @@
 #include "evsel.h"
 #include "thread_map.h"
 #include "cpumap.h"
+#include "tsc.h"
 #include "tests.h"
 
-#include "../arch/x86/util/tsc.h"
-
 #define CHECK__(x) {				\
 	while ((x) < 0) {			\
 		pr_debug(#x " failed!\n");	\
tools/perf/util/tsc.c new file +25 -0
new file mode 100644
index 0000000..ef4749836
@@ -0,0 +1,25 @@
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#include "tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
+{
+	u64 t, quot, rem;
+
+	t = ns - tc->time_zero;
+	quot = t / tc->time_mult;
+	rem  = t % tc->time_mult;
+	return (quot << tc->time_shift) +
+	       (rem << tc->time_shift) / tc->time_mult;
+}
+
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
+{
+	u64 quot, rem;
+
+	quot = cyc >> tc->time_shift;
+	rem  = cyc & ((1 << tc->time_shift) - 1);
+	return tc->time_zero + quot * tc->time_mult +
+	       ((rem * tc->time_mult) >> tc->time_shift);
+}
tools/perf/util/tsc.h new file +11 -0
new file mode 100644
index 0000000..4eca848
@@ -0,0 +1,11 @@
+#ifndef __PERF_TSC_H
+#define __PERF_TSC_H
+
+#include <linux/types.h>
+
+#include "../arch/x86/util/tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
+
+#endif
author reviewer
#120 lore raw

PATCH 40/41 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
author reviewer
#121 lore raw

PATCH 41/41 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