perf machine: Fix map groups of threads with unknown pids
authorAdrian Hunter <adrian.hunter@intel.com>
Wed, 16 Jul 2014 08:07:13 +0000 (11:07 +0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 17 Jul 2014 13:31:02 +0000 (10:31 -0300)
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.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1405498033-23817-1-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/machine.c
tools/perf/util/map.c
tools/perf/util/map.h

index 5b8087728f285b3001cb01fc19cc9bcf9a498f63..5484fa4385fc70159edaa22bec4b9ac2f8b03f2a 100644 (file)
@@ -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;
                }
 
index 25c571f4cba6abb1bcb54c527afcd8a8921125f5..7af14807ee903a1d60968e00d7c18752b386ebf5 100644 (file)
@@ -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));
index 7758c72522efa56bf58bc28545552e606947e4df..5806a906198b34500c46da4f7d745d26f7bc1754 100644 (file)
@@ -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)
 {