From 211ef12771e759a08e10c3c606e6a8b1663519e7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 10 Aug 2010 14:54:09 -0300 Subject: perf ui: Move annotate browser to util/ui/browsers/ LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 114 +++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tools/perf/util/ui/browsers/annotate.c (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c new file mode 100644 index 00000000000..783d277f219 --- /dev/null +++ b/tools/perf/util/ui/browsers/annotate.c @@ -0,0 +1,114 @@ +#include "../browser.h" +#include "../helpline.h" +#include "../libslang.h" +#include "../../hist.h" +#include "../../sort.h" +#include "../../symbol.h" + +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); +} + +static void annotate_browser__write(struct ui_browser *self, void *entry, int row) +{ + struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); + bool current_entry = ui_browser__is_current_entry(self, row); + int width = self->width; + + if (ol->offset != -1) { + struct hist_entry *he = self->priv; + struct symbol *sym = he->ms.sym; + int len = he->ms.sym->end - he->ms.sym->start; + unsigned int hits = 0; + double percent = 0.0; + int color; + struct sym_priv *priv = symbol__priv(sym); + struct sym_ext *sym_ext = priv->ext; + struct sym_hist *h = priv->hist; + s64 offset = ol->offset; + struct objdump_line *next = objdump__get_next_ip_line(self->entries, ol); + + while (offset < (s64)len && + (next == NULL || offset < next->offset)) { + if (sym_ext) { + percent += sym_ext[offset].percent; + } else + hits += h->ip[offset]; + + ++offset; + } + + if (sym_ext == NULL && h->sum) + percent = 100.0 * hits / h->sum; + + color = ui_browser__percent_color(percent, current_entry); + SLsmg_set_color(color); + 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_char(':'); + slsmg_write_nstring(" ", 8); + if (!*ol->line) + slsmg_write_nstring(" ", width - 18); + else + slsmg_write_nstring(ol->line, width - 18); +} + +int hist_entry__tui_annotate(struct hist_entry *self) +{ + struct newtExitStruct es; + struct objdump_line *pos, *n; + LIST_HEAD(head); + struct ui_browser browser = { + .entries = &head, + .refresh = ui_browser__list_head_refresh, + .seek = ui_browser__list_head_seek, + .write = annotate_browser__write, + .priv = self, + }; + int ret; + + if (self->ms.sym == NULL) + return -1; + + 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"); + + list_for_each_entry(pos, &head, node) { + size_t line_len = strlen(pos->line); + if (browser.width < line_len) + browser.width = line_len; + ++browser.nr_entries; + } + + browser.width += 18; /* Percentage */ + ui_browser__show(&browser, self->ms.sym->name); + newtFormAddHotKey(browser.form, ' '); + ret = ui_browser__run(&browser, &es); + newtFormDestroy(browser.form); + newtPopWindow(); + list_for_each_entry_safe(pos, n, &head, node) { + list_del(&pos->node); + objdump_line__free(pos); + } + ui_helpline__pop(); + return ret; +} -- cgit v1.2.3-18-g5258 From 1e6dd077a880ba5570beb690523b7a78a91a7615 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 10 Aug 2010 15:58:50 -0300 Subject: perf ui: Complete the breakdown of util/newt.c LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 783d277f219..5b01df633f9 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -86,7 +86,7 @@ int hist_entry__tui_annotate(struct hist_entry *self) return -1; if (hist_entry__annotate(self, &head) < 0) { - ui__error_window(browser__last_msg); + ui__error_window(ui_helpline__last_msg); return -1; } -- cgit v1.2.3-18-g5258 From 92221162875ec48913d3f9710046e48d599c9cf2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 9 Aug 2010 15:30:40 -0300 Subject: perf annotate: Sort by hottest lines in the TUI Right now it will just sort and position at the hottest line, i.e. the one where more samples were taken. It will be at the center of the screen and later TAB/shift-TAB will cycle thru the hottest lines. Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 153 +++++++++++++++++++++++++-------- 1 file changed, 115 insertions(+), 38 deletions(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 5b01df633f9..763592b09d7 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -14,6 +14,23 @@ static void ui__error_window(const char *fmt, ...) va_end(ap); } +struct annotate_browser { + struct ui_browser b; + struct rb_root entries; +}; + +struct objdump_line_rb_node { + struct rb_node rb_node; + double percent; + u32 idx; +}; + +static inline +struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) +{ + return (struct objdump_line_rb_node *)(self + 1); +} + static void annotate_browser__write(struct ui_browser *self, void *entry, int row) { struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); @@ -21,17 +38,41 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro int width = self->width; if (ol->offset != -1) { - struct hist_entry *he = self->priv; - struct symbol *sym = he->ms.sym; - int len = he->ms.sym->end - he->ms.sym->start; + struct objdump_line_rb_node *olrb = objdump_line__rb(ol); + int color = ui_browser__percent_color(olrb->percent, current_entry); + SLsmg_set_color(color); + slsmg_printf(" %7.2f ", olrb->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_char(':'); + slsmg_write_nstring(" ", 8); + if (!*ol->line) + slsmg_write_nstring(" ", width - 18); + else + slsmg_write_nstring(ol->line, width - 18); +} + +static double objdump_line__calc_percent(struct objdump_line *self, + struct list_head *head, + struct symbol *sym) +{ + double percent = 0.0; + + if (self->offset != -1) { + int len = sym->end - sym->start; unsigned int hits = 0; - double percent = 0.0; - int color; struct sym_priv *priv = symbol__priv(sym); struct sym_ext *sym_ext = priv->ext; struct sym_hist *h = priv->hist; - s64 offset = ol->offset; - struct objdump_line *next = objdump__get_next_ip_line(self->entries, ol); + s64 offset = self->offset; + struct objdump_line *next = objdump__get_next_ip_line(head, self); + while (offset < (s64)len && (next == NULL || offset < next->offset)) { @@ -45,37 +86,45 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (sym_ext == NULL && h->sum) percent = 100.0 * hits / h->sum; - - color = ui_browser__percent_color(percent, current_entry); - SLsmg_set_color(color); - 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_char(':'); - slsmg_write_nstring(" ", 8); - if (!*ol->line) - slsmg_write_nstring(" ", width - 18); - else - slsmg_write_nstring(ol->line, width - 18); + return percent; +} + +static void objdump__insert_line(struct rb_root *self, + struct objdump_line_rb_node *line) +{ + struct rb_node **p = &self->rb_node; + struct rb_node *parent = NULL; + struct objdump_line_rb_node *l; + + while (*p != NULL) { + parent = *p; + l = rb_entry(parent, struct objdump_line_rb_node, rb_node); + if (line->percent < l->percent) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + rb_link_node(&line->rb_node, parent, p); + rb_insert_color(&line->rb_node, self); } int hist_entry__tui_annotate(struct hist_entry *self) { struct newtExitStruct es; struct objdump_line *pos, *n; + struct objdump_line_rb_node *rbpos; + struct rb_node *nd; LIST_HEAD(head); - struct ui_browser browser = { - .entries = &head, - .refresh = ui_browser__list_head_refresh, - .seek = ui_browser__list_head_seek, - .write = annotate_browser__write, - .priv = self, + struct annotate_browser browser = { + .b = { + .entries = &head, + .refresh = ui_browser__list_head_refresh, + .seek = ui_browser__list_head_seek, + .write = annotate_browser__write, + .priv = self, + }, }; int ret; @@ -85,7 +134,7 @@ int hist_entry__tui_annotate(struct hist_entry *self) if (self->ms.map->dso->annotate_warned) return -1; - if (hist_entry__annotate(self, &head) < 0) { + if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { ui__error_window(ui_helpline__last_msg); return -1; } @@ -94,16 +143,44 @@ int hist_entry__tui_annotate(struct hist_entry *self) list_for_each_entry(pos, &head, node) { size_t line_len = strlen(pos->line); - if (browser.width < line_len) - browser.width = line_len; - ++browser.nr_entries; + if (browser.b.width < line_len) + browser.b.width = line_len; + rbpos = objdump_line__rb(pos); + rbpos->idx = browser.b.nr_entries++; + rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym); + if (rbpos->percent < 0.01) + continue; + objdump__insert_line(&browser.entries, rbpos); + } + + /* + * Position the browser at the hottest line. + */ + nd = rb_last(&browser.entries); + if (nd != NULL) { + unsigned back; + + ui_browser__refresh_dimensions(&browser.b); + back = browser.b.height / 2; + rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node); + pos = ((struct objdump_line *)rbpos) - 1; + browser.b.top_idx = browser.b.index = rbpos->idx; + + while (browser.b.top_idx != 0 && back != 0) { + pos = list_entry(pos->node.prev, struct objdump_line, node); + + --browser.b.top_idx; + --back; + } + + browser.b.top = pos; } - browser.width += 18; /* Percentage */ - ui_browser__show(&browser, self->ms.sym->name); - newtFormAddHotKey(browser.form, ' '); - ret = ui_browser__run(&browser, &es); - newtFormDestroy(browser.form); + browser.b.width += 18; /* Percentage */ + ui_browser__show(&browser.b, self->ms.sym->name); + newtFormAddHotKey(browser.b.form, ' '); + ret = ui_browser__run(&browser.b, &es); + newtFormDestroy(browser.b.form); newtPopWindow(); list_for_each_entry_safe(pos, n, &head, node) { list_del(&pos->node); -- cgit v1.2.3-18-g5258 From 9e22d6377ce6f31b1cc0bff16daeda2780495061 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 10 Aug 2010 15:09:02 -0300 Subject: perf ui: Make SPACE work as PGDN in all browsers Not just on the annotate one. Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 763592b09d7..d2156aebd4f 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -178,7 +178,6 @@ int hist_entry__tui_annotate(struct hist_entry *self) browser.b.width += 18; /* Percentage */ ui_browser__show(&browser.b, self->ms.sym->name); - newtFormAddHotKey(browser.b.form, ' '); ret = ui_browser__run(&browser.b, &es); newtFormDestroy(browser.b.form); newtPopWindow(); -- cgit v1.2.3-18-g5258 From f1e9214cc99644101d957c5c660946c6f2f86d7c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 10 Aug 2010 15:14:53 -0300 Subject: perf annotate: Cycle thru sorted lines with samples The annotate TUI now starts centered on the line with most samples, i.e. the hottest line in the annotated function. Pressing TAB will center on the second hottest function and so on. Shift+TAB goes in the other direction. This way one can more easily sift thru the function hotspots. Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 102 +++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 25 deletions(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index d2156aebd4f..73e78ef38a5 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -17,6 +17,7 @@ static void ui__error_window(const char *fmt, ...) struct annotate_browser { struct ui_browser b; struct rb_root entries; + struct rb_node *curr_hot; }; struct objdump_line_rb_node { @@ -110,12 +111,83 @@ static void objdump__insert_line(struct rb_root *self, rb_insert_color(&line->rb_node, self); } +static void annotate_browser__set_top(struct annotate_browser *self, + struct rb_node *nd) +{ + struct objdump_line_rb_node *rbpos; + struct objdump_line *pos; + unsigned back; + + ui_browser__refresh_dimensions(&self->b); + back = self->b.height / 2; + rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node); + pos = ((struct objdump_line *)rbpos) - 1; + self->b.top_idx = self->b.index = rbpos->idx; + + while (self->b.top_idx != 0 && back != 0) { + pos = list_entry(pos->node.prev, struct objdump_line, node); + + --self->b.top_idx; + --back; + } + + self->b.top = pos; + self->curr_hot = nd; +} + +static int annotate_browser__run(struct annotate_browser *self, + struct newtExitStruct *es) +{ + struct rb_node *nd; + struct hist_entry *he = self->b.priv; + + if (ui_browser__show(&self->b, he->ms.sym->name) < 0) + return -1; + + ui_helpline__fpush("<- or ESC: exit, TAB/shift+TAB: cycle thru samples"); + newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT); + + nd = self->curr_hot; + if (nd) { + newtFormAddHotKey(self->b.form, NEWT_KEY_TAB); + newtFormAddHotKey(self->b.form, NEWT_KEY_UNTAB); + } + + while (1) { + ui_browser__run(&self->b, es); + + if (es->reason != NEWT_EXIT_HOTKEY) + break; + + switch (es->u.key) { + case NEWT_KEY_TAB: + nd = rb_prev(nd); + if (nd == NULL) + nd = rb_last(&self->entries); + annotate_browser__set_top(self, nd); + break; + case NEWT_KEY_UNTAB: + nd = rb_next(nd); + if (nd == NULL) + nd = rb_first(&self->entries); + annotate_browser__set_top(self, nd); + break; + default: + goto out; + } + } +out: + newtFormDestroy(self->b.form); + newtPopWindow(); + ui_helpline__pop(); + return 0; +} + int hist_entry__tui_annotate(struct hist_entry *self) { struct newtExitStruct es; struct objdump_line *pos, *n; struct objdump_line_rb_node *rbpos; - struct rb_node *nd; LIST_HEAD(head); struct annotate_browser browser = { .b = { @@ -156,35 +228,15 @@ int hist_entry__tui_annotate(struct hist_entry *self) /* * Position the browser at the hottest line. */ - nd = rb_last(&browser.entries); - if (nd != NULL) { - unsigned back; - - ui_browser__refresh_dimensions(&browser.b); - back = browser.b.height / 2; - rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node); - pos = ((struct objdump_line *)rbpos) - 1; - browser.b.top_idx = browser.b.index = rbpos->idx; - - while (browser.b.top_idx != 0 && back != 0) { - pos = list_entry(pos->node.prev, struct objdump_line, node); - - --browser.b.top_idx; - --back; - } - - browser.b.top = pos; - } + browser.curr_hot = rb_last(&browser.entries); + if (browser.curr_hot) + annotate_browser__set_top(&browser, browser.curr_hot); browser.b.width += 18; /* Percentage */ - ui_browser__show(&browser.b, self->ms.sym->name); - ret = ui_browser__run(&browser.b, &es); - newtFormDestroy(browser.b.form); - newtPopWindow(); + ret = annotate_browser__run(&browser, &es); list_for_each_entry_safe(pos, n, &head, node) { list_del(&pos->node); objdump_line__free(pos); } - ui_helpline__pop(); return ret; } -- cgit v1.2.3-18-g5258 From 59e8fe32fc0cc9dff6b0c269d099a49e004dc45e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 10 Aug 2010 15:44:20 -0300 Subject: perf ui browser: Add ui_browser__show counterpart: __hide So that the common tasks of providing a helpline at __run entry and destroying the window and releasing resourses at exit can be abstracted away, reducing a bit more the coupling with libnewt. Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 73e78ef38a5..55ff792459a 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -141,10 +141,10 @@ static int annotate_browser__run(struct annotate_browser *self, struct rb_node *nd; struct hist_entry *he = self->b.priv; - if (ui_browser__show(&self->b, he->ms.sym->name) < 0) + if (ui_browser__show(&self->b, he->ms.sym->name, + "<- or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) return -1; - ui_helpline__fpush("<- or ESC: exit, TAB/shift+TAB: cycle thru samples"); newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT); nd = self->curr_hot; @@ -177,9 +177,7 @@ static int annotate_browser__run(struct annotate_browser *self, } } out: - newtFormDestroy(self->b.form); - newtPopWindow(); - ui_helpline__pop(); + ui_browser__hide(&self->b); return 0; } -- cgit v1.2.3-18-g5258