From 32ec6acfdcc066313261d0fbe6a966cb1804a7cd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 May 2010 00:23:14 -0300 Subject: perf tui: Fix build problem with slang <= 2.0.6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Reported-by: Steven Rostedt Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/newt.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/newt.c') diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index ccb7c5bb269e..9338d060ee49 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -1,7 +1,15 @@ #define _GNU_SOURCE #include #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 +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG +#endif #include #include #include -- cgit v1.2.3 From 17930b405e0ecdc8ecc4d336377a92950e2de76a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 May 2010 16:03:51 -0300 Subject: perf TUI: Make 'space' be an alias to 'PgDn' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like if one is using the stdio based pager, or more/less, for that matter. Suggested-by: Peter Zijlstra Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/newt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf/util/newt.c') diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 9338d060ee49..051022eb5f43 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -383,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); @@ -419,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; -- cgit v1.2.3 From 5d06e6915b1b76653e6fe3369b0b18fdbf75f0a5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 20 May 2010 22:01:10 -0300 Subject: perf tui: Allow disabling the TUI on a per command basis in ~/.perfconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the same scheme as for git's/perf's pager setup, i.e. if one doesn't want to, on a newt enabled perf binary, to disable the TUI for 'perf report', its just a matter of doing: [root@doppio linux-2.6-tip]# printf "[tui]\n\nreport = off\n" > /root/.perfconfig [root@doppio linux-2.6-tip]# cat /root/.perfconfig [tui] report = off [root@doppio linux-2.6-tip]# System wide settings are also possible, by editing /etc/perfconfig, etc, i.e. the git machinery for config files applies to perf as well, so when in doubt where to put your settings, consult the git documentation, if it fails, please let us know. Suggested-by: Ingo Molnar Discussed-with: Stephane Eranian Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 8 ++++---- tools/perf/perf.c | 25 +++++++++++++++++++++++-- tools/perf/util/cache.h | 2 +- tools/perf/util/newt.c | 9 ++++++--- 4 files changed, 34 insertions(+), 10 deletions(-) (limited to 'tools/perf/util/newt.c') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1d3c1003b43a..a7b8760e401c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -116,7 +116,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, * so we don't allocated the extra space needed because the stdio * code will not use it. */ - if (use_browser) + if (use_browser > 0) err = hist_entry__inc_addr_samples(he, al->addr); out_free_syms: free(syms); @@ -330,7 +330,7 @@ static int __cmd_report(void) hists = rb_entry(next, struct hists, rb_node); hists__collapse_resort(hists); hists__output_resort(hists); - if (use_browser) + if (use_browser > 0) hists__browse(hists, help, input_name); else { const char *evname = NULL; @@ -347,7 +347,7 @@ static int __cmd_report(void) next = rb_next(&hists->rb_node); } - if (!use_browser && sort_order == default_sort_order && + if (use_browser <= 0 && sort_order == default_sort_order && parent_pattern == default_parent_pattern) { fprintf(stdout, "#\n# (%s)\n#\n", help); @@ -491,7 +491,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) * so don't allocate extra space that won't be used in the stdio * implementation. */ - if (use_browser) + if (use_browser > 0) symbol_conf.priv_size = sizeof(struct sym_priv); if (symbol__init() < 0) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 08e0e5d2b50e..6e4871191138 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -15,15 +15,15 @@ #include "util/parse-events.h" #include "util/debugfs.h" -bool use_browser; - const char perf_usage_string[] = "perf [--version] [--help] COMMAND [ARGS]"; const char perf_more_info_string[] = "See 'perf help COMMAND' for more information on a specific command."; +int use_browser = -1; static int use_pager = -1; + struct pager_config { const char *cmd; int val; @@ -49,6 +49,24 @@ int check_pager_config(const char *cmd) return c.val; } +static int tui_command_config(const char *var, const char *value, void *data) +{ + struct pager_config *c = data; + if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd)) + c->val = perf_config_bool(var, value); + return 0; +} + +/* returns 0 for "no tui", 1 for "use tui", and -1 for "not specified" */ +static int check_tui_config(const char *cmd) +{ + struct pager_config c; + c.cmd = cmd; + c.val = -1; + perf_config(tui_command_config, &c); + return c.val; +} + static void commit_pager_choice(void) { switch (use_pager) { @@ -255,6 +273,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) if (p->option & RUN_SETUP) prefix = NULL; /* setup_perf_directory(); */ + if (use_browser == -1) + use_browser = check_tui_config(p->cmd); + if (use_pager == -1 && p->option & RUN_SETUP) use_pager = check_pager_config(p->cmd); if (use_pager == -1 && p->option & USE_PAGER) diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 5eca52595b62..65fe664fddf6 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -30,7 +30,7 @@ extern const char *pager_program; extern int pager_in_use(void); extern int pager_use_color; -extern bool use_browser; +extern int use_browser; #ifdef NO_NEWT_SUPPORT static inline void setup_browser(void) diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 9338d060ee49..9d203c972f3b 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -1066,10 +1066,13 @@ 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(" "); @@ -1082,7 +1085,7 @@ void setup_browser(void) 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); -- cgit v1.2.3 From 6e78c9fd1bc2c7e04b3d7052e9eb27aa536e4e2c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 22 May 2010 11:20:24 -0300 Subject: perf tui: Remove annotate from popup menu after failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/newt.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools/perf/util/newt.c') diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 0b45658f7497..c65838c99354 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -914,6 +914,9 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na switch (toupper(es.u.key)) { case 'A': + if (browser->selection->map == NULL && + browser->selection->map->dso->annotate_warned) + continue; goto do_annotate; case 'D': goto zoom_dso; @@ -957,6 +960,7 @@ do_help: } 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++; @@ -991,6 +995,7 @@ do_help: 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"); -- cgit v1.2.3 From 46e3e055ce69a00d735e458445ab1d24718ff751 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 22 May 2010 11:25:40 -0300 Subject: perf annotate: Add TUI interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When annotating multiple entries, for instance, when running simply as: $ perf annotate the right and left keys, as well as TAB can be used to cycle thru the multiple symbols being annotated. If one doesn't like TUI annotate, disable it by editing ~/.perfconfig and adding: [tui] annotate = off Just like it is possible for report. Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 61 +++++++++++++++++++++++++++++++------------ tools/perf/builtin-report.c | 4 +-- tools/perf/util/hist.c | 13 ++++----- tools/perf/util/hist.h | 10 +++++++ tools/perf/util/newt.c | 56 +++++++++++++++++++++++++-------------- tools/perf/util/util.h | 15 ++++++++++- 6 files changed, 112 insertions(+), 47 deletions(-) (limited to 'tools/perf/util/newt.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 77bcc9b130f5..08278eda31a5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -277,7 +277,7 @@ static void hist_entry__print_hits(struct hist_entry *self) printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum); } -static void annotate_sym(struct hist_entry *he) +static int hist_entry__tty_annotate(struct hist_entry *he) { struct map *map = he->ms.map; struct dso *dso = map->dso; @@ -288,7 +288,7 @@ static void annotate_sym(struct hist_entry *he) struct objdump_line *pos, *n; if (hist_entry__annotate(he, &head) < 0) - return; + return -1; if (full_paths) d_filename = filename; @@ -317,30 +317,59 @@ static void annotate_sym(struct hist_entry *he) if (print_line) free_source_line(he, len); + + return 0; } static void hists__find_annotations(struct hists *self) { - struct rb_node *nd; + struct rb_node *first = rb_first(&self->entries), *nd = first; + int key = KEY_RIGHT; - for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { + while (nd) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); struct sym_priv *priv; - if (he->ms.sym == NULL) - continue; + if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) + goto find_next; priv = symbol__priv(he->ms.sym); - if (priv->hist == NULL) + if (priv->hist == NULL) { +find_next: + if (key == KEY_LEFT) + nd = rb_prev(nd); + else + nd = rb_next(nd); continue; + } - annotate_sym(he); - /* - * Since we have a hist_entry per IP for the same symbol, free - * he->ms.sym->hist to signal we already processed this symbol. - */ - free(priv->hist); - priv->hist = NULL; + if (use_browser) { + key = hist_entry__tui_annotate(he); + if (is_exit_key(key)) + break; + switch (key) { + case KEY_RIGHT: + case '\t': + nd = rb_next(nd); + break; + case KEY_LEFT: + if (nd == first) + continue; + nd = rb_prev(nd); + default: + break; + } + } else { + hist_entry__tty_annotate(he); + nd = rb_next(nd); + /* + * Since we have a hist_entry per IP for the same + * symbol, free he->ms.sym->hist to signal we already + * processed this symbol. + */ + free(priv->hist); + priv->hist = NULL; + } } } @@ -416,6 +445,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) { argc = parse_options(argc, argv, options, annotate_usage, 0); + setup_browser(); + symbol_conf.priv_size = sizeof(struct sym_priv); symbol_conf.try_vmlinux_path = true; @@ -435,8 +466,6 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) sym_hist_filter = argv[0]; } - setup_pager(); - if (field_sep && *field_sep == '.') { pr_err("'.' is the only non valid --field-separator argument\n"); return -1; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2c39bd358975..a7b8760e401c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -484,9 +484,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) { argc = parse_options(argc, argv, options, report_usage, 0); - if (dump_trace) - setup_pager(); - else if (strcmp(input_name, "-") != 0) + if (strcmp(input_name, "-") != 0) setup_browser(); /* * Only in the newt browser we are doing integrated annotation, diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 009ad76b0879..682a6d88862c 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -992,14 +992,14 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) char *filename = dso__build_id_filename(dso, NULL, 0); char command[PATH_MAX * 2]; FILE *file; - int err = -1; + int err = 0; u64 len; if (filename == NULL) { if (dso->has_build_id) { pr_err("Can't annotate %s: not enough memory\n", sym->name); - return -1; + return -ENOMEM; } /* * If we don't have build-ids, well, lets hope that this @@ -1009,14 +1009,12 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) } if (dso->origin == DSO__ORIG_KERNEL) { - if (dso->annotate_warned) { - err = 0; + if (dso->annotate_warned) goto out_free_filename; - } + err = -ENOENT; dso->annotate_warned = 1; pr_err("Can't annotate %s: No vmlinux file was found in the " - "path:\n", sym->name); - vmlinux_path__fprintf(stderr); + "path\n", sym->name); goto out_free_filename; } @@ -1046,7 +1044,6 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) break; pclose(file); - err = 0; out_free_filename: if (dso->has_build_id) free(filename); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 6f17dcd8412c..2d5203fedb20 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -102,8 +102,18 @@ static inline int hists__browse(struct hists *self __used, { return 0; } +static inline int hist_entry__tui_annotate(struct hist_entry *self __used) +{ + return 0; +} +#define KEY_LEFT -1 +#define KEY_RIGHT -2 #else +#include int hists__browse(struct hists *self, const char *helpline, const char *input_name); +int hist_entry__tui_annotate(struct hist_entry *self); +#define KEY_LEFT NEWT_KEY_LEFT +#define KEY_RIGHT NEWT_KEY_RIGHT #endif #endif /* __PERF_HIST_H */ diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index c65838c99354..ffd04720b754 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -235,6 +235,15 @@ static bool dialog_yesno(const char *msg) return newtWinChoice(NULL, yes, no, (char *)msg) == 1; } +static void ui__error_window(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap); + va_end(ap); +} + #define HE_COLORSET_TOP 50 #define HE_COLORSET_MEDIUM 51 #define HE_COLORSET_NORMAL 52 @@ -386,6 +395,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title, newtFormAddHotKey(self->form, ' '); newtFormAddHotKey(self->form, NEWT_KEY_HOME); newtFormAddHotKey(self->form, NEWT_KEY_END); + newtFormAddHotKey(self->form, NEWT_KEY_TAB); + newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); if (ui_browser__refresh_entries(self) < 0) return -1; @@ -398,6 +409,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title, if (es->reason != NEWT_EXIT_HOTKEY) break; + if (is_exit_key(es->u.key)) + return es->u.key; switch (es->u.key) { case NEWT_KEY_DOWN: if (self->index == self->nr_entries - 1) @@ -471,12 +484,10 @@ static int ui_browser__run(struct ui_browser *self, const char *title, } } break; - case NEWT_KEY_ESCAPE: + case NEWT_KEY_RIGHT: case NEWT_KEY_LEFT: - case CTRL('c'): - case 'Q': - case 'q': - return 0; + case NEWT_KEY_TAB: + return es->u.key; default: continue; } @@ -668,18 +679,24 @@ static size_t hist_entry__append_browser(struct hist_entry *self, return ret; } -static void hist_entry__annotate_browser(struct hist_entry *self) +int hist_entry__tui_annotate(struct hist_entry *self) { struct ui_browser browser; struct newtExitStruct es; struct objdump_line *pos, *n; LIST_HEAD(head); + int ret; if (self->ms.sym == NULL) - return; + return -1; - if (hist_entry__annotate(self, &head) < 0) - return; + if (self->ms.map->dso->annotate_warned) + return -1; + + if (hist_entry__annotate(self, &head) < 0) { + ui__error_window(browser__last_msg); + return -1; + } ui_helpline__push("Press <- or ESC to exit"); @@ -694,7 +711,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self) } browser.width += 18; /* Percentage */ - ui_browser__run(&browser, self->ms.sym->name, &es); + ret = ui_browser__run(&browser, self->ms.sym->name, &es); newtFormDestroy(browser.form); newtPopWindow(); list_for_each_entry_safe(pos, n, &head, node) { @@ -702,6 +719,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self) objdump_line__free(pos); } ui_helpline__pop(); + return ret; } static const void *newt__symbol_tree_get_current(newtComponent self) @@ -935,14 +953,14 @@ do_help: 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?")) + if (is_exit_key(es.u.key)) { + if (es.u.key == NEWT_KEY_ESCAPE) { + if (dialog_yesno("Do you really want to exit?")) + break; + else + continue; + } else break; - else - continue; } if (es.u.key == NEWT_KEY_LEFT) { @@ -1006,7 +1024,7 @@ do_annotate: if (he == NULL) continue; - hist_entry__annotate_browser(he); + hist_entry__tui_annotate(he); } else if (choice == zoom_dso) { zoom_dso: if (dso_filter) { @@ -1074,7 +1092,7 @@ void setup_browser(void) { struct newtPercentTreeColors *c = &defaultPercentTreeColors; - if (!isatty(1) || !use_browser) { + if (!isatty(1) || !use_browser || dump_trace) { setup_pager(); return; } diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 45b9655f3a5c..4e8b6b0c551c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -81,7 +81,7 @@ #include #include "../../../include/linux/magic.h" #include "types.h" - +#include #ifndef NO_ICONV #include @@ -263,6 +263,19 @@ bool strglobmatch(const char *str, const char *pat); bool strlazymatch(const char *str, const char *pat); unsigned long convert_unit(unsigned long value, char *unit); +#ifndef ESC +#define ESC 27 +#endif + +static inline bool is_exit_key(int key) +{ + char up; + if (key == CTRL('c') || key == ESC) + return true; + up = toupper(key); + return up == 'Q'; +} + #define _STR(x) #x #define STR(x) _STR(x) -- cgit v1.2.3 From d67f088e084755bdceb4f15bc6e05e309db1eea7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 23 May 2010 22:36:51 -0300 Subject: perf report: Support multiple events on the TUI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hists__tty_browse_tree function was created with the loop to print all events, and its equivalent, hists__tui_browse_tree, was created in a similar fashion, where it is possible to switch among the multiple events, if present, using TAB to go the next event, and shift+TAB (UNTAB) to go to the previous. The report TUI now shows as the window title the name of the event and a leak was fixed wrt pstacks. Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 60 +++++++++++++++++++++--------------- tools/perf/util/hist.h | 14 +++++++-- tools/perf/util/newt.c | 74 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 108 insertions(+), 40 deletions(-) (limited to 'tools/perf/util/newt.c') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index a7b8760e401c..359205782964 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -288,6 +288,38 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, return ret + fprintf(fp, "\n#\n"); } +static int hists__tty_browse_tree(struct rb_root *tree, const char *help) +{ + struct rb_node *next = rb_first(tree); + + while (next) { + struct hists *hists = rb_entry(next, struct hists, rb_node); + const char *evname = NULL; + + if (rb_first(&hists->entries) != rb_last(&hists->entries)) + evname = __event_name(hists->type, hists->config); + + hists__fprintf_nr_sample_events(hists, evname, stdout); + hists__fprintf(hists, NULL, false, stdout); + fprintf(stdout, "\n\n"); + next = rb_next(&hists->rb_node); + } + + if (sort_order == default_sort_order && + parent_pattern == default_parent_pattern) { + fprintf(stdout, "#\n# (%s)\n#\n", help); + + if (show_threads) { + bool style = !strcmp(pretty_printing_style, "raw"); + perf_read_values_display(stdout, &show_threads_values, + style); + perf_read_values_destroy(&show_threads_values); + } + } + + return 0; +} + static int __cmd_report(void) { int ret = -EINVAL; @@ -330,34 +362,14 @@ static int __cmd_report(void) hists = rb_entry(next, struct hists, rb_node); hists__collapse_resort(hists); hists__output_resort(hists); - if (use_browser > 0) - hists__browse(hists, help, input_name); - else { - const char *evname = NULL; - if (rb_first(&session->hists.entries) != - rb_last(&session->hists.entries)) - evname = __event_name(hists->type, hists->config); - - hists__fprintf_nr_sample_events(hists, evname, stdout); - - hists__fprintf(hists, NULL, false, stdout); - fprintf(stdout, "\n\n"); - } - next = rb_next(&hists->rb_node); } - if (use_browser <= 0 && sort_order == default_sort_order && - parent_pattern == default_parent_pattern) { - fprintf(stdout, "#\n# (%s)\n#\n", help); + if (use_browser > 0) + hists__tui_browse_tree(&session->hists_tree, help); + else + hists__tty_browse_tree(&session->hists_tree, help); - if (show_threads) { - bool style = !strcmp(pretty_printing_style, "raw"); - perf_read_values_display(stdout, &show_threads_values, - style); - perf_read_values_destroy(&show_threads_values); - } - } out_delete: perf_session__delete(session); return ret; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 2d5203fedb20..83fa33a7b38b 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -98,10 +98,17 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread); #ifdef NO_NEWT_SUPPORT static inline int hists__browse(struct hists *self __used, const char *helpline __used, - const char *input_name __used) + const char *ev_name __used) { return 0; } + +static inline int hists__tui_browse_tree(struct rb_root *self __used, + const char *help __used) +{ + return 0; +} + static inline int hist_entry__tui_annotate(struct hist_entry *self __used) { return 0; @@ -111,9 +118,12 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used) #else #include int hists__browse(struct hists *self, const char *helpline, - const char *input_name); + const char *ev_name); int hist_entry__tui_annotate(struct hist_entry *self); + #define KEY_LEFT NEWT_KEY_LEFT #define KEY_RIGHT NEWT_KEY_RIGHT + +int hists__tui_browse_tree(struct rb_root *self, const char *help); #endif #endif /* __PERF_HIST_H */ diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index ffd04720b754..d54c540f49db 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -842,6 +842,8 @@ static int hist_browser__populate(struct hist_browser *self, struct hists *hists newtFormAddHotKey(self->form, 'h'); newtFormAddHotKey(self->form, NEWT_KEY_F1); newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); + newtFormAddHotKey(self->form, NEWT_KEY_TAB); + newtFormAddHotKey(self->form, NEWT_KEY_UNTAB); newtFormAddComponents(self->form, self->tree, NULL); self->selection = newt__symbol_tree_get_current(self->tree); @@ -873,7 +875,7 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self) return he ? he->thread : NULL; } -static int hist_browser__title(char *bf, size_t size, const char *input_name, +static int hist_browser__title(char *bf, size_t size, const char *ev_name, const struct dso *dso, const struct thread *thread) { int printed = 0; @@ -887,18 +889,18 @@ static int hist_browser__title(char *bf, size_t size, const char *input_name, printed += snprintf(bf + printed, size - printed, "%sDSO: %s", thread ? " " : "", dso->short_name); - return printed ?: snprintf(bf, size, "Report: %s", input_name); + return printed ?: snprintf(bf, size, "Event: %s", ev_name); } -int hists__browse(struct hists *self, const char *helpline, const char *input_name) +int hists__browse(struct hists *self, const char *helpline, const char *ev_name) { struct hist_browser *browser = hist_browser__new(); - struct pstack *fstack = pstack__new(2); + struct pstack *fstack; const struct thread *thread_filter = NULL; const struct dso *dso_filter = NULL; struct newtExitStruct es; char msg[160]; - int err = -1; + int key = -1; if (browser == NULL) return -1; @@ -909,7 +911,7 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na ui_helpline__push(helpline); - hist_browser__title(msg, sizeof(msg), input_name, + hist_browser__title(msg, sizeof(msg), ev_name, dso_filter, thread_filter); if (hist_browser__populate(browser, self, msg) < 0) goto out_free_stack; @@ -927,10 +929,23 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na dso = browser->selection->map ? browser->selection->map->dso : NULL; if (es.reason == NEWT_EXIT_HOTKEY) { - if (es.u.key == NEWT_KEY_F1) + key = es.u.key; + + switch (key) { + case NEWT_KEY_F1: goto do_help; + case NEWT_KEY_TAB: + case NEWT_KEY_UNTAB: + /* + * Exit the browser, let hists__browser_tree + * go to the next or previous + */ + goto out_free_stack; + default:; + } - switch (toupper(es.u.key)) { + key = toupper(key); + switch (key) { case 'A': if (browser->selection->map == NULL && browser->selection->map->dso->annotate_warned) @@ -953,8 +968,8 @@ do_help: continue; default:; } - if (is_exit_key(es.u.key)) { - if (es.u.key == NEWT_KEY_ESCAPE) { + if (is_exit_key(key)) { + if (key == NEWT_KEY_ESCAPE) { if (dialog_yesno("Do you really want to exit?")) break; else @@ -1041,7 +1056,7 @@ zoom_out_dso: pstack__push(fstack, &dso_filter); } hists__filter_by_dso(self, dso_filter); - hist_browser__title(msg, sizeof(msg), input_name, + hist_browser__title(msg, sizeof(msg), ev_name, dso_filter, thread_filter); if (hist_browser__populate(browser, self, msg) < 0) goto out; @@ -1060,18 +1075,49 @@ zoom_out_thread: pstack__push(fstack, &thread_filter); } hists__filter_by_thread(self, thread_filter); - hist_browser__title(msg, sizeof(msg), input_name, + hist_browser__title(msg, sizeof(msg), ev_name, dso_filter, thread_filter); if (hist_browser__populate(browser, self, msg) < 0) goto out; } } - err = 0; out_free_stack: pstack__delete(fstack); out: hist_browser__delete(browser); - return err; + return key; +} + +int hists__tui_browse_tree(struct rb_root *self, const char *help) +{ + struct rb_node *first = rb_first(self), *nd = first, *next; + int key = 0; + + while (nd) { + struct hists *hists = rb_entry(nd, struct hists, rb_node); + const char *ev_name = __event_name(hists->type, hists->config); + + key = hists__browse(hists, help, ev_name); + + if (is_exit_key(key)) + break; + + switch (key) { + case NEWT_KEY_TAB: + next = rb_next(nd); + if (next) + nd = next; + break; + case NEWT_KEY_UNTAB: + if (nd == first) + continue; + nd = rb_prev(nd); + default: + break; + } + } + + return key; } static struct newtPercentTreeColors { -- cgit v1.2.3