[PATCH 04/20] perf tools: Fix FORK after COMM when synthesizing records for pre-existing threads

From: Arnaldo Carvalho de Melo
Date: Mon Mar 02 2015 - 22:32:14 EST


From: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>

In this commit:

commit 363b785f3805a2632eb09a8b430842461c21a640
Author: Don Zickus <dzickus@xxxxxxxxxx>
Date: Fri Mar 14 10:43:44 2014 -0400

perf tools: Speed up thread map generation

We ended up emitting PERF_RECORD_FORK events after their corresponding
PERF_RECORD_COMM, so the code below will remove the "existing thread"
and then recreates it, unnecessarily:

[root@ssdandy ~]# perf probe -x ~/bin/perf -L machine__process_fork_event
<machine__process_fork_event@/home/acme/git/linux/tools/perf/util/machine.c:0>
0 int machine__process_fork_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample)
2 {
3 struct thread *thread = machine__find_thread(machine,
event->fork.pid,
event->fork.tid);
6 struct thread *parent = machine__findnew_thread(machine,
event->fork.ppid,
event->fork.ptid);

/* if a thread currently exists for the thread id remove it */
if (thread != NULL)
12 machine__remove_thread(machine, thread);

14 thread = machine__findnew_thread(machine, event->fork.pid,
event->fork.tid);
16 if (dump_trace)
17 perf_event__fprintf_task(event, stdout);

19 if (thread == NULL || parent == NULL ||
20 thread__fork(thread, parent, sample->time) < 0) {
21 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
22 return -1;
}

25 return 0;
26 }

[root@ssdandy ~]# perf probe -x ~/bin/perf fork_after_comm=machine__process_fork_event:12
Added new event:
probe_perf:fork_after_comm (on machine__process_fork_event:12 in /home/acme/bin/perf)

You can now use it in all perf tools, such as:

perf record -e probe_perf:fork_after_comm -aR sleep 1

[root@ssdandy ~]#

[root@ssdandy ~]# perf record -g -e probe_perf:* trace -o /tmp/bla
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.021 MB perf.data (30 samples) ]
Terminated
[root@ssdandy ~]#

[root@ssdandy ~]# perf report --no-children --show-total-period --stdio
# To display the perf.data header info, please use --header/--header-only options.
#
# Samples: 30 of event 'probe_perf:fork_after_comm'
# Event count (approx.): 30
#
# Overhead Period Command Shared Object Symbol
# ........ ............ ....... ............. ...............................
#
100.00% 30 trace trace [.] machine__process_fork_event
|
---machine__process_fork_event
__event__synthesize_thread.part.2
perf_event__synthesize_threads
cmd_trace
main
__libc_start_main

[root@ssdandy ~]#

And Looking at 'perf report -D' output we see it:

0 0 0x8698 [0x30]: PERF_RECORD_COMM: auditd:703/707
0 0 0x86c8 [0x38]: PERF_RECORD_FORK(703:707):(703:703)

Fix it by more closely mimicking how the kernel generates those records
when a new fork happens, i.e. first a PERF_RECORD_FORK, then a
PERF_RECORD_COMM.

Cc: Adrian Hunter <adrian.hunter@xxxxxxxxx>
Cc: Borislav Petkov <bp@xxxxxxx>
Cc: David Ahern <dsahern@xxxxxxxxx>
Cc: Don Zickus <dzickus@xxxxxxxxxx>
Cc: Frederic Weisbecker <fweisbec@xxxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: Namhyung Kim <namhyung@xxxxxxxxxx>
Cc: Stephane Eranian <eranian@xxxxxxxxxx>
Link: http://lkml.kernel.org/n/tip-h0emvymi2t3mw8dlqd6d6z73@xxxxxxxxxxxxxx
Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
---
tools/perf/util/event.c | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 9e806d855b04..d5efa5092ce6 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -95,9 +95,7 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
return tgid;
}

-static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
- union perf_event *event, pid_t pid,
- perf_event__handler_t process,
+static pid_t perf_event__prepare_comm(union perf_event *event, pid_t pid,
struct machine *machine)
{
size_t size;
@@ -124,6 +122,19 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
(sizeof(event->comm.comm) - size) +
machine->id_hdr_size);
event->comm.tid = pid;
+out:
+ return tgid;
+}
+
+static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
+ union perf_event *event, pid_t pid,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ pid_t tgid = perf_event__prepare_comm(event, pid, machine);
+
+ if (tgid == -1)
+ goto out;

if (process(tool, event, &synth_sample, machine) != 0)
return -1;
@@ -139,7 +150,6 @@ static int perf_event__synthesize_fork(struct perf_tool *tool,
{
memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size);

- /* this is really a clone event but we use fork to synthesize it */
event->fork.ppid = tgid;
event->fork.ptid = tgid;
event->fork.pid = tgid;
@@ -368,19 +378,23 @@ static int __event__synthesize_thread(union perf_event *comm_event,
if (*end)
continue;

- tgid = perf_event__synthesize_comm(tool, comm_event, _pid,
- process, machine);
+ tgid = perf_event__prepare_comm(comm_event, _pid, machine);
if (tgid == -1)
return -1;

+ if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
+ process, machine) < 0)
+ return -1;
+ /*
+ * Send the prepared comm event
+ */
+ if (process(tool, comm_event, &synth_sample, machine) != 0)
+ return -1;
+
if (_pid == pid) {
/* process the parent's maps too */
rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
process, machine, mmap_data);
- } else {
- /* only fork the tid's map, to save time */
- rc = perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
- process, machine);
}

if (rc)
--
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/