Re: [PATCH v7 4/8] perf tool: synthesize namespace events for current processes
From: Arnaldo Carvalho de Melo
Date: Wed Mar 01 2017 - 16:17:52 EST
Em Tue, Feb 21, 2017 at 07:31:44PM +0530, Hari Bathini escreveu:
> Synthesize PERF_RECORD_NAMESPACES events for processes that were
> running prior to invocation of perf record, the data for which is
> taken from /proc/$PID/ns. These changes make way for analyzing
> events with regard to namespaces.
>
> Signed-off-by: Hari Bathini <hbathini@xxxxxxxxxxxxxxxxxx>
> ---
> tools/perf/builtin-record.c | 27 +++++++++--
> tools/perf/util/event.c | 107 +++++++++++++++++++++++++++++++++++++++++--
> tools/perf/util/event.h | 6 ++
> 3 files changed, 130 insertions(+), 10 deletions(-)
>
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index a8b9a78..f4bf6a6 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,28 @@ 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) + 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..c8c112a 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,56 @@ 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) + machine->id_hdr_size);
> +
> + event->namespaces.pid = tgid;
> + event->namespaces.tid = pid;
> +
> + event->namespaces.nr_namespaces = NR_NAMESPACES;
Huh? Don't you have to first figure out how many namespaces a process is
in to then set this field?
> + 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) +
> + 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 +502,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 +524,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 +562,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 +595,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 +610,15 @@ 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) +
> + 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 +644,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 +653,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 +674,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 +692,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
> if (fork_event == NULL)
> goto out_free_mmap;
>
> + namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
> + 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 +713,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 4e90b09..c73ad47 100644
> --- a/tools/perf/util/event.h
> +++ b/tools/perf/util/event.h
> @@ -650,6 +650,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,