Synthesize PERF_RECORD_NAMESPACES events for processes that were
running prior to invocation of perf record. The data for this is
taken from /proc/$PID/ns. These changes make way for analyzing
events with regard to namespaces.

Acked-by: Jiri Olsa <[email protected]>
Signed-off-by: Hari Bathini <[email protected]>
---
 tools/perf/builtin-record.c |   29 ++++++++++-
 tools/perf/util/event.c     |  111 +++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/event.h     |    6 ++
 3 files changed, 136 insertions(+), 10 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 99562c7..04faef7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -986,6 +986,7 @@ static int __cmd_record(struct record *rec, int argc, const 
char **argv)
         */
        if (forks) {
                union perf_event *event;
+               pid_t tgid;
 
                event = malloc(sizeof(event->comm) + machine->id_hdr_size);
                if (event == NULL) {
@@ -999,10 +1000,30 @@ static int __cmd_record(struct record *rec, int argc, 
const char **argv)
                 * cannot see a correct process name for those events.
                 * Synthesize COMM event to prevent it.
                 */
-               perf_event__synthesize_comm(tool, event,
-                                           rec->evlist->workload.pid,
-                                           process_synthesized_event,
-                                           machine);
+               tgid = perf_event__synthesize_comm(tool, event,
+                                                  rec->evlist->workload.pid,
+                                                  process_synthesized_event,
+                                                  machine);
+               free(event);
+
+               if (tgid == -1)
+                       goto out_child;
+
+               event = malloc(sizeof(event->namespaces) +
+                              (NR_NAMESPACES * sizeof(struct 
perf_ns_link_info)) +
+                              machine->id_hdr_size);
+               if (event == NULL) {
+                       err = -ENOMEM;
+                       goto out_child;
+               }
+
+               /*
+                * Synthesize NAMESPACES event for the command specified.
+                */
+               perf_event__synthesize_namespaces(tool, event,
+                                                 rec->evlist->workload.pid,
+                                                 tgid, 
process_synthesized_event,
+                                                 machine);
                free(event);
 
                perf_evlist__start_workload(rec->evlist);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index f118eac..5a99af8 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -50,6 +50,16 @@ static const char *perf_event__names[] = {
        [PERF_RECORD_TIME_CONV]                 = "TIME_CONV",
 };
 
+static const char *perf_ns__names[] = {
+       [NET_NS_INDEX]          = "net",
+       [UTS_NS_INDEX]          = "uts",
+       [IPC_NS_INDEX]          = "ipc",
+       [PID_NS_INDEX]          = "pid",
+       [USER_NS_INDEX]         = "user",
+       [MNT_NS_INDEX]          = "mnt",
+       [CGROUP_NS_INDEX]       = "cgroup",
+};
+
 const char *perf_event__name(unsigned int id)
 {
        if (id >= ARRAY_SIZE(perf_event__names))
@@ -59,6 +69,13 @@ const char *perf_event__name(unsigned int id)
        return perf_event__names[id];
 }
 
+static const char *perf_ns__name(unsigned int id)
+{
+       if (id >= ARRAY_SIZE(perf_ns__names))
+               return "UNKNOWN";
+       return perf_ns__names[id];
+}
+
 static int perf_tool__process_synth_event(struct perf_tool *tool,
                                          union perf_event *event,
                                          struct machine *machine,
@@ -204,6 +221,58 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
        return tgid;
 }
 
+static void perf_event__get_ns_link_info(pid_t pid, const char *ns,
+                                        struct perf_ns_link_info *ns_link_info)
+{
+       struct stat64 st;
+       char proc_ns[128];
+
+       sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns);
+       if (stat64(proc_ns, &st) == 0) {
+               ns_link_info->dev = st.st_dev;
+               ns_link_info->ino = st.st_ino;
+       }
+}
+
+int perf_event__synthesize_namespaces(struct perf_tool *tool,
+                                     union perf_event *event,
+                                     pid_t pid, pid_t tgid,
+                                     perf_event__handler_t process,
+                                     struct machine *machine)
+{
+       u32 idx;
+       struct perf_ns_link_info *ns_link_info;
+
+       if (!tool->namespace_events)
+               return 0;
+
+       memset(&event->namespaces, 0, (sizeof(event->namespaces) +
+              (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
+              machine->id_hdr_size));
+
+       event->namespaces.pid = tgid;
+       event->namespaces.tid = pid;
+
+       event->namespaces.nr_namespaces = NR_NAMESPACES;
+
+       ns_link_info = event->namespaces.link_info;
+
+       for (idx = 0; idx < event->namespaces.nr_namespaces; idx++)
+               perf_event__get_ns_link_info(pid, perf_ns__name(idx),
+                                            &ns_link_info[idx]);
+
+       event->namespaces.header.type = PERF_RECORD_NAMESPACES;
+
+       event->namespaces.header.size = (sizeof(event->namespaces) +
+                       (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
+                       machine->id_hdr_size);
+
+       if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
+               return -1;
+
+       return 0;
+}
+
 static int perf_event__synthesize_fork(struct perf_tool *tool,
                                       union perf_event *event,
                                       pid_t pid, pid_t tgid, pid_t ppid,
@@ -435,8 +504,9 @@ 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,
+                                     union perf_event *namespaces_event,
                                      pid_t pid, int full,
-                                         perf_event__handler_t process,
+                                     perf_event__handler_t process,
                                      struct perf_tool *tool,
                                      struct machine *machine,
                                      bool mmap_data,
@@ -456,6 +526,11 @@ static int __event__synthesize_thread(union perf_event 
*comm_event,
                if (tgid == -1)
                        return -1;
 
+               if (perf_event__synthesize_namespaces(tool, namespaces_event, 
pid,
+                                                     tgid, process, machine) < 
0)
+                       return -1;
+
+
                return perf_event__synthesize_mmap_events(tool, mmap_event, 
pid, tgid,
                                                          process, machine, 
mmap_data,
                                                          proc_map_timeout);
@@ -489,6 +564,11 @@ static int __event__synthesize_thread(union perf_event 
*comm_event,
                if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
                                                ppid, process, machine) < 0)
                        break;
+
+               if (perf_event__synthesize_namespaces(tool, namespaces_event, 
_pid,
+                                                     tgid, process, machine) < 
0)
+                       break;
+
                /*
                 * Send the prepared comm event
                 */
@@ -517,6 +597,7 @@ int perf_event__synthesize_thread_map(struct perf_tool 
*tool,
                                      unsigned int proc_map_timeout)
 {
        union perf_event *comm_event, *mmap_event, *fork_event;
+       union perf_event *namespaces_event;
        int err = -1, thread, j;
 
        comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
@@ -531,10 +612,16 @@ int perf_event__synthesize_thread_map(struct perf_tool 
*tool,
        if (fork_event == NULL)
                goto out_free_mmap;
 
+       namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
+                                 (NR_NAMESPACES * sizeof(struct 
perf_ns_link_info)) +
+                                 machine->id_hdr_size);
+       if (namespaces_event == NULL)
+               goto out_free_fork;
+
        err = 0;
        for (thread = 0; thread < threads->nr; ++thread) {
                if (__event__synthesize_thread(comm_event, mmap_event,
-                                              fork_event,
+                                              fork_event, namespaces_event,
                                               thread_map__pid(threads, 
thread), 0,
                                               process, tool, machine,
                                               mmap_data, proc_map_timeout)) {
@@ -560,7 +647,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,
+                                                      fork_event, 
namespaces_event,
                                                       comm_event->comm.pid, 0,
                                                       process, tool, machine,
                                                       mmap_data, 
proc_map_timeout)) {
@@ -569,6 +656,8 @@ int perf_event__synthesize_thread_map(struct perf_tool 
*tool,
                        }
                }
        }
+       free(namespaces_event);
+out_free_fork:
        free(fork_event);
 out_free_mmap:
        free(mmap_event);
@@ -588,6 +677,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
        char proc_path[PATH_MAX];
        struct dirent *dirent;
        union perf_event *comm_event, *mmap_event, *fork_event;
+       union perf_event *namespaces_event;
        int err = -1;
 
        if (machine__is_default_guest(machine))
@@ -605,11 +695,17 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
        if (fork_event == NULL)
                goto out_free_mmap;
 
+       namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
+                                 (NR_NAMESPACES * sizeof(struct 
perf_ns_link_info)) +
+                                 machine->id_hdr_size);
+       if (namespaces_event == NULL)
+               goto out_free_fork;
+
        snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
        proc = opendir(proc_path);
 
        if (proc == NULL)
-               goto out_free_fork;
+               goto out_free_namespaces;
 
        while ((dirent = readdir(proc)) != NULL) {
                char *end;
@@ -621,13 +717,16 @@ 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, fork_event, 
pid,
-                                          1, process, tool, machine, mmap_data,
+               __event__synthesize_thread(comm_event, mmap_event, fork_event,
+                                          namespaces_event, pid, 1, process,
+                                          tool, machine, mmap_data,
                                           proc_map_timeout);
        }
 
        err = 0;
        closedir(proc);
+out_free_namespaces:
+       free(namespaces_event);
 out_free_fork:
        free(fork_event);
 out_free_mmap:
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 26efc77..a46a1b4 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -648,6 +648,12 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
                                  perf_event__handler_t process,
                                  struct machine *machine);
 
+int perf_event__synthesize_namespaces(struct perf_tool *tool,
+                                     union perf_event *event,
+                                     pid_t pid, pid_t tgid,
+                                     perf_event__handler_t process,
+                                     struct machine *machine);
+
 int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                                       union perf_event *event,
                                       pid_t pid, pid_t tgid,

Reply via email to