perf record: Synthesize namespace events for current processes
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. Committer notes: Check if 'tool' is NULL in perf_event__synthesize_namespaces(), as in the test__mmap_thread_lookup case, i.e. 'perf test Lookup mmap thread". Testing it: # ps axH > /tmp/allthreads # perf record -a --namespaces usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 1.169 MB perf.data (8 samples) ] # perf report -D | grep PERF_RECORD_NAMESPACES | wc -l 602 # wc -l /tmp/allthreads 601 /tmp/allthreads # tail /tmp/allthreads 16951 pts/4 T 0:00 git rebase -i a033bf1bfacdaa25642e6bcc857a7d0f67cc3c92^ 16952 pts/4 T 0:00 /bin/sh /usr/libexec/git-core/git-rebase -i a033bf1bfacdaa25642e6bcc857a7d0f67cc3c92^ 17176 pts/4 T 0:00 git commit --amend --no-post-rewrite 17204 pts/4 T 0:00 vim /home/acme/git/linux/.git/COMMIT_EDITMSG 18939 ? S 0:00 [kworker/2:1] 18947 ? S 0:00 [kworker/3:0] 18974 ? S 0:00 [kworker/1:0] 19047 ? S 0:00 [kworker/0:1] 19152 pts/6 S+ 0:00 weechat 19153 pts/7 R+ 0:00 ps axH # perf report -D | grep PERF_RECORD_NAMESPACES | tail 0 0 0x125068 [0xa0]: PERF_RECORD_NAMESPACES 17176/17176 - nr_namespaces: 7 0 0 0x1255b8 [0xa0]: PERF_RECORD_NAMESPACES 17204/17204 - nr_namespaces: 7 0 0 0x125df0 [0xa0]: PERF_RECORD_NAMESPACES 18939/18939 - nr_namespaces: 7 0 0 0x125f00 [0xa0]: PERF_RECORD_NAMESPACES 18947/18947 - nr_namespaces: 7 0 0 0x126010 [0xa0]: PERF_RECORD_NAMESPACES 18974/18974 - nr_namespaces: 7 0 0 0x126120 [0xa0]: PERF_RECORD_NAMESPACES 19047/19047 - nr_namespaces: 7 0 0 0x126230 [0xa0]: PERF_RECORD_NAMESPACES 19152/19152 - nr_namespaces: 7 0 0 0x129330 [0xa0]: PERF_RECORD_NAMESPACES 19154/19154 - nr_namespaces: 7 0 0 0x12a1f8 [0xa0]: PERF_RECORD_NAMESPACES 19155/19155 - nr_namespaces: 7 0 0 0x12b0b8 [0xa0]: PERF_RECORD_NAMESPACES 19155/19155 - nr_namespaces: 7 # Humm, investigate why we got two record for the 19155 pid/tid... Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com> Cc: Aravinda Prasad <aravinda@linux.vnet.ibm.com> Cc: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Eric Biederman <ebiederm@xmission.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Sargun Dhillon <sargun@sargun.me> Cc: Steven Rostedt <rostedt@goodmis.org> Link: http://lkml.kernel.org/r/148891931111.25309.11073854609798681633.stgit@hbathini.in.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
f3b3614a28
commit
e907caf3a0
|
@ -986,6 +986,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
||||||
*/
|
*/
|
||||||
if (forks) {
|
if (forks) {
|
||||||
union perf_event *event;
|
union perf_event *event;
|
||||||
|
pid_t tgid;
|
||||||
|
|
||||||
event = malloc(sizeof(event->comm) + machine->id_hdr_size);
|
event = malloc(sizeof(event->comm) + machine->id_hdr_size);
|
||||||
if (event == NULL) {
|
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.
|
* cannot see a correct process name for those events.
|
||||||
* Synthesize COMM event to prevent it.
|
* Synthesize COMM event to prevent it.
|
||||||
*/
|
*/
|
||||||
perf_event__synthesize_comm(tool, event,
|
tgid = perf_event__synthesize_comm(tool, event,
|
||||||
rec->evlist->workload.pid,
|
rec->evlist->workload.pid,
|
||||||
process_synthesized_event,
|
process_synthesized_event,
|
||||||
machine);
|
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);
|
free(event);
|
||||||
|
|
||||||
perf_evlist__start_workload(rec->evlist);
|
perf_evlist__start_workload(rec->evlist);
|
||||||
|
|
|
@ -221,6 +221,58 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
|
||||||
return tgid;
|
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 || !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,
|
static int perf_event__synthesize_fork(struct perf_tool *tool,
|
||||||
union perf_event *event,
|
union perf_event *event,
|
||||||
pid_t pid, pid_t tgid, pid_t ppid,
|
pid_t pid, pid_t tgid, pid_t ppid,
|
||||||
|
@ -452,8 +504,9 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
|
||||||
static int __event__synthesize_thread(union perf_event *comm_event,
|
static int __event__synthesize_thread(union perf_event *comm_event,
|
||||||
union perf_event *mmap_event,
|
union perf_event *mmap_event,
|
||||||
union perf_event *fork_event,
|
union perf_event *fork_event,
|
||||||
|
union perf_event *namespaces_event,
|
||||||
pid_t pid, int full,
|
pid_t pid, int full,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct perf_tool *tool,
|
struct perf_tool *tool,
|
||||||
struct machine *machine,
|
struct machine *machine,
|
||||||
bool mmap_data,
|
bool mmap_data,
|
||||||
|
@ -473,6 +526,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
|
||||||
if (tgid == -1)
|
if (tgid == -1)
|
||||||
return -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,
|
return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
|
||||||
process, machine, mmap_data,
|
process, machine, mmap_data,
|
||||||
proc_map_timeout);
|
proc_map_timeout);
|
||||||
|
@ -506,6 +564,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
|
||||||
if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
|
if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
|
||||||
ppid, process, machine) < 0)
|
ppid, process, machine) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid,
|
||||||
|
tgid, process, machine) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send the prepared comm event
|
* Send the prepared comm event
|
||||||
*/
|
*/
|
||||||
|
@ -534,6 +597,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
||||||
unsigned int proc_map_timeout)
|
unsigned int proc_map_timeout)
|
||||||
{
|
{
|
||||||
union perf_event *comm_event, *mmap_event, *fork_event;
|
union perf_event *comm_event, *mmap_event, *fork_event;
|
||||||
|
union perf_event *namespaces_event;
|
||||||
int err = -1, thread, j;
|
int err = -1, thread, j;
|
||||||
|
|
||||||
comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
|
comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
|
||||||
|
@ -548,10 +612,16 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
||||||
if (fork_event == NULL)
|
if (fork_event == NULL)
|
||||||
goto out_free_mmap;
|
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;
|
err = 0;
|
||||||
for (thread = 0; thread < threads->nr; ++thread) {
|
for (thread = 0; thread < threads->nr; ++thread) {
|
||||||
if (__event__synthesize_thread(comm_event, mmap_event,
|
if (__event__synthesize_thread(comm_event, mmap_event,
|
||||||
fork_event,
|
fork_event, namespaces_event,
|
||||||
thread_map__pid(threads, thread), 0,
|
thread_map__pid(threads, thread), 0,
|
||||||
process, tool, machine,
|
process, tool, machine,
|
||||||
mmap_data, proc_map_timeout)) {
|
mmap_data, proc_map_timeout)) {
|
||||||
|
@ -577,7 +647,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
||||||
/* if not, generate events for it */
|
/* if not, generate events for it */
|
||||||
if (need_leader &&
|
if (need_leader &&
|
||||||
__event__synthesize_thread(comm_event, mmap_event,
|
__event__synthesize_thread(comm_event, mmap_event,
|
||||||
fork_event,
|
fork_event, namespaces_event,
|
||||||
comm_event->comm.pid, 0,
|
comm_event->comm.pid, 0,
|
||||||
process, tool, machine,
|
process, tool, machine,
|
||||||
mmap_data, proc_map_timeout)) {
|
mmap_data, proc_map_timeout)) {
|
||||||
|
@ -586,6 +656,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(namespaces_event);
|
||||||
|
out_free_fork:
|
||||||
free(fork_event);
|
free(fork_event);
|
||||||
out_free_mmap:
|
out_free_mmap:
|
||||||
free(mmap_event);
|
free(mmap_event);
|
||||||
|
@ -605,6 +677,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
|
||||||
char proc_path[PATH_MAX];
|
char proc_path[PATH_MAX];
|
||||||
struct dirent *dirent;
|
struct dirent *dirent;
|
||||||
union perf_event *comm_event, *mmap_event, *fork_event;
|
union perf_event *comm_event, *mmap_event, *fork_event;
|
||||||
|
union perf_event *namespaces_event;
|
||||||
int err = -1;
|
int err = -1;
|
||||||
|
|
||||||
if (machine__is_default_guest(machine))
|
if (machine__is_default_guest(machine))
|
||||||
|
@ -622,11 +695,17 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
|
||||||
if (fork_event == NULL)
|
if (fork_event == NULL)
|
||||||
goto out_free_mmap;
|
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);
|
snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
|
||||||
proc = opendir(proc_path);
|
proc = opendir(proc_path);
|
||||||
|
|
||||||
if (proc == NULL)
|
if (proc == NULL)
|
||||||
goto out_free_fork;
|
goto out_free_namespaces;
|
||||||
|
|
||||||
while ((dirent = readdir(proc)) != NULL) {
|
while ((dirent = readdir(proc)) != NULL) {
|
||||||
char *end;
|
char *end;
|
||||||
|
@ -638,13 +717,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
|
||||||
* We may race with exiting thread, so don't stop just because
|
* We may race with exiting thread, so don't stop just because
|
||||||
* one thread couldn't be synthesized.
|
* one thread couldn't be synthesized.
|
||||||
*/
|
*/
|
||||||
__event__synthesize_thread(comm_event, mmap_event, fork_event, pid,
|
__event__synthesize_thread(comm_event, mmap_event, fork_event,
|
||||||
1, process, tool, machine, mmap_data,
|
namespaces_event, pid, 1, process,
|
||||||
|
tool, machine, mmap_data,
|
||||||
proc_map_timeout);
|
proc_map_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
closedir(proc);
|
closedir(proc);
|
||||||
|
out_free_namespaces:
|
||||||
|
free(namespaces_event);
|
||||||
out_free_fork:
|
out_free_fork:
|
||||||
free(fork_event);
|
free(fork_event);
|
||||||
out_free_mmap:
|
out_free_mmap:
|
||||||
|
|
|
@ -648,6 +648,12 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct machine *machine);
|
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,
|
int perf_event__synthesize_mmap_events(struct perf_tool *tool,
|
||||||
union perf_event *event,
|
union perf_event *event,
|
||||||
pid_t pid, pid_t tgid,
|
pid_t pid, pid_t tgid,
|
||||||
|
|
Loading…
Reference in New Issue