Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / tools / perf / util / event.c
index b0f3ca8..9d12aa6 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/types.h>
 #include "event.h"
 #include "debug.h"
+#include "hist.h"
 #include "machine.h"
 #include "sort.h"
 #include "string.h"
@@ -94,14 +95,10 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
 
 static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
                                         union perf_event *event, pid_t pid,
-                                        int full,
                                         perf_event__handler_t process,
                                         struct machine *machine)
 {
-       char filename[PATH_MAX];
        size_t size;
-       DIR *tasks;
-       struct dirent dirent, *next;
        pid_t tgid;
 
        memset(&event->comm, 0, sizeof(event->comm));
@@ -124,55 +121,35 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
        event->comm.header.size = (sizeof(event->comm) -
                                (sizeof(event->comm.comm) - size) +
                                machine->id_hdr_size);
-       if (!full) {
-               event->comm.tid = pid;
+       event->comm.tid = pid;
 
-               if (process(tool, event, &synth_sample, machine) != 0)
-                       return -1;
-
-               goto out;
-       }
-
-       if (machine__is_default_guest(machine))
-               return 0;
-
-       snprintf(filename, sizeof(filename), "%s/proc/%d/task",
-                machine->root_dir, pid);
-
-       tasks = opendir(filename);
-       if (tasks == NULL) {
-               pr_debug("couldn't open %s\n", filename);
-               return 0;
-       }
+       if (process(tool, event, &synth_sample, machine) != 0)
+               return -1;
 
-       while (!readdir_r(tasks, &dirent, &next) && next) {
-               char *end;
-               pid = strtol(dirent.d_name, &end, 10);
-               if (*end)
-                       continue;
+out:
+       return tgid;
+}
 
-               /* already have tgid; jut want to update the comm */
-               (void) perf_event__get_comm_tgid(pid, event->comm.comm,
-                                        sizeof(event->comm.comm));
+static int perf_event__synthesize_fork(struct perf_tool *tool,
+                                      union perf_event *event, pid_t pid,
+                                      pid_t tgid, perf_event__handler_t process,
+                                      struct machine *machine)
+{
+       memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size);
 
-               size = strlen(event->comm.comm) + 1;
-               size = PERF_ALIGN(size, sizeof(u64));
-               memset(event->comm.comm + size, 0, machine->id_hdr_size);
-               event->comm.header.size = (sizeof(event->comm) -
-                                         (sizeof(event->comm.comm) - size) +
-                                         machine->id_hdr_size);
+       /* this is really a clone event but we use fork to synthesize it */
+       event->fork.ppid = tgid;
+       event->fork.ptid = tgid;
+       event->fork.pid  = tgid;
+       event->fork.tid  = pid;
+       event->fork.header.type = PERF_RECORD_FORK;
 
-               event->comm.tid = pid;
+       event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);
 
-               if (process(tool, event, &synth_sample, machine) != 0) {
-                       tgid = -1;
-                       break;
-               }
-       }
+       if (process(tool, event, &synth_sample, machine) != 0)
+               return -1;
 
-       closedir(tasks);
-out:
-       return tgid;
+       return 0;
 }
 
 int perf_event__synthesize_mmap_events(struct perf_tool *tool,
@@ -324,17 +301,71 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
 
 static int __event__synthesize_thread(union perf_event *comm_event,
                                      union perf_event *mmap_event,
+                                     union perf_event *fork_event,
                                      pid_t pid, int full,
                                          perf_event__handler_t process,
                                      struct perf_tool *tool,
                                      struct machine *machine, bool mmap_data)
 {
-       pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full,
+       char filename[PATH_MAX];
+       DIR *tasks;
+       struct dirent dirent, *next;
+       pid_t tgid;
+
+       /* special case: only send one comm event using passed in pid */
+       if (!full) {
+               tgid = perf_event__synthesize_comm(tool, comm_event, pid,
+                                                  process, machine);
+
+               if (tgid == -1)
+                       return -1;
+
+               return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
+                                                         process, machine, mmap_data);
+       }
+
+       if (machine__is_default_guest(machine))
+               return 0;
+
+       snprintf(filename, sizeof(filename), "%s/proc/%d/task",
+                machine->root_dir, pid);
+
+       tasks = opendir(filename);
+       if (tasks == NULL) {
+               pr_debug("couldn't open %s\n", filename);
+               return 0;
+       }
+
+       while (!readdir_r(tasks, &dirent, &next) && next) {
+               char *end;
+               int rc = 0;
+               pid_t _pid;
+
+               _pid = strtol(dirent.d_name, &end, 10);
+               if (*end)
+                       continue;
+
+               tgid = perf_event__synthesize_comm(tool, comm_event, _pid,
+                                                  process, machine);
+               if (tgid == -1)
+                       return -1;
+
+               if (_pid == pid) {
+                       /* process the parent's maps too */
+                       rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
+                                               process, machine, mmap_data);
+               } else {
+                       /* only fork the tid's map, to save time */
+                       rc = perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
                                                 process, machine);
-       if (tgid == -1)
-               return -1;
-       return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
-                                                 process, machine, mmap_data);
+               }
+
+               if (rc)
+                       return rc;
+       }
+
+       closedir(tasks);
+       return 0;
 }
 
 int perf_event__synthesize_thread_map(struct perf_tool *tool,
@@ -343,7 +374,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
                                      struct machine *machine,
                                      bool mmap_data)
 {
-       union perf_event *comm_event, *mmap_event;
+       union perf_event *comm_event, *mmap_event, *fork_event;
        int err = -1, thread, j;
 
        comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
@@ -354,9 +385,14 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
        if (mmap_event == NULL)
                goto out_free_comm;
 
+       fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
+       if (fork_event == NULL)
+               goto out_free_mmap;
+
        err = 0;
        for (thread = 0; thread < threads->nr; ++thread) {
                if (__event__synthesize_thread(comm_event, mmap_event,
+                                              fork_event,
                                               threads->map[thread], 0,
                                               process, tool, machine,
                                               mmap_data)) {
@@ -382,6 +418,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
                        /* if not, generate events for it */
                        if (need_leader &&
                            __event__synthesize_thread(comm_event, mmap_event,
+                                                      fork_event,
                                                       comm_event->comm.pid, 0,
                                                       process, tool, machine,
                                                       mmap_data)) {
@@ -390,6 +427,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
                        }
                }
        }
+       free(fork_event);
+out_free_mmap:
        free(mmap_event);
 out_free_comm:
        free(comm_event);
@@ -404,9 +443,12 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
        DIR *proc;
        char proc_path[PATH_MAX];
        struct dirent dirent, *next;
-       union perf_event *comm_event, *mmap_event;
+       union perf_event *comm_event, *mmap_event, *fork_event;
        int err = -1;
 
+       if (machine__is_default_guest(machine))
+               return 0;
+
        comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
        if (comm_event == NULL)
                goto out;
@@ -415,14 +457,15 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
        if (mmap_event == NULL)
                goto out_free_comm;
 
-       if (machine__is_default_guest(machine))
-               return 0;
+       fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
+       if (fork_event == NULL)
+               goto out_free_mmap;
 
        snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
        proc = opendir(proc_path);
 
        if (proc == NULL)
-               goto out_free_mmap;
+               goto out_free_fork;
 
        while (!readdir_r(proc, &dirent, &next) && next) {
                char *end;
@@ -434,12 +477,14 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
                 * We may race with exiting thread, so don't stop just because
                 * one thread couldn't be synthesized.
                 */
-               __event__synthesize_thread(comm_event, mmap_event, pid, 1,
-                                          process, tool, machine, mmap_data);
+               __event__synthesize_thread(comm_event, mmap_event, fork_event, pid,
+                                          1, process, tool, machine, mmap_data);
        }
 
        err = 0;
        closedir(proc);
+out_free_fork:
+       free(fork_event);
 out_free_mmap:
        free(mmap_event);
 out_free_comm:
@@ -661,7 +706,7 @@ void thread__find_addr_map(struct thread *thread,
        al->thread = thread;
        al->addr = addr;
        al->cpumode = cpumode;
-       al->filtered = false;
+       al->filtered = 0;
 
        if (machine == NULL) {
                al->map = NULL;
@@ -687,11 +732,11 @@ void thread__find_addr_map(struct thread *thread,
                if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
                        cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
                        !perf_guest)
-                       al->filtered = true;
+                       al->filtered |= (1 << HIST_FILTER__GUEST);
                if ((cpumode == PERF_RECORD_MISC_USER ||
                        cpumode == PERF_RECORD_MISC_KERNEL) &&
                        !perf_host)
-                       al->filtered = true;
+                       al->filtered |= (1 << HIST_FILTER__HOST);
 
                return;
        }
@@ -748,9 +793,6 @@ int perf_event__preprocess_sample(const union perf_event *event,
        if (thread == NULL)
                return -1;
 
-       if (thread__is_filtered(thread))
-               goto out_filtered;
-
        dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
        /*
         * Have we already created the kernel maps for this machine?
@@ -768,6 +810,10 @@ int perf_event__preprocess_sample(const union perf_event *event,
        dump_printf(" ...... dso: %s\n",
                    al->map ? al->map->dso->long_name :
                        al->level == 'H' ? "[hypervisor]" : "<not found>");
+
+       if (thread__is_filtered(thread))
+               al->filtered |= (1 << HIST_FILTER__THREAD);
+
        al->sym = NULL;
        al->cpu = sample->cpu;
 
@@ -779,8 +825,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
                                                  dso->short_name) ||
                               (dso->short_name != dso->long_name &&
                                strlist__has_entry(symbol_conf.dso_list,
-                                                  dso->long_name)))))
-                       goto out_filtered;
+                                                  dso->long_name))))) {
+                       al->filtered |= (1 << HIST_FILTER__DSO);
+               }
 
                al->sym = map__find_symbol(al->map, al->addr,
                                           machine->symbol_filter);
@@ -788,12 +835,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
 
        if (symbol_conf.sym_list &&
                (!al->sym || !strlist__has_entry(symbol_conf.sym_list,
-                                               al->sym->name)))
-               goto out_filtered;
-
-       return 0;
+                                               al->sym->name))) {
+               al->filtered |= (1 << HIST_FILTER__SYMBOL);
+       }
 
-out_filtered:
-       al->filtered = true;
        return 0;
 }