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 <dsah...@gmail.com>
Cc: Arjan van de Ven <ar...@linux.intel.com>
Cc: Namhyung Kim <namhy...@gmail.com>
Cc: Yanmin Zhang <yanmin.zh...@intel.com>
Cc: Wu Fengguang <fengguang...@intel.com>
Cc: Mike Galbraith <efa...@gmx.de>
Cc: Paul Mackerras <pau...@samba.org>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Ingo Molnar <mi...@redhat.com>
Cc: Arnaldo Carvalho de Melo <a...@ghostprotocols.net>
Cc: Andrew Morton <a...@linux-foundation.org>
Signed-off-by: Chenggang Qin <chenggang....@taobao.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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to