perf browsers: Add live mode to the hists, annotate browsers
authorArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 5 Oct 2011 22:11:32 +0000 (19:11 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 7 Oct 2011 15:12:51 +0000 (12:12 -0300)
This allows passing a timer to be run periodically, which will update
the hists tree that then gers refreshed on the screen, just like the
Live mode (symbol entries, annotation) we already have in 'perf top
--tui'.

Will be used by the new hist_entry/hists based 'top' tool.

Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-2r44qd8oe4sagzcgoikl8qzc@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-annotate.c
tools/perf/builtin-report.c
tools/perf/util/annotate.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/hist.h
tools/perf/util/ui/browsers/annotate.c
tools/perf/util/ui/browsers/hists.c
tools/perf/util/ui/browsers/top.c

index cf68819f7453fbb1213c4e3b6b0c90dcda45b042..39e3d382b2d809b832981bb693e4374d6e6ac643 100644 (file)
@@ -137,7 +137,7 @@ find_next:
                }
 
                if (use_browser > 0) {
-                       key = hist_entry__tui_annotate(he, evidx);
+                       key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0);
                        switch (key) {
                        case KEY_RIGHT:
                                next = rb_next(nd);
index c1cc7ab6f84931ddf7b0ee707c75da694c94c2e6..e7140c6289b8441423c5af3d749e3bd6ba06eb4c 100644 (file)
@@ -327,9 +327,10 @@ static int __cmd_report(void)
                goto out_delete;
        }
 
-       if (use_browser > 0)
-               perf_evlist__tui_browse_hists(session->evlist, help);
-       else
+       if (use_browser > 0) {
+               perf_evlist__tui_browse_hists(session->evlist, help,
+                                             NULL, NULL, 0);
+       } else
                perf_evlist__tty_browse_hists(session->evlist, help);
 
 out_delete:
index 6ede1286ee71ff2c0e669109c2434ddd6d0f164b..aafbc7e9a9baf53af2344ed335b7dc828188aca0 100644 (file)
@@ -91,13 +91,16 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
 #ifdef NO_NEWT_SUPPORT
 static inline int symbol__tui_annotate(struct symbol *sym __used,
                                       struct map *map __used,
-                                      int evidx __used, int refresh __used)
+                                      int evidx __used,
+                                      void(*timer)(void *arg) __used,
+                                      void *arg __used, int delay_secs __used)
 {
        return 0;
 }
 #else
 int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
-                        int refresh);
+                        void(*timer)(void *arg), void *arg,
+                        int delay_secs);
 #endif
 
 extern const char      *disassembler_style;
index 72e9f4886b6d062f1d239a78de3c03f4c52f797c..2f6bc89027da7eb78b349bb71aa7c4765cbd2c27 100644 (file)
@@ -533,3 +533,9 @@ bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
        first = list_entry(evlist->entries.next, struct perf_evsel, node);
        return first->attr.sample_id_all;
 }
+
+void perf_evlist__set_selected(struct perf_evlist *evlist,
+                              struct perf_evsel *evsel)
+{
+       evlist->selected = evsel;
+}
index f3491500274576965dfc800bfb27a788f5423dc6..6be71fc57794e0fe67a68c7ca20cd60482ba556c 100644 (file)
@@ -25,6 +25,7 @@ struct perf_evlist {
        struct pollfd    *pollfd;
        struct thread_map *threads;
        struct cpu_map    *cpus;
+       struct perf_evsel *selected;
 };
 
 struct perf_evsel;
@@ -56,6 +57,9 @@ void perf_evlist__munmap(struct perf_evlist *evlist);
 void perf_evlist__disable(struct perf_evlist *evlist);
 void perf_evlist__enable(struct perf_evlist *evlist);
 
+void perf_evlist__set_selected(struct perf_evlist *evlist,
+                              struct perf_evsel *evsel);
+
 static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
                                         struct cpu_map *cpus,
                                         struct thread_map *threads)
index d3f976cc7c56b71141c24012ef64ba97dd87271c..424f9eb8310c8d5ea692bc10e1df48936a1fc148 100644 (file)
@@ -100,13 +100,16 @@ struct perf_evlist;
 #ifdef NO_NEWT_SUPPORT
 static inline
 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
-                                 const char *help __used)
+                                 const char *help __used, void(*timer)(void *arg) __used, void *arg,
+                                 int refresh __used)
 {
        return 0;
 }
 
 static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
-                                          int evidx __used)
+                                          int evidx __used,
+                                          void(*timer)(void *arg) __used,
+                                          void *arg __used, int delay_secs __used);
 {
        return 0;
 }
@@ -114,12 +117,15 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
 #define KEY_RIGHT -2
 #else
 #include <newt.h>
-int hist_entry__tui_annotate(struct hist_entry *self, int evidx);
+int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
+                            void(*timer)(void *arg), void *arg, int delay_secs);
 
 #define KEY_LEFT NEWT_KEY_LEFT
 #define KEY_RIGHT NEWT_KEY_RIGHT
 
-int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help);
+int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
+                                 void(*timer)(void *arg), void *arg,
+                                 int refresh);
 #endif
 
 unsigned int hists__sort_list_width(struct hists *self);
index 0229723aceb320bb9d7ae0a92bfb2a9820a132a5..76c1d083aa94cbfcde271313649618ea694b7edd 100644 (file)
@@ -164,7 +164,8 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
 }
 
 static int annotate_browser__run(struct annotate_browser *self, int evidx,
-                                int refresh)
+                                void(*timer)(void *arg) __used, void *arg __used,
+                                int delay_secs)
 {
        struct rb_node *nd = NULL;
        struct symbol *sym = self->b.priv;
@@ -189,13 +190,13 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
 
        nd = self->curr_hot;
 
-       if (refresh != 0)
-               newtFormSetTimer(self->b.form, refresh);
+       if (delay_secs != 0)
+               newtFormSetTimer(self->b.form, delay_secs * 1000);
 
        while (1) {
                key = ui_browser__run(&self->b);
 
-               if (refresh != 0) {
+               if (delay_secs != 0) {
                        annotate_browser__calc_percent(self, evidx);
                        /*
                         * Current line focus got out of the list of most active
@@ -212,7 +213,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
                         * FIXME we need to check if it was
                         * es.reason == NEWT_EXIT_TIMER
                         */
-                       if (refresh != 0)
+                       if (timer != NULL)
+                               timer(arg);
+
+                       if (delay_secs != 0)
                                symbol__annotate_decay_histogram(sym, evidx);
                        continue;
                case NEWT_KEY_TAB:
@@ -246,13 +250,16 @@ out:
        return key;
 }
 
-int hist_entry__tui_annotate(struct hist_entry *he, int evidx)
+int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
+                            void(*timer)(void *arg), void *arg, int delay_secs)
 {
-       return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0);
+       return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
+                                   timer, arg, delay_secs);
 }
 
 int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
-                        int refresh)
+                       void(*timer)(void *arg), void *arg,
+                       int delay_secs)
 {
        struct objdump_line *pos, *n;
        struct annotation *notes;
@@ -293,7 +300,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
 
        browser.b.entries = &notes->src->source,
        browser.b.width += 18; /* Percentage */
-       ret = annotate_browser__run(&browser, evidx, refresh);
+       ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
        list_for_each_entry_safe(pos, n, &notes->src->source, node) {
                list_del(&pos->node);
                objdump_line__free(pos);
index 5d767c622dfc1f862fb747ababa610e9031944c8..6244d19bd1f2a436e4e47b3a5105411402e08766 100644 (file)
@@ -24,8 +24,14 @@ struct hist_browser {
        struct hists        *hists;
        struct hist_entry   *he_selection;
        struct map_symbol   *selection;
+       const struct thread *thread_filter;
+       const struct dso    *dso_filter;
 };
 
+static int hists__browser_title(struct hists *self, char *bf, size_t size,
+                               const char *ev_name, const struct dso *dso,
+                               const struct thread *thread);
+
 static void hist_browser__refresh_dimensions(struct hist_browser *self)
 {
        /* 3 == +/- toggle symbol before actual hist_entry rendering */
@@ -290,9 +296,12 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
        ui_browser__reset_index(&self->b);
 }
 
-static int hist_browser__run(struct hist_browser *self, const char *title)
+static int hist_browser__run(struct hist_browser *self, const char *ev_name,
+                            void(*timer)(void *arg), void *arg, int delay_secs)
 {
        int key;
+       int delay_msecs = delay_secs * 1000;
+       char title[160];
        int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't',
                            NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
                            NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
@@ -301,17 +310,30 @@ static int hist_browser__run(struct hist_browser *self, const char *title)
        self->b.nr_entries = self->hists->nr_entries;
 
        hist_browser__refresh_dimensions(self);
+       hists__browser_title(self->hists, title, sizeof(title), ev_name,
+                            self->dso_filter, self->thread_filter);
 
        if (ui_browser__show(&self->b, title,
                             "Press '?' for help on key bindings") < 0)
                return -1;
 
+       if (timer != NULL)
+               newtFormSetTimer(self->b.form, delay_msecs);
+
        ui_browser__add_exit_keys(&self->b, exit_keys);
 
        while (1) {
                key = ui_browser__run(&self->b);
 
                switch (key) {
+               case -1:
+                       /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
+                       timer(arg);
+                       hists__browser_title(self->hists, title, sizeof(title),
+                                            ev_name, self->dso_filter,
+                                            self->thread_filter);
+                       ui_browser__show_title(&self->b, title);
+                       continue;
                case 'D': { /* Debug */
                        static int seq;
                        struct hist_entry *h = rb_entry(self->b.top,
@@ -805,14 +827,13 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
 
 static int perf_evsel__hists_browse(struct perf_evsel *evsel,
                                    const char *helpline, const char *ev_name,
-                                   bool left_exits)
+                                   bool left_exits,
+                                   void(*timer)(void *arg), void *arg,
+                                   int delay_secs)
 {
        struct hists *self = &evsel->hists;
        struct hist_browser *browser = hist_browser__new(self);
        struct pstack *fstack;
-       const struct thread *thread_filter = NULL;
-       const struct dso *dso_filter = NULL;
-       char msg[160];
        int key = -1;
 
        if (browser == NULL)
@@ -824,8 +845,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
 
        ui_helpline__push(helpline);
 
-       hists__browser_title(self, msg, sizeof(msg), ev_name,
-                            dso_filter, thread_filter);
        while (1) {
                const struct thread *thread = NULL;
                const struct dso *dso = NULL;
@@ -834,7 +853,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
                    annotate = -2, zoom_dso = -2, zoom_thread = -2,
                    browse_map = -2;
 
-               key = hist_browser__run(browser, msg);
+               key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
 
                if (browser->he_selection != NULL) {
                        thread = hist_browser__selected_thread(browser);
@@ -889,9 +908,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
                                continue;
                        }
                        top = pstack__pop(fstack);
-                       if (top == &dso_filter)
+                       if (top == &browser->dso_filter)
                                goto zoom_out_dso;
-                       if (top == &thread_filter)
+                       if (top == &browser->thread_filter)
                                goto zoom_out_thread;
                        continue;
                }
@@ -913,14 +932,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
 
                if (thread != NULL &&
                    asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
-                            (thread_filter ? "out of" : "into"),
+                            (browser->thread_filter ? "out of" : "into"),
                             (thread->comm_set ? thread->comm : ""),
                             thread->pid) > 0)
                        zoom_thread = nr_options++;
 
                if (dso != NULL &&
                    asprintf(&options[nr_options], "Zoom %s %s DSO",
-                            (dso_filter ? "out of" : "into"),
+                            (browser->dso_filter ? "out of" : "into"),
                             (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
                        zoom_dso = nr_options++;
 
@@ -949,45 +968,42 @@ do_annotate:
                        if (he == NULL)
                                continue;
 
-                       hist_entry__tui_annotate(he, evsel->idx);
+                       hist_entry__tui_annotate(he, evsel->idx,
+                                                timer, arg, delay_secs);
                } else if (choice == browse_map)
                        map__browse(browser->selection->map);
                else if (choice == zoom_dso) {
 zoom_dso:
-                       if (dso_filter) {
-                               pstack__remove(fstack, &dso_filter);
+                       if (browser->dso_filter) {
+                               pstack__remove(fstack, &browser->dso_filter);
 zoom_out_dso:
                                ui_helpline__pop();
-                               dso_filter = NULL;
+                               browser->dso_filter = NULL;
                        } else {
                                if (dso == NULL)
                                        continue;
                                ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
                                                   dso->kernel ? "the Kernel" : dso->short_name);
-                               dso_filter = dso;
-                               pstack__push(fstack, &dso_filter);
+                               browser->dso_filter = dso;
+                               pstack__push(fstack, &browser->dso_filter);
                        }
-                       hists__filter_by_dso(self, dso_filter);
-                       hists__browser_title(self, msg, sizeof(msg), ev_name,
-                                            dso_filter, thread_filter);
+                       hists__filter_by_dso(self, browser->dso_filter);
                        hist_browser__reset(browser);
                } else if (choice == zoom_thread) {
 zoom_thread:
-                       if (thread_filter) {
-                               pstack__remove(fstack, &thread_filter);
+                       if (browser->thread_filter) {
+                               pstack__remove(fstack, &browser->thread_filter);
 zoom_out_thread:
                                ui_helpline__pop();
-                               thread_filter = NULL;
+                               browser->thread_filter = NULL;
                        } else {
                                ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
                                                   thread->comm_set ? thread->comm : "",
                                                   thread->pid);
-                               thread_filter = thread;
-                               pstack__push(fstack, &thread_filter);
+                               browser->thread_filter = thread;
+                               pstack__push(fstack, &browser->thread_filter);
                        }
-                       hists__filter_by_thread(self, thread_filter);
-                       hists__browser_title(self, msg, sizeof(msg), ev_name,
-                                            dso_filter, thread_filter);
+                       hists__filter_by_thread(self, browser->thread_filter);
                        hist_browser__reset(browser);
                }
        }
@@ -1026,9 +1042,11 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
                menu->selection = evsel;
 }
 
-static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
+static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help,
+                               void(*timer)(void *arg), void *arg, int delay_secs)
 {
        int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
+       int delay_msecs = delay_secs * 1000;
        struct perf_evlist *evlist = menu->b.priv;
        struct perf_evsel *pos;
        const char *ev_name, *title = "Available samples";
@@ -1038,20 +1056,29 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
                             "ESC: exit, ENTER|->: Browse histograms") < 0)
                return -1;
 
+       if (timer != NULL)
+               newtFormSetTimer(menu->b.form, delay_msecs);
+
        ui_browser__add_exit_keys(&menu->b, exit_keys);
 
        while (1) {
                key = ui_browser__run(&menu->b);
 
                switch (key) {
+               case -1:
+                       /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
+                       timer(arg);
+                       continue;
                case NEWT_KEY_RIGHT:
                case NEWT_KEY_ENTER:
                        if (!menu->selection)
                                continue;
                        pos = menu->selection;
+                       perf_evlist__set_selected(evlist, pos);
 browse_hists:
                        ev_name = event_name(pos);
-                       key = perf_evsel__hists_browse(pos, help, ev_name, true);
+                       key = perf_evsel__hists_browse(pos, help, ev_name, true,
+                                                      timer, arg, delay_secs);
                        ui_browser__show_title(&menu->b, title);
                        break;
                case NEWT_KEY_LEFT:
@@ -1091,7 +1118,9 @@ out:
 }
 
 static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
-                                          const char *help)
+                                          const char *help,
+                                          void(*timer)(void *arg), void *arg,
+                                          int delay_secs)
 {
        struct perf_evsel *pos;
        struct perf_evsel_menu menu = {
@@ -1121,18 +1150,22 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
                        pos->name = strdup(ev_name);
        }
 
-       return perf_evsel_menu__run(&menu, help);
+       return perf_evsel_menu__run(&menu, help, timer, arg, delay_secs);
 }
 
-int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help)
+int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
+                                 void(*timer)(void *arg), void *arg,
+                                 int delay_secs)
 {
 
        if (evlist->nr_entries == 1) {
                struct perf_evsel *first = list_entry(evlist->entries.next,
                                                      struct perf_evsel, node);
                const char *ev_name = event_name(first);
-               return perf_evsel__hists_browse(first, help, ev_name, false);
+               return perf_evsel__hists_browse(first, help, ev_name, false,
+                                               timer, arg, delay_secs);
        }
 
-       return __perf_evlist__tui_browse_hists(evlist, help);
+       return __perf_evlist__tui_browse_hists(evlist, help,
+                                              timer, arg, delay_secs);
 }
index 9b6b43b32ac8f10a2c9b92ea3f6eb45b1e32e103..d43875b2356fa59e530f8c94646d70ffa4ada1da 100644 (file)
@@ -142,7 +142,7 @@ static void perf_top_browser__annotate(struct perf_top_browser *browser)
 
        pthread_mutex_unlock(&notes->lock);
 do_annotation:
-       symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
+       symbol__tui_annotate(sym, syme->map, 0, NULL, NULL, top->delay_secs * 1000);
 }
 
 static void perf_top_browser__warn_lost(struct perf_top_browser *browser)