summaryrefslogtreecommitdiffstats
path: root/tools/perf/util/machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/machine.c')
-rw-r--r--tools/perf/util/machine.c81
1 files changed, 71 insertions, 10 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index c73e1fc12e53..93c8b6fbc799 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -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];
@@ -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 && 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 && pid != th->pid_)
- th->pid_ = pid;
+ machine__update_thread_pid(machine, th, pid);
return th;
}
@@ -325,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;
@@ -1281,7 +1328,9 @@ static int machine__resolve_callchain_sample(struct machine *machine,
u8 cpumode = PERF_RECORD_MISC_USER;
int chain_nr = min(max_stack, (int)chain->nr);
int i;
+ int j;
int err;
+ int skip_idx __maybe_unused;
callchain_cursor_reset(&callchain_cursor);
@@ -1290,14 +1339,26 @@ static int machine__resolve_callchain_sample(struct machine *machine,
return 0;
}
+ /*
+ * Based on DWARF debug information, some architectures skip
+ * a callchain entry saved by the kernel.
+ */
+ skip_idx = arch_skip_callchain_idx(machine, thread, chain);
+
for (i = 0; i < chain_nr; i++) {
u64 ip;
struct addr_location al;
if (callchain_param.order == ORDER_CALLEE)
- ip = chain->ips[i];
+ j = i;
else
- ip = chain->ips[chain->nr - i - 1];
+ j = chain->nr - i - 1;
+
+#ifdef HAVE_SKIP_CALLCHAIN_IDX
+ if (j == skip_idx)
+ continue;
+#endif
+ ip = chain->ips[j];
if (ip >= PERF_CONTEXT_MAX) {
switch (ip) {
OpenPOWER on IntegriCloud