lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Thu, 20 Dec 2012 17:07:15 +0800
From:	chenggang <chenggang.qin@...il.com>
To:	linux-kernel@...r.kernel.org
Cc:	chenggang <chenggang.qin@...il.com>,
	David Ahern <dsahern@...il.com>,
	Arjan van de Ven <arjan@...ux.intel.com>,
	Namhyung Kim <namhyung@...il.com>,
	Yanmin Zhang <yanmin.zhang@...el.com>,
	Wu Fengguang <fengguang.wu@...el.com>,
	Mike Galbraith <efault@....de>,
	Paul Mackerras <paulus@...ba.org>,
	Peter Zijlstra <peterz@...radead.org>,
	Ingo Molnar <mingo@...hat.com>,
	Arnaldo Carvalho de Melo <acme@...stprotocols.net>,
	Andrew Morton <akpm@...ux-foundation.org>,
	Chenggang Qin <chenggang.qcg@...bao.com>
Subject: [PATCH 5/5] perf top: Add the function to make 'perf top -p $pid' could be aware of new forked thread.

This patch implemnet a fork function and a exit function in perf_top->tool to respond to
PERF_RECORD_FORK & PERF_RECORD_EXIT events. In the fork function 
(perf_top__process_event_fork), the information of the new thread is added into
thread_map. The fd and mmap of the new thread are created in this function also.
In the exit function (perf_top__process_event_exit), the information of the exited
thread are removed from thread_map. The fd and mmap of this thread are closed
in this function also.
Based on this patch, 'perf top -p $pid' can be aware of thread's fork and exit on-the-fly.
The new forked threads' sample events can be got by 'perf top'. And the symbols of the new
forked threads can be display on the ui.

Cc: David Ahern <dsahern@...il.com>
Cc: Arjan van de Ven <arjan@...ux.intel.com>
Cc: Namhyung Kim <namhyung@...il.com>
Cc: Yanmin Zhang <yanmin.zhang@...el.com>
Cc: Wu Fengguang <fengguang.wu@...el.com>
Cc: Mike Galbraith <efault@....de>
Cc: Paul Mackerras <paulus@...ba.org>
Cc: Peter Zijlstra <peterz@...radead.org>
Cc: Ingo Molnar <mingo@...hat.com>
Cc: Arnaldo Carvalho de Melo <acme@...stprotocols.net>
Cc: Andrew Morton <akpm@...ux-foundation.org>
Signed-off-by: Chenggang Qin <chenggang.qcg@...bao.com>
---
 tools/perf/builtin-top.c |  135 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 135 insertions(+)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index b3650e3..e7978ce 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -844,6 +844,17 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
 		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, machine);
+
+		if (cpu_map__all(top->evlist->cpus) &&
+		    event->header.type == PERF_RECORD_EXIT) {
+			int close_nr;
+
+			close_nr = (&top->tool)->exit(&top->tool, event,
+						      &sample, machine);
+			if (close_nr == idx)
+				return;
+		}
+
 		switch (origin) {
 		case PERF_RECORD_MISC_USER:
 			++top->us_samples;
@@ -896,6 +907,26 @@ static void perf_top__mmap_read(struct perf_top *top)
 			perf_top__mmap_read_idx(top, i);
 }
 
+static void perf_top__append_thread(struct perf_top *top, int append_nr,
+				     bool need_realloc)
+{
+	struct perf_evsel *counter;
+	struct perf_evlist *evlist = top->evlist;
+	int err;
+
+	list_for_each_entry(counter, &evlist->entries, node) {
+		err = perf_evsel__append_open(counter, top->evlist->cpus,
+					      top->evlist->threads,
+					      append_nr, need_realloc);
+
+		if (err == ESRCH) {
+			top->evlist->threads->map[append_nr] = -1;
+			clear_bit(append_nr, top->evlist->threads->bitmap);
+			return;
+		} else if (err < 0)
+			ui__error("append open error: %d\n", errno);
+	}
+}
+
 static void perf_top__start_counters(struct perf_top *top)
 {
 	struct perf_evsel *counter;
@@ -1174,12 +1205,116 @@ setup:
 	return 0;
 }
 
+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)
+{
+	struct perf_top *top = container_of(tool, struct perf_top, tool);
+	pid_t tid = event->fork.tid;
+	pid_t ptid = event->fork.ptid;
+	int append_nr = -1;
+	int thread;
+
+	/*
+	 * There are 2 same fork events are received while a thread was forked.
+	 * This may be a kernel bug.
+	 */
+	for_each_set_bit(thread, top->evlist->threads->bitmap, PID_MAX_DEFAULT)
+		if (tid == top->evlist->threads->map[thread])
+			return -1;
+
+	for_each_set_bit(thread, top->evlist->threads->bitmap, PID_MAX_DEFAULT) {
+		/*
+		 * If new thread's parent is not target task, just ignore it.
+		 */
+		if (ptid == top->evlist->threads->map[thread]) {
+			bool realloc_need;
+
+			append_nr = thread_map__update(&(top->evlist->threads),
+						       tid, &realloc_need);
+			/*
+			 * Open counters for new thread.
+			 */
+			perf_top__append_thread(top, append_nr, realloc_need);
+
+			if (perf_evlist__mmap(top->evlist, top->mmap_pages,
+					      false, append_nr, realloc_need) < 0) {
+				ui__error("mmap append error!\n");
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int close_thread(struct perf_top *top, int close_nr)
+{
+	struct perf_evsel *evsel;
+
+	clear_bit(close_nr, top->evlist->threads->bitmap);
+
+	top->evlist->threads->map[close_nr] = -1;
+	top->evlist->threads->nr--;
+
+	if (cpu_map__all(top->evlist->cpus)) {
+		munmap(top->evlist->mmap[close_nr].base, top->evlist->mmap_len);
+		top->evlist->mmap[close_nr].base = NULL;
+		top->evlist->nr_mmaps--;
+	}
+
+	perf_evlist_remove_pollfd(top->evlist, close_nr);
+
+	list_for_each_entry(evsel, &top->evlist->entries, node) {
+		int cpu;
+
+		for (cpu = 0; cpu < cpu_map__nr(evsel->cpus); cpu++) {
+			int fd;
+
+			if (evsel->attr.read_format & PERF_FORMAT_ID)
+				perf_evlist__id_remove(evsel, cpu, close_nr);
+
+			fd = FD(evsel, cpu, close_nr);
+			if (fd)
+				close(fd);
+		}
+	}
+
+	return 0;
+}
+
+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)
+{
+	struct perf_top *top = container_of(tool, struct perf_top, tool);
+	pid_t tid = event->fork.tid;
+	int bit;
+	int close_nr = 0;
+
+	for_each_set_bit(bit, top->evlist->threads->bitmap, PID_MAX_DEFAULT) {
+		if (tid == top->evlist->threads->map[bit]) {
+			close_thread(top, bit);
+			close_nr = bit;
+		}
+	}
+
+	return close_nr;
+}
+
 int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_evsel *pos;
 	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,
 		.freq		     = 4000, /* 4 KHz */
--
1.7.9.5

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

Powered by blists - more mailing lists