summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Miller <davem@davemloft.net>2018-10-31 01:24:04 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2018-10-31 09:18:01 -0400
commit4f8f382e635707ddaddf8269a116e4f8cc8835c0 (patch)
treec5fceab005fc1d526f7ce91d2323d52d530e6fb6
parentff27a06af6ffd3f49b9e193eb68f487ad76651e1 (diff)
perf tools: Don't clone maps from parent when synthesizing forks
When synthesizing FORK events, we are trying to create thread objects for the already running tasks on the machine. Normally, for a kernel FORK event, we want to clone the parent's maps because that is what the kernel just did. But when synthesizing, this should not be done. If we do, we end up with overlapping maps as we process the sythesized MMAP2 events that get delivered shortly thereafter. Use the FORK event misc flags in an internal way to signal this situation, so we can elide the map clone when appropriate. Signed-off-by: David S. Miller <davem@davemloft.net> Cc: Don Zickus <dzickus@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Joe Mario <jmario@redhat.com> Link: http://lkml.kernel.org/r/20181030.222404.2085088822877051075.davem@davemloft.net [ Added comment about flag use in machine__process_fork_event(), use ternary op in thread__clone_map_groups() as suggested by Jiri ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--include/uapi/linux/perf_event.h2
-rw-r--r--tools/include/uapi/linux/perf_event.h2
-rw-r--r--tools/perf/util/event.c1
-rw-r--r--tools/perf/util/machine.c19
-rw-r--r--tools/perf/util/thread.c13
-rw-r--r--tools/perf/util/thread.h2
6 files changed, 29 insertions, 10 deletions
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index f35eb72739c0..9de8780ac8d9 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -646,10 +646,12 @@ struct perf_event_mmap_page {
646 * 646 *
647 * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events 647 * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events
648 * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event 648 * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event
649 * PERF_RECORD_MISC_FORK_EXEC - PERF_RECORD_FORK event (perf internal)
649 * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events 650 * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events
650 */ 651 */
651#define PERF_RECORD_MISC_MMAP_DATA (1 << 13) 652#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
652#define PERF_RECORD_MISC_COMM_EXEC (1 << 13) 653#define PERF_RECORD_MISC_COMM_EXEC (1 << 13)
654#define PERF_RECORD_MISC_FORK_EXEC (1 << 13)
653#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) 655#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13)
654/* 656/*
655 * These PERF_RECORD_MISC_* flags below are safely reused 657 * These PERF_RECORD_MISC_* flags below are safely reused
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index f35eb72739c0..9de8780ac8d9 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -646,10 +646,12 @@ struct perf_event_mmap_page {
646 * 646 *
647 * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events 647 * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events
648 * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event 648 * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event
649 * PERF_RECORD_MISC_FORK_EXEC - PERF_RECORD_FORK event (perf internal)
649 * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events 650 * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events
650 */ 651 */
651#define PERF_RECORD_MISC_MMAP_DATA (1 << 13) 652#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
652#define PERF_RECORD_MISC_COMM_EXEC (1 << 13) 653#define PERF_RECORD_MISC_COMM_EXEC (1 << 13)
654#define PERF_RECORD_MISC_FORK_EXEC (1 << 13)
653#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) 655#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13)
654/* 656/*
655 * These PERF_RECORD_MISC_* flags below are safely reused 657 * These PERF_RECORD_MISC_* flags below are safely reused
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index bc646185f8d9..e9c108a6b1c3 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -308,6 +308,7 @@ static int perf_event__synthesize_fork(struct perf_tool *tool,
308 event->fork.pid = tgid; 308 event->fork.pid = tgid;
309 event->fork.tid = pid; 309 event->fork.tid = pid;
310 event->fork.header.type = PERF_RECORD_FORK; 310 event->fork.header.type = PERF_RECORD_FORK;
311 event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC;
311 312
312 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 313 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);
313 314
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 8ee8ab39d8ac..8f36ce813bc5 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1708,6 +1708,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1708 struct thread *parent = machine__findnew_thread(machine, 1708 struct thread *parent = machine__findnew_thread(machine,
1709 event->fork.ppid, 1709 event->fork.ppid,
1710 event->fork.ptid); 1710 event->fork.ptid);
1711 bool do_maps_clone = true;
1711 int err = 0; 1712 int err = 0;
1712 1713
1713 if (dump_trace) 1714 if (dump_trace)
@@ -1736,9 +1737,25 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1736 1737
1737 thread = machine__findnew_thread(machine, event->fork.pid, 1738 thread = machine__findnew_thread(machine, event->fork.pid,
1738 event->fork.tid); 1739 event->fork.tid);
1740 /*
1741 * When synthesizing FORK events, we are trying to create thread
1742 * objects for the already running tasks on the machine.
1743 *
1744 * Normally, for a kernel FORK event, we want to clone the parent's
1745 * maps because that is what the kernel just did.
1746 *
1747 * But when synthesizing, this should not be done. If we do, we end up
1748 * with overlapping maps as we process the sythesized MMAP2 events that
1749 * get delivered shortly thereafter.
1750 *
1751 * Use the FORK event misc flags in an internal way to signal this
1752 * situation, so we can elide the map clone when appropriate.
1753 */
1754 if (event->fork.header.misc & PERF_RECORD_MISC_FORK_EXEC)
1755 do_maps_clone = false;
1739 1756
1740 if (thread == NULL || parent == NULL || 1757 if (thread == NULL || parent == NULL ||
1741 thread__fork(thread, parent, sample->time) < 0) { 1758 thread__fork(thread, parent, sample->time, do_maps_clone) < 0) {
1742 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); 1759 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1743 err = -1; 1760 err = -1;
1744 } 1761 }
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 2048d393ece6..3d9ed7d0e281 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -330,7 +330,8 @@ static int thread__prepare_access(struct thread *thread)
330} 330}
331 331
332static int thread__clone_map_groups(struct thread *thread, 332static int thread__clone_map_groups(struct thread *thread,
333 struct thread *parent) 333 struct thread *parent,
334 bool do_maps_clone)
334{ 335{
335 /* This is new thread, we share map groups for process. */ 336 /* This is new thread, we share map groups for process. */
336 if (thread->pid_ == parent->pid_) 337 if (thread->pid_ == parent->pid_)
@@ -341,15 +342,11 @@ static int thread__clone_map_groups(struct thread *thread,
341 thread->pid_, thread->tid, parent->pid_, parent->tid); 342 thread->pid_, thread->tid, parent->pid_, parent->tid);
342 return 0; 343 return 0;
343 } 344 }
344
345 /* But this one is new process, copy maps. */ 345 /* But this one is new process, copy maps. */
346 if (map_groups__clone(thread, parent->mg) < 0) 346 return do_maps_clone ? map_groups__clone(thread, parent->mg) : 0;
347 return -ENOMEM;
348
349 return 0;
350} 347}
351 348
352int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) 349int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone)
353{ 350{
354 if (parent->comm_set) { 351 if (parent->comm_set) {
355 const char *comm = thread__comm_str(parent); 352 const char *comm = thread__comm_str(parent);
@@ -362,7 +359,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
362 } 359 }
363 360
364 thread->ppid = parent->tid; 361 thread->ppid = parent->tid;
365 return thread__clone_map_groups(thread, parent); 362 return thread__clone_map_groups(thread, parent, do_maps_clone);
366} 363}
367 364
368void thread__find_cpumode_addr_location(struct thread *thread, u64 addr, 365void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 36c09a9904e6..30e2b4c165fe 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -89,7 +89,7 @@ struct comm *thread__comm(const struct thread *thread);
89struct comm *thread__exec_comm(const struct thread *thread); 89struct comm *thread__exec_comm(const struct thread *thread);
90const char *thread__comm_str(const struct thread *thread); 90const char *thread__comm_str(const struct thread *thread);
91int thread__insert_map(struct thread *thread, struct map *map); 91int thread__insert_map(struct thread *thread, struct map *map);
92int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); 92int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone);
93size_t thread__fprintf(struct thread *thread, FILE *fp); 93size_t thread__fprintf(struct thread *thread, FILE *fp);
94 94
95struct thread *thread__main_thread(struct machine *machine, struct thread *thread); 95struct thread *thread__main_thread(struct machine *machine, struct thread *thread);