perf tui: Remove annotate from popup menu after failure
[linux-2.6.git] / tools / perf / util / newt.c
index 010bacf..c65838c 100644 (file)
@@ -1,7 +1,15 @@
 #define _GNU_SOURCE
 #include <stdio.h>
 #undef _GNU_SOURCE
-
+/*
+ * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
+ * the build if it isn't defined. Use the equivalent one that glibc
+ * has on features.h.
+ */
+#include <features.h>
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
+#endif
 #include <slang.h>
 #include <stdlib.h>
 #include <newt.h>
 
 #include "cache.h"
 #include "hist.h"
+#include "pstack.h"
 #include "session.h"
 #include "sort.h"
 #include "symbol.h"
 
+#if SLANG_VERSION < 20104
+#define slsmg_printf(msg, args...) SLsmg_printf((char *)msg, ##args)
+#define slsmg_write_nstring(msg, len) SLsmg_write_nstring((char *)msg, len)
+#define sltt_set_color(obj, name, fg, bg) SLtt_set_color(obj,(char *)name,\
+                                                        (char *)fg, (char *)bg)
+#else
+#define slsmg_printf SLsmg_printf
+#define slsmg_write_nstring SLsmg_write_nstring
+#define sltt_set_color SLtt_set_color
+#endif
+
 struct ui_progress {
        newtComponent form, scale;
 };
@@ -117,6 +137,7 @@ int browser__show_help(const char *format, va_list ap)
 
 static void newt_form__set_exit_keys(newtComponent self)
 {
+       newtFormAddHotKey(self, NEWT_KEY_LEFT);
        newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
        newtFormAddHotKey(self, 'Q');
        newtFormAddHotKey(self, 'q');
@@ -165,6 +186,48 @@ out_destroy_form:
        return rc;
 }
 
+static int ui__help_window(const char *text)
+{
+       struct newtExitStruct es;
+       newtComponent tb, form = newt_form__new();
+       int rc = -1;
+       int max_len = 0, nr_lines = 0;
+       const char *t;
+
+       if (form == NULL)
+               return -1;
+
+       t = text;
+       while (1) {
+               const char *sep = strchr(t, '\n');
+               int len;
+
+               if (sep == NULL)
+                       sep = strchr(t, '\0');
+               len = sep - t;
+               if (max_len < len)
+                       max_len = len;
+               ++nr_lines;
+               if (*sep == '\0')
+                       break;
+               t = sep + 1;
+       }
+
+       tb = newtTextbox(0, 0, max_len, nr_lines, 0);
+       if (tb == NULL)
+               goto out_destroy_form;
+
+       newtTextboxSetText(tb, text);
+       newtFormAddComponent(form, tb);
+       newtCenteredWindow(max_len, nr_lines, NULL);
+       newtFormRun(form, &es);
+       newtPopWindow();
+       rc = 0;
+out_destroy_form:
+       newtFormDestroy(form);
+       return rc;
+}
+
 static bool dialog_yesno(const char *msg)
 {
        /* newtWinChoice should really be accepting const char pointers... */
@@ -248,21 +311,21 @@ static int objdump_line__show(struct objdump_line *self, struct list_head *head,
 
                color = ui_browser__percent_color(percent, current_entry);
                SLsmg_set_color(color);
-               SLsmg_printf(" %7.2f ", percent);
+               slsmg_printf(" %7.2f ", percent);
                if (!current_entry)
                        SLsmg_set_color(HE_COLORSET_CODE);
        } else {
                int color = ui_browser__percent_color(0, current_entry);
                SLsmg_set_color(color);
-               SLsmg_write_nstring(" ", 9);
+               slsmg_write_nstring(" ", 9);
        }
 
        SLsmg_write_char(':');
-       SLsmg_write_nstring(" ", 8);
+       slsmg_write_nstring(" ", 8);
        if (!*self->line)
-               SLsmg_write_nstring(" ", width - 18);
+               slsmg_write_nstring(" ", width - 18);
        else
-               SLsmg_write_nstring(self->line, width - 18);
+               slsmg_write_nstring(self->line, width - 18);
 
        return 0;
 }
@@ -320,6 +383,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
        newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
        newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
        newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
+       newtFormAddHotKey(self->form, ' ');
        newtFormAddHotKey(self->form, NEWT_KEY_HOME);
        newtFormAddHotKey(self->form, NEWT_KEY_END);
 
@@ -356,6 +420,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
                        }
                        break;
                case NEWT_KEY_PGDN:
+               case ' ':
                        if (self->first_visible_entry_idx + self->height > self->nr_entries - 1)
                                break;
 
@@ -407,6 +472,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
                }
                        break;
                case NEWT_KEY_ESCAPE:
+               case NEWT_KEY_LEFT:
                case CTRL('c'):
                case 'Q':
                case 'q':
@@ -615,7 +681,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self)
        if (hist_entry__annotate(self, &head) < 0)
                return;
 
-       ui_helpline__push("Press ESC to exit");
+       ui_helpline__push("Press <- or ESC to exit");
 
        memset(&browser, 0, sizeof(browser));
        browser.entries = &head;
@@ -680,16 +746,18 @@ static int hist_browser__populate(struct hist_browser *self, struct hists *hists
        struct ui_progress *progress;
        struct rb_node *nd;
        u64 curr_hist = 0;
-       char seq[] = ".";
+       char seq[] = ".", unit;
        char str[256];
+       unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
 
        if (self->form) {
                newtFormDestroy(self->form);
                newtPopWindow();
        }
 
-       snprintf(str, sizeof(str), "Samples: %Ld                            ",
-                hists->stats.total_period);
+       nr_events = convert_unit(nr_events, &unit);
+       snprintf(str, sizeof(str), "Events: %lu%c                            ",
+                nr_events, unit);
        newtDrawRootText(0, 0, str);
 
        newtGetScreenSize(NULL, &rows);
@@ -747,6 +815,14 @@ static int hist_browser__populate(struct hist_browser *self, struct hists *hists
 
        newtFormAddHotKey(self->form, 'A');
        newtFormAddHotKey(self->form, 'a');
+       newtFormAddHotKey(self->form, 'D');
+       newtFormAddHotKey(self->form, 'd');
+       newtFormAddHotKey(self->form, 'T');
+       newtFormAddHotKey(self->form, 't');
+       newtFormAddHotKey(self->form, '?');
+       newtFormAddHotKey(self->form, 'H');
+       newtFormAddHotKey(self->form, 'h');
+       newtFormAddHotKey(self->form, NEWT_KEY_F1);
        newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
        newtFormAddComponents(self->form, self->tree, NULL);
        self->selection = newt__symbol_tree_get_current(self->tree);
@@ -799,6 +875,7 @@ static int hist_browser__title(char *bf, size_t size, const char *input_name,
 int hists__browse(struct hists *self, const char *helpline, const char *input_name)
 {
        struct hist_browser *browser = hist_browser__new();
+       struct pstack *fstack = pstack__new(2);
        const struct thread *thread_filter = NULL;
        const struct dso *dso_filter = NULL;
        struct newtExitStruct es;
@@ -808,12 +885,16 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na
        if (browser == NULL)
                return -1;
 
+       fstack = pstack__new(2);
+       if (fstack == NULL)
+               goto out;
+
        ui_helpline__push(helpline);
 
        hist_browser__title(msg, sizeof(msg), input_name,
                            dso_filter, thread_filter);
        if (hist_browser__populate(browser, self, msg) < 0)
-               goto out;
+               goto out_free_stack;
 
        while (1) {
                const struct thread *thread;
@@ -823,25 +904,67 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na
                    annotate = -2, zoom_dso = -2, zoom_thread = -2;
 
                newtFormRun(browser->form, &es);
+
+               thread = hist_browser__selected_thread(browser);
+               dso = browser->selection->map ? browser->selection->map->dso : NULL;
+
                if (es.reason == NEWT_EXIT_HOTKEY) {
-                       if (toupper(es.u.key) == 'A')
+                       if (es.u.key == NEWT_KEY_F1)
+                               goto do_help;
+
+                       switch (toupper(es.u.key)) {
+                       case 'A':
+                               if (browser->selection->map == NULL &&
+                                   browser->selection->map->dso->annotate_warned)
+                                       continue;
                                goto do_annotate;
-                       if (es.u.key == NEWT_KEY_ESCAPE ||
-                           toupper(es.u.key) == 'Q' ||
-                           es.u.key == CTRL('c')) {
+                       case 'D':
+                               goto zoom_dso;
+                       case 'T':
+                               goto zoom_thread;
+                       case 'H':
+                       case '?':
+do_help:
+                               ui__help_window("->        Zoom into DSO/Threads & Annotate current symbol\n"
+                                               "<-        Zoom out\n"
+                                               "a         Annotate current symbol\n"
+                                               "h/?/F1    Show this window\n"
+                                               "d         Zoom into current DSO\n"
+                                               "t         Zoom into current Thread\n"
+                                               "q/CTRL+C  Exit browser");
+                               continue;
+                       default:;
+                       }
+                       if (toupper(es.u.key) == 'Q' ||
+                           es.u.key == CTRL('c'))
+                               break;
+                       if (es.u.key == NEWT_KEY_ESCAPE) {
                                if (dialog_yesno("Do you really want to exit?"))
                                        break;
                                else
                                        continue;
                        }
+
+                       if (es.u.key == NEWT_KEY_LEFT) {
+                               const void *top;
+
+                               if (pstack__empty(fstack))
+                                       continue;
+                               top = pstack__pop(fstack);
+                               if (top == &dso_filter)
+                                       goto zoom_out_dso;
+                               if (top == &thread_filter)
+                                       goto zoom_out_thread;
+                               continue;
+                       }
                }
 
                if (browser->selection->sym != NULL &&
+                   !browser->selection->map->dso->annotate_warned &&
                    asprintf(&options[nr_options], "Annotate %s",
                             browser->selection->sym->name) > 0)
                        annotate = nr_options++;
 
-               thread = hist_browser__selected_thread(browser);
                if (thread != NULL &&
                    asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
                             (thread_filter ? "out of" : "into"),
@@ -849,7 +972,6 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na
                             thread->pid) > 0)
                        zoom_thread = nr_options++;
 
-               dso = browser->selection->map ? browser->selection->map->dso : NULL;
                if (dso != NULL &&
                    asprintf(&options[nr_options], "Zoom %s %s DSO",
                             (dso_filter ? "out of" : "into"),
@@ -868,11 +990,12 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na
 
                if (choice == -1)
                        continue;
-do_annotate:
+
                if (choice == annotate) {
                        struct hist_entry *he;
-
+do_annotate:
                        if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
+                               browser->selection->map->dso->annotate_warned = 1;
                                ui_helpline__puts("No vmlinux file found, can't "
                                                 "annotate with just a "
                                                 "kallsyms file");
@@ -885,13 +1008,19 @@ do_annotate:
 
                        hist_entry__annotate_browser(he);
                } else if (choice == zoom_dso) {
+zoom_dso:
                        if (dso_filter) {
+                               pstack__remove(fstack, &dso_filter);
+zoom_out_dso:
                                ui_helpline__pop();
                                dso_filter = NULL;
                        } else {
-                               ui_helpline__fpush("To zoom out press -> + \"Zoom out of %s DSO\"",
+                               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);
                        }
                        hists__filter_by_dso(self, dso_filter);
                        hist_browser__title(msg, sizeof(msg), input_name,
@@ -899,14 +1028,18 @@ do_annotate:
                        if (hist_browser__populate(browser, self, msg) < 0)
                                goto out;
                } else if (choice == zoom_thread) {
+zoom_thread:
                        if (thread_filter) {
+                               pstack__remove(fstack, &thread_filter);
+zoom_out_thread:
                                ui_helpline__pop();
                                thread_filter = NULL;
                        } else {
-                               ui_helpline__fpush("To zoom out press -> + \"Zoom out of %s(%d) thread\"",
+                               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);
                        }
                        hists__filter_by_thread(self, thread_filter);
                        hist_browser__title(msg, sizeof(msg), input_name,
@@ -916,6 +1049,8 @@ do_annotate:
                }
        }
        err = 0;
+out_free_stack:
+       pstack__delete(fstack);
 out:
        hist_browser__delete(browser);
        return err;
@@ -938,23 +1073,26 @@ static struct newtPercentTreeColors {
 void setup_browser(void)
 {
        struct newtPercentTreeColors *c = &defaultPercentTreeColors;
-       if (!isatty(1))
+
+       if (!isatty(1) || !use_browser) {
+               setup_pager();
                return;
+       }
 
-       use_browser = true;
+       use_browser = 1;
        newtInit();
        newtCls();
        ui_helpline__puts(" ");
-       SLtt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
-       SLtt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
-       SLtt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg);
-       SLtt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg);
-       SLtt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
+       sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
+       sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
+       sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg);
+       sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg);
+       sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
 }
 
 void exit_browser(bool wait_for_ok)
 {
-       if (use_browser) {
+       if (use_browser > 0) {
                if (wait_for_ok) {
                        char title[] = "Fatal Error", ok[] = "Ok";
                        newtWinMessage(title, ok, browser__last_msg);