linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 8/8]Perf: Add some callback functions to process fork & exit events
@ 2013-03-13  9:42 chenggang
  2013-03-13  9:42 ` [PATCH v3 7/8]Perf: changed the method to traverse mmap list chenggang
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: chenggang @ 2013-03-13  9:42 UTC (permalink / raw)
  To: linux-kernel
  Cc: chenggang, David Ahern, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, Arnaldo Carvalho de Melo, Arjan van de Ven,
	Namhyung Kim, Yanmin Zhang, Wu Fengguang, Mike Galbraith,
	Andrew Morton

From: chenggang <chenggang.qcg@taobao.com>

Many applications will fork threads on-the-fly, these threads could exit before
the main thread exit. The perf top tool should perceive the new forked threads
while we profile a special application.
If the target process fork a thread or a thread exit, we will get a PERF_RECORD_FORK
 or PERF_RECORD_EXIT events. The following callback functions can process these events.
1) perf_top__process_event_fork()
   Open a new fd for the new forked, and expend the related data structures.
2) perf_top__process_event_exit()
   Close the fd of exit threadsd, and destroy the nodes in the related data structures.

Cc: David Ahern <dsahern@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Yanmin Zhang <yanmin.zhang@intel.com>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Chenggang Qin <chenggang.qcg@taobao.com>

---
 tools/perf/builtin-top.c |  109 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 107 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index cff58e5..a591b96 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -800,7 +800,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
 	return;
 }
 
-static void perf_top__mmap_read_idx(struct perf_top *top, struct perf_mmap *md)
+static int perf_top__mmap_read_idx(struct perf_top *top, struct perf_mmap *md,
+				    int idx)
 {
 	struct perf_sample sample;
 	struct perf_evsel *evsel;
@@ -825,6 +826,20 @@ static void perf_top__mmap_read_idx(struct perf_top *top, struct perf_mmap *md)
 		if (event->header.type == PERF_RECORD_SAMPLE)
 			++top->samples;
 
+		if (cpu_map__all(top->evlist->cpus) &&
+		    event->header.type == PERF_RECORD_FORK)
+			(&top->tool)->fork(&top->tool, event, &sample, NULL);
+
+		if (cpu_map__all(top->evlist->cpus) &&
+		    event->header.type == PERF_RECORD_EXIT) {
+			int tidx;
+
+			tidx = (&top->tool)->exit(&top->tool, event,
+						  &sample, NULL);
+			if (tidx == idx)
+				return -1;
+		}
+
 		switch (origin) {
 		case PERF_RECORD_MISC_USER:
 			++top->us_samples;
@@ -863,14 +878,18 @@ static void perf_top__mmap_read_idx(struct perf_top *top, struct perf_mmap *md)
 		} else
 			++session->stats.nr_unknown_events;
 	}
+	return 0;
 }
 
 static void perf_top__mmap_read(struct perf_top *top)
 {
 	struct perf_mmap *md;
+	int i = 0;
 
 	for_each_mmap(md, top->evlist) {
-		perf_top__mmap_read_idx(top, md);
+		if (perf_top__mmap_read_idx(top, md, i) == -1)
+			break;
+		i++;
 	}
 }
 
@@ -1025,11 +1044,97 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
 	return record_parse_callchain_opt(opt, arg, unset);
 }
 
+static int perf_top__append_thread(struct perf_top *top, pid_t pid)
+{
+	char msg[512];
+	struct perf_evsel *counter, *counter_err;
+	struct perf_evlist *evlist = top->evlist;
+	struct cpu_map *cpus = evlist->cpus;
+
+	counter_err = list_entry(evlist->entries.prev, struct perf_evsel, node);
+
+	list_for_each_entry(counter, &evlist->entries, node) {
+		if (perf_evsel__open_single_thread(counter, cpus, pid) < 0) {
+			if (verbose) {
+				perf_evsel__open_strerror(counter,
+							  &top->record_opts.target,
+							  errno, msg, sizeof(msg));
+				ui__warning("%s\n", msg);
+			}
+			counter_err = counter;
+			goto close_opened_fd;
+		}
+	}
+
+	if (perf_evlist__mmap_thread(evlist, false) < 0)
+		goto close_opened_fd;
+
+	return 0;
+
+close_opened_fd:
+	list_for_each_entry(counter, &evlist->entries, node) {
+		perf_evsel__close_single_thread(counter, cpus->nr, -1);
+		if (counter == counter_err)
+			break;
+	}
+	return -1;
+}
+
+static int perf_top__process_event_fork(struct perf_tool *tool __maybe_unused,
+					union perf_event *event __maybe_unused,
+					struct perf_sample *sample __maybe_unused,
+					struct machine *machine __maybe_unused)
+{
+	pid_t tid = event->fork.tid;
+	struct perf_top *top = container_of(tool, struct perf_top, tool);
+	struct thread_map *threads = top->evlist->threads;
+	int ret;
+
+	ret = thread_map__append(threads, tid); 
+	if (ret != 0)                   
+		return ret;             
+
+	if (perf_top__append_thread(top, tid) < 0)
+		goto free_new_thread;
+
+	return 0; 
+
+free_new_thread:
+	thread_map__remove(threads, -1);
+	return -1;
+}
+
+static int perf_top__process_event_exit(struct perf_tool *tool __maybe_unused,
+					union perf_event *event __maybe_unused,
+					struct perf_sample *sample __maybe_unused,
+					struct machine *machine __maybe_unused)
+{
+	pid_t tid = event->fork.tid;
+	struct perf_top *top = container_of(tool, struct perf_top, tool);
+	struct perf_evsel *evsel;
+	struct thread_map *threads = top->evlist->threads;
+	int tidx = thread_map__get_idx_by_pid(threads, tid);
+
+	if (tidx < 0)
+		return -1;
+
+	perf_evlist__munmap_thread(top->evlist, tidx);
+	list_for_each_entry(evsel, &top->evlist->entries, node) {
+		perf_evsel__close_single_thread(evsel, top->evlist->cpus->nr, tidx);
+	}
+	thread_map__remove(threads, tidx);
+	return tidx;
+}
+
 int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	int status;
 	char errbuf[BUFSIZ];
 	struct perf_top top = {
+		.tool = {
+			.fork		= perf_top__process_event_fork,
+			.exit		= perf_top__process_event_exit,
+		},
 		.count_filter	     = 5,
 		.delay_secs	     = 2,
 		.record_opts = {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2013-03-17 23:45 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-13  9:42 [PATCH v3 8/8]Perf: Add some callback functions to process fork & exit events chenggang
2013-03-13  9:42 ` [PATCH v3 7/8]Perf: changed the method to traverse mmap list chenggang
2013-03-13  9:42 ` [PATCH v3 6/8]Perf: Add extend mechanism for mmap & pollfd chenggang
2013-03-13  9:42 ` [PATCH v3 5/8]Perf: add extend mechanism for evsel->id & evsel->fd chenggang
2013-03-13  9:42 ` [PATCH v3 4/8]perf: Transform evsel->id to xyarray chenggang
2013-03-17 23:45   ` David Ahern
2013-03-13  9:42 ` [PATCH v3 3/8]Perf: Transform evlist->mmap " chenggang
2013-03-17 23:42   ` David Ahern
2013-03-13  9:42 ` [PATCH v3 2/8]Perf: Transform xyarray to linked list chenggang
2013-03-13  9:42 ` [PATCH v3 1/8]Perf: Transform thread_map " chenggang
2013-03-17 23:37   ` David Ahern
2013-03-13  9:42 ` [PATCH v3 0/8]Perf: Make the 'perf top -p $pid' can perceive the new forked threads chenggang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).