2017-03-01 21:17:33

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH v7 4/8] perf tool: synthesize namespace events for current processes

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 <[email protected]>
> ---
> 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,


2017-03-03 08:57:54

by Hari Bathini

[permalink] [raw]
Subject: Re: [PATCH v7 4/8] perf tool: synthesize namespace events for current processes



On Thursday 02 March 2017 02:35 AM, Arnaldo Carvalho de Melo wrote:
> 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 <[email protected]>
>> ---
>> 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?
>

NR_NAMESPACES is the total number of namespaces. For synthesized namespace
events, data is obtained from /proc/<pid>/ns/ dir. Looking at this dir, it
is difficult to arrive at the total number of namespaces in kernel, as
some namespaces can be compiled in/out of the kernel. NR_NAMESPACES is
used instead. Its value is most likely the same for kernel and perf tool
unless a new namespace is introduced - the warning in previous patch is
intended to alert the user about such scenario.

Thanks
Hari