Re: [PATCH v8 3/6] perf record: Synthesize namespace events for current processes

From: Arnaldo Carvalho de Melo
Date: Tue Mar 14 2017 - 09:37:02 EST


Em Wed, Mar 08, 2017 at 02:11:51AM +0530, Hari Bathini escreveu:
> 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.

Will investigate...

[root@jouet ~]# perf test Lookup
26: Lookup mmap thread : FAILED!
[root@jouet ~]# perf test -v Lookup
26: Lookup mmap thread :
--- start ---
test child forked, pid 3413
tid = 3413, map = 0x7fd99225d000
tid = 3414, map = 0x7fd99225c000
tid = 3415, map = 0x7fd99225b000
tid = 3416, map = 0x7fd99225a000
perf: Segmentation fault
Obtained 16 stack frames.
perf(dump_stack+0x2d) [0x53dee6]
perf(sighandler_dump_stack+0x2d) [0x53dfc6]
/lib64/libc.so.6(+0x3598f) [0x7fd98f48898f]
perf(perf_event__synthesize_namespaces+0x32) [0x4c808b]
perf() [0x4c8de1]
perf(perf_event__synthesize_threads+0x20c) [0x4c935d]
perf() [0x4aa6e8]
perf() [0x4aa7fe]
perf(test__mmap_thread_lookup+0x23) [0x4aa9e9]
perf() [0x48daf8]
perf() [0x48dc2e]
perf() [0x48deb5]
perf(cmd_test+0x233) [0x48e340]
perf() [0x4b90fa]
perf() [0x4b9367]
perf() [0x4b94ac]
test child interrupted
---- end ----
Lookup mmap thread: FAILED!
[root@jouet ~]#

> Acked-by: Jiri Olsa <jolsa@xxxxxxxxxx>
> Signed-off-by: Hari Bathini <hbathini@xxxxxxxxxxxxxxxxxx>
> ---
> 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,