diff options
Diffstat (limited to 'tools/perf/util/ui')
| -rw-r--r-- | tools/perf/util/ui/browser.c | 25 | ||||
| -rw-r--r-- | tools/perf/util/ui/browser.h | 3 | ||||
| -rw-r--r-- | tools/perf/util/ui/browsers/annotate.c | 178 | ||||
| -rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 199 | ||||
| -rw-r--r-- | tools/perf/util/ui/browsers/map.c | 7 | ||||
| -rw-r--r-- | tools/perf/util/ui/browsers/top.c | 213 | ||||
| -rw-r--r-- | tools/perf/util/ui/helpline.c | 5 | ||||
| -rw-r--r-- | tools/perf/util/ui/libslang.h | 6 | ||||
| -rw-r--r-- | tools/perf/util/ui/setup.c | 8 | ||||
| -rw-r--r-- | tools/perf/util/ui/ui.h | 8 | ||||
| -rw-r--r-- | tools/perf/util/ui/util.c | 7 |
11 files changed, 550 insertions, 109 deletions
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 8bc010edca2..611219f8068 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | #include "libslang.h" | 1 | #include "libslang.h" |
| 2 | #include "ui.h" | ||
| 2 | #include <linux/compiler.h> | 3 | #include <linux/compiler.h> |
| 3 | #include <linux/list.h> | 4 | #include <linux/list.h> |
| 4 | #include <linux/rbtree.h> | 5 | #include <linux/rbtree.h> |
| @@ -156,6 +157,20 @@ void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) | |||
| 156 | } | 157 | } |
| 157 | } | 158 | } |
| 158 | 159 | ||
| 160 | void __ui_browser__show_title(struct ui_browser *browser, const char *title) | ||
| 161 | { | ||
| 162 | SLsmg_gotorc(0, 0); | ||
| 163 | ui_browser__set_color(browser, NEWT_COLORSET_ROOT); | ||
| 164 | slsmg_write_nstring(title, browser->width); | ||
| 165 | } | ||
| 166 | |||
| 167 | void ui_browser__show_title(struct ui_browser *browser, const char *title) | ||
| 168 | { | ||
| 169 | pthread_mutex_lock(&ui__lock); | ||
| 170 | __ui_browser__show_title(browser, title); | ||
| 171 | pthread_mutex_unlock(&ui__lock); | ||
| 172 | } | ||
| 173 | |||
| 159 | int ui_browser__show(struct ui_browser *self, const char *title, | 174 | int ui_browser__show(struct ui_browser *self, const char *title, |
| 160 | const char *helpline, ...) | 175 | const char *helpline, ...) |
| 161 | { | 176 | { |
| @@ -178,9 +193,8 @@ int ui_browser__show(struct ui_browser *self, const char *title, | |||
| 178 | if (self->sb == NULL) | 193 | if (self->sb == NULL) |
| 179 | return -1; | 194 | return -1; |
| 180 | 195 | ||
| 181 | SLsmg_gotorc(0, 0); | 196 | pthread_mutex_lock(&ui__lock); |
| 182 | ui_browser__set_color(self, NEWT_COLORSET_ROOT); | 197 | __ui_browser__show_title(self, title); |
| 183 | slsmg_write_nstring(title, self->width); | ||
| 184 | 198 | ||
| 185 | ui_browser__add_exit_keys(self, keys); | 199 | ui_browser__add_exit_keys(self, keys); |
| 186 | newtFormAddComponent(self->form, self->sb); | 200 | newtFormAddComponent(self->form, self->sb); |
| @@ -188,25 +202,30 @@ int ui_browser__show(struct ui_browser *self, const char *title, | |||
| 188 | va_start(ap, helpline); | 202 | va_start(ap, helpline); |
| 189 | ui_helpline__vpush(helpline, ap); | 203 | ui_helpline__vpush(helpline, ap); |
| 190 | va_end(ap); | 204 | va_end(ap); |
| 205 | pthread_mutex_unlock(&ui__lock); | ||
| 191 | return 0; | 206 | return 0; |
| 192 | } | 207 | } |
| 193 | 208 | ||
| 194 | void ui_browser__hide(struct ui_browser *self) | 209 | void ui_browser__hide(struct ui_browser *self) |
| 195 | { | 210 | { |
| 211 | pthread_mutex_lock(&ui__lock); | ||
| 196 | newtFormDestroy(self->form); | 212 | newtFormDestroy(self->form); |
| 197 | self->form = NULL; | 213 | self->form = NULL; |
| 198 | ui_helpline__pop(); | 214 | ui_helpline__pop(); |
| 215 | pthread_mutex_unlock(&ui__lock); | ||
| 199 | } | 216 | } |
| 200 | 217 | ||
| 201 | int ui_browser__refresh(struct ui_browser *self) | 218 | int ui_browser__refresh(struct ui_browser *self) |
| 202 | { | 219 | { |
| 203 | int row; | 220 | int row; |
| 204 | 221 | ||
| 222 | pthread_mutex_lock(&ui__lock); | ||
| 205 | newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); | 223 | newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); |
| 206 | row = self->refresh(self); | 224 | row = self->refresh(self); |
| 207 | ui_browser__set_color(self, HE_COLORSET_NORMAL); | 225 | ui_browser__set_color(self, HE_COLORSET_NORMAL); |
| 208 | SLsmg_fill_region(self->y + row, self->x, | 226 | SLsmg_fill_region(self->y + row, self->x, |
| 209 | self->height - row, self->width, ' '); | 227 | self->height - row, self->width, ' '); |
| 228 | pthread_mutex_unlock(&ui__lock); | ||
| 210 | 229 | ||
| 211 | return 0; | 230 | return 0; |
| 212 | } | 231 | } |
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index 0dc7e4da36f..fc63dda1091 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h | |||
| @@ -24,7 +24,6 @@ struct ui_browser { | |||
| 24 | u32 nr_entries; | 24 | u32 nr_entries; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | |||
| 28 | void ui_browser__set_color(struct ui_browser *self, int color); | 27 | void ui_browser__set_color(struct ui_browser *self, int color); |
| 29 | void ui_browser__set_percent_color(struct ui_browser *self, | 28 | void ui_browser__set_percent_color(struct ui_browser *self, |
| 30 | double percent, bool current); | 29 | double percent, bool current); |
| @@ -35,6 +34,8 @@ void ui_browser__reset_index(struct ui_browser *self); | |||
| 35 | void ui_browser__gotorc(struct ui_browser *self, int y, int x); | 34 | void ui_browser__gotorc(struct ui_browser *self, int y, int x); |
| 36 | void ui_browser__add_exit_key(struct ui_browser *self, int key); | 35 | void ui_browser__add_exit_key(struct ui_browser *self, int key); |
| 37 | void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]); | 36 | void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]); |
| 37 | void __ui_browser__show_title(struct ui_browser *browser, const char *title); | ||
| 38 | void ui_browser__show_title(struct ui_browser *browser, const char *title); | ||
| 38 | int ui_browser__show(struct ui_browser *self, const char *title, | 39 | int ui_browser__show(struct ui_browser *self, const char *title, |
| 39 | const char *helpline, ...); | 40 | const char *helpline, ...); |
| 40 | void ui_browser__hide(struct ui_browser *self); | 41 | void ui_browser__hide(struct ui_browser *self); |
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 82b78f99251..8c17a8730e4 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | #include "../browser.h" | 1 | #include "../browser.h" |
| 2 | #include "../helpline.h" | 2 | #include "../helpline.h" |
| 3 | #include "../libslang.h" | 3 | #include "../libslang.h" |
| 4 | #include "../../annotate.h" | ||
| 4 | #include "../../hist.h" | 5 | #include "../../hist.h" |
| 5 | #include "../../sort.h" | 6 | #include "../../sort.h" |
| 6 | #include "../../symbol.h" | 7 | #include "../../symbol.h" |
| 8 | #include "../../annotate.h" | ||
| 9 | #include <pthread.h> | ||
| 7 | 10 | ||
| 8 | static void ui__error_window(const char *fmt, ...) | 11 | static void ui__error_window(const char *fmt, ...) |
| 9 | { | 12 | { |
| @@ -42,8 +45,6 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro | |||
| 42 | struct objdump_line_rb_node *olrb = objdump_line__rb(ol); | 45 | struct objdump_line_rb_node *olrb = objdump_line__rb(ol); |
| 43 | ui_browser__set_percent_color(self, olrb->percent, current_entry); | 46 | ui_browser__set_percent_color(self, olrb->percent, current_entry); |
| 44 | slsmg_printf(" %7.2f ", olrb->percent); | 47 | slsmg_printf(" %7.2f ", olrb->percent); |
| 45 | if (!current_entry) | ||
| 46 | ui_browser__set_color(self, HE_COLORSET_CODE); | ||
| 47 | } else { | 48 | } else { |
| 48 | ui_browser__set_percent_color(self, 0, current_entry); | 49 | ui_browser__set_percent_color(self, 0, current_entry); |
| 49 | slsmg_write_nstring(" ", 9); | 50 | slsmg_write_nstring(" ", 9); |
| @@ -55,35 +56,40 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro | |||
| 55 | slsmg_write_nstring(" ", width - 18); | 56 | slsmg_write_nstring(" ", width - 18); |
| 56 | else | 57 | else |
| 57 | slsmg_write_nstring(ol->line, width - 18); | 58 | slsmg_write_nstring(ol->line, width - 18); |
| 59 | |||
| 60 | if (!current_entry) | ||
| 61 | ui_browser__set_color(self, HE_COLORSET_CODE); | ||
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | static double objdump_line__calc_percent(struct objdump_line *self, | 64 | static double objdump_line__calc_percent(struct objdump_line *self, |
| 61 | struct list_head *head, | 65 | struct symbol *sym, int evidx) |
| 62 | struct symbol *sym) | ||
| 63 | { | 66 | { |
| 64 | double percent = 0.0; | 67 | double percent = 0.0; |
| 65 | 68 | ||
| 66 | if (self->offset != -1) { | 69 | if (self->offset != -1) { |
| 67 | int len = sym->end - sym->start; | 70 | int len = sym->end - sym->start; |
| 68 | unsigned int hits = 0; | 71 | unsigned int hits = 0; |
| 69 | struct sym_priv *priv = symbol__priv(sym); | 72 | struct annotation *notes = symbol__annotation(sym); |
| 70 | struct sym_ext *sym_ext = priv->ext; | 73 | struct source_line *src_line = notes->src->lines; |
| 71 | struct sym_hist *h = priv->hist; | 74 | struct sym_hist *h = annotation__histogram(notes, evidx); |
| 72 | s64 offset = self->offset; | 75 | s64 offset = self->offset; |
| 73 | struct objdump_line *next = objdump__get_next_ip_line(head, self); | 76 | struct objdump_line *next; |
| 74 | |||
| 75 | 77 | ||
| 78 | next = objdump__get_next_ip_line(¬es->src->source, self); | ||
| 76 | while (offset < (s64)len && | 79 | while (offset < (s64)len && |
| 77 | (next == NULL || offset < next->offset)) { | 80 | (next == NULL || offset < next->offset)) { |
| 78 | if (sym_ext) { | 81 | if (src_line) { |
| 79 | percent += sym_ext[offset].percent; | 82 | percent += src_line[offset].percent; |
| 80 | } else | 83 | } else |
| 81 | hits += h->ip[offset]; | 84 | hits += h->addr[offset]; |
| 82 | 85 | ||
| 83 | ++offset; | 86 | ++offset; |
| 84 | } | 87 | } |
| 85 | 88 | /* | |
| 86 | if (sym_ext == NULL && h->sum) | 89 | * If the percentage wasn't already calculated in |
| 90 | * symbol__get_source_line, do it now: | ||
| 91 | */ | ||
| 92 | if (src_line == NULL && h->sum) | ||
| 87 | percent = 100.0 * hits / h->sum; | 93 | percent = 100.0 * hits / h->sum; |
| 88 | } | 94 | } |
| 89 | 95 | ||
| @@ -133,103 +139,161 @@ static void annotate_browser__set_top(struct annotate_browser *self, | |||
| 133 | self->curr_hot = nd; | 139 | self->curr_hot = nd; |
| 134 | } | 140 | } |
| 135 | 141 | ||
| 136 | static int annotate_browser__run(struct annotate_browser *self) | 142 | static void annotate_browser__calc_percent(struct annotate_browser *browser, |
| 143 | int evidx) | ||
| 137 | { | 144 | { |
| 138 | struct rb_node *nd; | 145 | struct symbol *sym = browser->b.priv; |
| 139 | struct hist_entry *he = self->b.priv; | 146 | struct annotation *notes = symbol__annotation(sym); |
| 140 | int key; | 147 | struct objdump_line *pos; |
| 141 | 148 | ||
| 142 | if (ui_browser__show(&self->b, he->ms.sym->name, | 149 | browser->entries = RB_ROOT; |
| 143 | "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) | 150 | |
| 144 | return -1; | 151 | pthread_mutex_lock(¬es->lock); |
| 152 | |||
| 153 | list_for_each_entry(pos, ¬es->src->source, node) { | ||
| 154 | struct objdump_line_rb_node *rbpos = objdump_line__rb(pos); | ||
| 155 | rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); | ||
| 156 | if (rbpos->percent < 0.01) { | ||
| 157 | RB_CLEAR_NODE(&rbpos->rb_node); | ||
| 158 | continue; | ||
| 159 | } | ||
| 160 | objdump__insert_line(&browser->entries, rbpos); | ||
| 161 | } | ||
| 162 | pthread_mutex_unlock(¬es->lock); | ||
| 163 | |||
| 164 | browser->curr_hot = rb_last(&browser->entries); | ||
| 165 | } | ||
| 166 | |||
| 167 | static int annotate_browser__run(struct annotate_browser *self, int evidx, | ||
| 168 | int refresh) | ||
| 169 | { | ||
| 170 | struct rb_node *nd = NULL; | ||
| 171 | struct symbol *sym = self->b.priv; | ||
| 145 | /* | 172 | /* |
| 146 | * To allow builtin-annotate to cycle thru multiple symbols by | 173 | * RIGHT To allow builtin-annotate to cycle thru multiple symbols by |
| 147 | * examining the exit key for this function. | 174 | * examining the exit key for this function. |
| 148 | */ | 175 | */ |
| 149 | ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT); | 176 | int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, |
| 177 | NEWT_KEY_RIGHT, 0 }; | ||
| 178 | int key; | ||
| 179 | |||
| 180 | if (ui_browser__show(&self->b, sym->name, | ||
| 181 | "<-, -> or ESC: exit, TAB/shift+TAB: " | ||
| 182 | "cycle hottest lines, H: Hottest") < 0) | ||
| 183 | return -1; | ||
| 184 | |||
| 185 | ui_browser__add_exit_keys(&self->b, exit_keys); | ||
| 186 | annotate_browser__calc_percent(self, evidx); | ||
| 187 | |||
| 188 | if (self->curr_hot) | ||
| 189 | annotate_browser__set_top(self, self->curr_hot); | ||
| 150 | 190 | ||
| 151 | nd = self->curr_hot; | 191 | nd = self->curr_hot; |
| 152 | if (nd) { | 192 | |
| 153 | int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 }; | 193 | if (refresh != 0) |
| 154 | ui_browser__add_exit_keys(&self->b, tabs); | 194 | newtFormSetTimer(self->b.form, refresh); |
| 155 | } | ||
| 156 | 195 | ||
| 157 | while (1) { | 196 | while (1) { |
| 158 | key = ui_browser__run(&self->b); | 197 | key = ui_browser__run(&self->b); |
| 159 | 198 | ||
| 199 | if (refresh != 0) { | ||
| 200 | annotate_browser__calc_percent(self, evidx); | ||
| 201 | /* | ||
| 202 | * Current line focus got out of the list of most active | ||
| 203 | * lines, NULL it so that if TAB|UNTAB is pressed, we | ||
| 204 | * move to curr_hot (current hottest line). | ||
| 205 | */ | ||
| 206 | if (nd != NULL && RB_EMPTY_NODE(nd)) | ||
| 207 | nd = NULL; | ||
| 208 | } | ||
| 209 | |||
| 160 | switch (key) { | 210 | switch (key) { |
| 211 | case -1: | ||
| 212 | /* | ||
| 213 | * FIXME we need to check if it was | ||
| 214 | * es.reason == NEWT_EXIT_TIMER | ||
| 215 | */ | ||
| 216 | if (refresh != 0) | ||
| 217 | symbol__annotate_decay_histogram(sym, evidx); | ||
| 218 | continue; | ||
| 161 | case NEWT_KEY_TAB: | 219 | case NEWT_KEY_TAB: |
| 162 | nd = rb_prev(nd); | 220 | if (nd != NULL) { |
| 163 | if (nd == NULL) | 221 | nd = rb_prev(nd); |
| 164 | nd = rb_last(&self->entries); | 222 | if (nd == NULL) |
| 165 | annotate_browser__set_top(self, nd); | 223 | nd = rb_last(&self->entries); |
| 224 | } else | ||
| 225 | nd = self->curr_hot; | ||
| 166 | break; | 226 | break; |
| 167 | case NEWT_KEY_UNTAB: | 227 | case NEWT_KEY_UNTAB: |
| 168 | nd = rb_next(nd); | 228 | if (nd != NULL) |
| 169 | if (nd == NULL) | 229 | nd = rb_next(nd); |
| 170 | nd = rb_first(&self->entries); | 230 | if (nd == NULL) |
| 171 | annotate_browser__set_top(self, nd); | 231 | nd = rb_first(&self->entries); |
| 232 | else | ||
| 233 | nd = self->curr_hot; | ||
| 234 | break; | ||
| 235 | case 'H': | ||
| 236 | nd = self->curr_hot; | ||
| 172 | break; | 237 | break; |
| 173 | default: | 238 | default: |
| 174 | goto out; | 239 | goto out; |
| 175 | } | 240 | } |
| 241 | |||
| 242 | if (nd != NULL) | ||
| 243 | annotate_browser__set_top(self, nd); | ||
| 176 | } | 244 | } |
| 177 | out: | 245 | out: |
| 178 | ui_browser__hide(&self->b); | 246 | ui_browser__hide(&self->b); |
| 179 | return key; | 247 | return key; |
| 180 | } | 248 | } |
| 181 | 249 | ||
| 182 | int hist_entry__tui_annotate(struct hist_entry *self) | 250 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx) |
| 251 | { | ||
| 252 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); | ||
| 253 | } | ||
| 254 | |||
| 255 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | ||
| 256 | int refresh) | ||
| 183 | { | 257 | { |
| 184 | struct objdump_line *pos, *n; | 258 | struct objdump_line *pos, *n; |
| 185 | struct objdump_line_rb_node *rbpos; | 259 | struct annotation *notes = symbol__annotation(sym); |
| 186 | LIST_HEAD(head); | ||
| 187 | struct annotate_browser browser = { | 260 | struct annotate_browser browser = { |
| 188 | .b = { | 261 | .b = { |
| 189 | .entries = &head, | 262 | .entries = ¬es->src->source, |
| 190 | .refresh = ui_browser__list_head_refresh, | 263 | .refresh = ui_browser__list_head_refresh, |
| 191 | .seek = ui_browser__list_head_seek, | 264 | .seek = ui_browser__list_head_seek, |
| 192 | .write = annotate_browser__write, | 265 | .write = annotate_browser__write, |
| 193 | .priv = self, | 266 | .priv = sym, |
| 194 | }, | 267 | }, |
| 195 | }; | 268 | }; |
| 196 | int ret; | 269 | int ret; |
| 197 | 270 | ||
| 198 | if (self->ms.sym == NULL) | 271 | if (sym == NULL) |
| 199 | return -1; | 272 | return -1; |
| 200 | 273 | ||
| 201 | if (self->ms.map->dso->annotate_warned) | 274 | if (map->dso->annotate_warned) |
| 202 | return -1; | 275 | return -1; |
| 203 | 276 | ||
| 204 | if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { | 277 | if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { |
| 205 | ui__error_window(ui_helpline__last_msg); | 278 | ui__error_window(ui_helpline__last_msg); |
| 206 | return -1; | 279 | return -1; |
| 207 | } | 280 | } |
| 208 | 281 | ||
| 209 | ui_helpline__push("Press <- or ESC to exit"); | 282 | ui_helpline__push("Press <- or ESC to exit"); |
| 210 | 283 | ||
| 211 | list_for_each_entry(pos, &head, node) { | 284 | list_for_each_entry(pos, ¬es->src->source, node) { |
| 285 | struct objdump_line_rb_node *rbpos; | ||
| 212 | size_t line_len = strlen(pos->line); | 286 | size_t line_len = strlen(pos->line); |
| 287 | |||
| 213 | if (browser.b.width < line_len) | 288 | if (browser.b.width < line_len) |
| 214 | browser.b.width = line_len; | 289 | browser.b.width = line_len; |
| 215 | rbpos = objdump_line__rb(pos); | 290 | rbpos = objdump_line__rb(pos); |
| 216 | rbpos->idx = browser.b.nr_entries++; | 291 | rbpos->idx = browser.b.nr_entries++; |
| 217 | rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym); | ||
| 218 | if (rbpos->percent < 0.01) | ||
| 219 | continue; | ||
| 220 | objdump__insert_line(&browser.entries, rbpos); | ||
| 221 | } | 292 | } |
| 222 | 293 | ||
| 223 | /* | ||
| 224 | * Position the browser at the hottest line. | ||
| 225 | */ | ||
| 226 | browser.curr_hot = rb_last(&browser.entries); | ||
| 227 | if (browser.curr_hot) | ||
| 228 | annotate_browser__set_top(&browser, browser.curr_hot); | ||
| 229 | |||
| 230 | browser.b.width += 18; /* Percentage */ | 294 | browser.b.width += 18; /* Percentage */ |
| 231 | ret = annotate_browser__run(&browser); | 295 | ret = annotate_browser__run(&browser, evidx, refresh); |
| 232 | list_for_each_entry_safe(pos, n, &head, node) { | 296 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { |
| 233 | list_del(&pos->node); | 297 | list_del(&pos->node); |
| 234 | objdump_line__free(pos); | 298 | objdump_line__free(pos); |
| 235 | } | 299 | } |
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index ebda8c3fde9..798efdca3ea 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include <newt.h> | 7 | #include <newt.h> |
| 8 | #include <linux/rbtree.h> | 8 | #include <linux/rbtree.h> |
| 9 | 9 | ||
| 10 | #include "../../evsel.h" | ||
| 11 | #include "../../evlist.h" | ||
| 10 | #include "../../hist.h" | 12 | #include "../../hist.h" |
| 11 | #include "../../pstack.h" | 13 | #include "../../pstack.h" |
| 12 | #include "../../sort.h" | 14 | #include "../../sort.h" |
| @@ -292,7 +294,8 @@ static int hist_browser__run(struct hist_browser *self, const char *title) | |||
| 292 | { | 294 | { |
| 293 | int key; | 295 | int key; |
| 294 | int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', | 296 | int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', |
| 295 | NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 0, }; | 297 | NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, |
| 298 | NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, }; | ||
| 296 | 299 | ||
| 297 | self->b.entries = &self->hists->entries; | 300 | self->b.entries = &self->hists->entries; |
| 298 | self->b.nr_entries = self->hists->nr_entries; | 301 | self->b.nr_entries = self->hists->nr_entries; |
| @@ -350,7 +353,7 @@ static char *callchain_list__sym_name(struct callchain_list *self, | |||
| 350 | if (self->ms.sym) | 353 | if (self->ms.sym) |
| 351 | return self->ms.sym->name; | 354 | return self->ms.sym->name; |
| 352 | 355 | ||
| 353 | snprintf(bf, bfsize, "%#Lx", self->ip); | 356 | snprintf(bf, bfsize, "%#" PRIx64, self->ip); |
| 354 | return bf; | 357 | return bf; |
| 355 | } | 358 | } |
| 356 | 359 | ||
| @@ -377,7 +380,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self, | |||
| 377 | while (node) { | 380 | while (node) { |
| 378 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); | 381 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); |
| 379 | struct rb_node *next = rb_next(node); | 382 | struct rb_node *next = rb_next(node); |
| 380 | u64 cumul = cumul_hits(child); | 383 | u64 cumul = callchain_cumul_hits(child); |
| 381 | struct callchain_list *chain; | 384 | struct callchain_list *chain; |
| 382 | char folded_sign = ' '; | 385 | char folded_sign = ' '; |
| 383 | int first = true; | 386 | int first = true; |
| @@ -638,6 +641,9 @@ static void ui_browser__hists_seek(struct ui_browser *self, | |||
| 638 | struct rb_node *nd; | 641 | struct rb_node *nd; |
| 639 | bool first = true; | 642 | bool first = true; |
| 640 | 643 | ||
| 644 | if (self->nr_entries == 0) | ||
| 645 | return; | ||
| 646 | |||
| 641 | switch (whence) { | 647 | switch (whence) { |
| 642 | case SEEK_SET: | 648 | case SEEK_SET: |
| 643 | nd = hists__filter_entries(rb_first(self->entries)); | 649 | nd = hists__filter_entries(rb_first(self->entries)); |
| @@ -797,8 +803,11 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size, | |||
| 797 | return printed; | 803 | return printed; |
| 798 | } | 804 | } |
| 799 | 805 | ||
| 800 | int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | 806 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, |
| 807 | const char *helpline, const char *ev_name, | ||
| 808 | bool left_exits) | ||
| 801 | { | 809 | { |
| 810 | struct hists *self = &evsel->hists; | ||
| 802 | struct hist_browser *browser = hist_browser__new(self); | 811 | struct hist_browser *browser = hist_browser__new(self); |
| 803 | struct pstack *fstack; | 812 | struct pstack *fstack; |
| 804 | const struct thread *thread_filter = NULL; | 813 | const struct thread *thread_filter = NULL; |
| @@ -818,8 +827,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
| 818 | hists__browser_title(self, msg, sizeof(msg), ev_name, | 827 | hists__browser_title(self, msg, sizeof(msg), ev_name, |
| 819 | dso_filter, thread_filter); | 828 | dso_filter, thread_filter); |
| 820 | while (1) { | 829 | while (1) { |
| 821 | const struct thread *thread; | 830 | const struct thread *thread = NULL; |
| 822 | const struct dso *dso; | 831 | const struct dso *dso = NULL; |
| 823 | char *options[16]; | 832 | char *options[16]; |
| 824 | int nr_options = 0, choice = 0, i, | 833 | int nr_options = 0, choice = 0, i, |
| 825 | annotate = -2, zoom_dso = -2, zoom_thread = -2, | 834 | annotate = -2, zoom_dso = -2, zoom_thread = -2, |
| @@ -827,8 +836,10 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
| 827 | 836 | ||
| 828 | key = hist_browser__run(browser, msg); | 837 | key = hist_browser__run(browser, msg); |
| 829 | 838 | ||
| 830 | thread = hist_browser__selected_thread(browser); | 839 | if (browser->he_selection != NULL) { |
| 831 | dso = browser->selection->map ? browser->selection->map->dso : NULL; | 840 | thread = hist_browser__selected_thread(browser); |
| 841 | dso = browser->selection->map ? browser->selection->map->dso : NULL; | ||
| 842 | } | ||
| 832 | 843 | ||
| 833 | switch (key) { | 844 | switch (key) { |
| 834 | case NEWT_KEY_TAB: | 845 | case NEWT_KEY_TAB: |
| @@ -839,7 +850,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
| 839 | */ | 850 | */ |
| 840 | goto out_free_stack; | 851 | goto out_free_stack; |
| 841 | case 'a': | 852 | case 'a': |
| 842 | if (browser->selection->map == NULL && | 853 | if (browser->selection == NULL || |
| 854 | browser->selection->map == NULL || | ||
| 843 | browser->selection->map->dso->annotate_warned) | 855 | browser->selection->map->dso->annotate_warned) |
| 844 | continue; | 856 | continue; |
| 845 | goto do_annotate; | 857 | goto do_annotate; |
| @@ -858,6 +870,7 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
| 858 | "E Expand all callchains\n" | 870 | "E Expand all callchains\n" |
| 859 | "d Zoom into current DSO\n" | 871 | "d Zoom into current DSO\n" |
| 860 | "t Zoom into current Thread\n" | 872 | "t Zoom into current Thread\n" |
| 873 | "TAB/UNTAB Switch events\n" | ||
| 861 | "q/CTRL+C Exit browser"); | 874 | "q/CTRL+C Exit browser"); |
| 862 | continue; | 875 | continue; |
| 863 | case NEWT_KEY_ENTER: | 876 | case NEWT_KEY_ENTER: |
| @@ -867,8 +880,14 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
| 867 | case NEWT_KEY_LEFT: { | 880 | case NEWT_KEY_LEFT: { |
| 868 | const void *top; | 881 | const void *top; |
| 869 | 882 | ||
| 870 | if (pstack__empty(fstack)) | 883 | if (pstack__empty(fstack)) { |
| 884 | /* | ||
| 885 | * Go back to the perf_evsel_menu__run or other user | ||
| 886 | */ | ||
| 887 | if (left_exits) | ||
| 888 | goto out_free_stack; | ||
| 871 | continue; | 889 | continue; |
| 890 | } | ||
| 872 | top = pstack__pop(fstack); | 891 | top = pstack__pop(fstack); |
| 873 | if (top == &dso_filter) | 892 | if (top == &dso_filter) |
| 874 | goto zoom_out_dso; | 893 | goto zoom_out_dso; |
| @@ -877,14 +896,16 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
| 877 | continue; | 896 | continue; |
| 878 | } | 897 | } |
| 879 | case NEWT_KEY_ESCAPE: | 898 | case NEWT_KEY_ESCAPE: |
| 880 | if (!ui__dialog_yesno("Do you really want to exit?")) | 899 | if (!left_exits && |
| 900 | !ui__dialog_yesno("Do you really want to exit?")) | ||
| 881 | continue; | 901 | continue; |
| 882 | /* Fall thru */ | 902 | /* Fall thru */ |
| 883 | default: | 903 | default: |
| 884 | goto out_free_stack; | 904 | goto out_free_stack; |
| 885 | } | 905 | } |
| 886 | 906 | ||
| 887 | if (browser->selection->sym != NULL && | 907 | if (browser->selection != NULL && |
| 908 | browser->selection->sym != NULL && | ||
| 888 | !browser->selection->map->dso->annotate_warned && | 909 | !browser->selection->map->dso->annotate_warned && |
| 889 | asprintf(&options[nr_options], "Annotate %s", | 910 | asprintf(&options[nr_options], "Annotate %s", |
| 890 | browser->selection->sym->name) > 0) | 911 | browser->selection->sym->name) > 0) |
| @@ -903,7 +924,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
| 903 | (dso->kernel ? "the Kernel" : dso->short_name)) > 0) | 924 | (dso->kernel ? "the Kernel" : dso->short_name)) > 0) |
| 904 | zoom_dso = nr_options++; | 925 | zoom_dso = nr_options++; |
| 905 | 926 | ||
| 906 | if (browser->selection->map != NULL && | 927 | if (browser->selection != NULL && |
| 928 | browser->selection->map != NULL && | ||
| 907 | asprintf(&options[nr_options], "Browse map details") > 0) | 929 | asprintf(&options[nr_options], "Browse map details") > 0) |
| 908 | browse_map = nr_options++; | 930 | browse_map = nr_options++; |
| 909 | 931 | ||
| @@ -923,19 +945,11 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
| 923 | if (choice == annotate) { | 945 | if (choice == annotate) { |
| 924 | struct hist_entry *he; | 946 | struct hist_entry *he; |
| 925 | do_annotate: | 947 | do_annotate: |
| 926 | if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { | ||
| 927 | browser->selection->map->dso->annotate_warned = 1; | ||
| 928 | ui_helpline__puts("No vmlinux file found, can't " | ||
| 929 | "annotate with just a " | ||
| 930 | "kallsyms file"); | ||
| 931 | continue; | ||
| 932 | } | ||
| 933 | |||
| 934 | he = hist_browser__selected_entry(browser); | 948 | he = hist_browser__selected_entry(browser); |
| 935 | if (he == NULL) | 949 | if (he == NULL) |
| 936 | continue; | 950 | continue; |
| 937 | 951 | ||
| 938 | hist_entry__tui_annotate(he); | 952 | hist_entry__tui_annotate(he, evsel->idx); |
| 939 | } else if (choice == browse_map) | 953 | } else if (choice == browse_map) |
| 940 | map__browse(browser->selection->map); | 954 | map__browse(browser->selection->map); |
| 941 | else if (choice == zoom_dso) { | 955 | else if (choice == zoom_dso) { |
| @@ -984,30 +998,141 @@ out: | |||
| 984 | return key; | 998 | return key; |
| 985 | } | 999 | } |
| 986 | 1000 | ||
| 987 | int hists__tui_browse_tree(struct rb_root *self, const char *help) | 1001 | struct perf_evsel_menu { |
| 1002 | struct ui_browser b; | ||
| 1003 | struct perf_evsel *selection; | ||
| 1004 | }; | ||
| 1005 | |||
| 1006 | static void perf_evsel_menu__write(struct ui_browser *browser, | ||
| 1007 | void *entry, int row) | ||
| 1008 | { | ||
| 1009 | struct perf_evsel_menu *menu = container_of(browser, | ||
| 1010 | struct perf_evsel_menu, b); | ||
| 1011 | struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); | ||
| 1012 | bool current_entry = ui_browser__is_current_entry(browser, row); | ||
| 1013 | unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | ||
| 1014 | const char *ev_name = event_name(evsel); | ||
| 1015 | char bf[256], unit; | ||
| 1016 | |||
| 1017 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | ||
| 1018 | HE_COLORSET_NORMAL); | ||
| 1019 | |||
| 1020 | nr_events = convert_unit(nr_events, &unit); | ||
| 1021 | snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, | ||
| 1022 | unit, unit == ' ' ? "" : " ", ev_name); | ||
| 1023 | slsmg_write_nstring(bf, browser->width); | ||
| 1024 | |||
| 1025 | if (current_entry) | ||
| 1026 | menu->selection = evsel; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) | ||
| 988 | { | 1030 | { |
| 989 | struct rb_node *first = rb_first(self), *nd = first, *next; | 1031 | int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; |
| 990 | int key = 0; | 1032 | struct perf_evlist *evlist = menu->b.priv; |
| 1033 | struct perf_evsel *pos; | ||
| 1034 | const char *ev_name, *title = "Available samples"; | ||
| 1035 | int key; | ||
| 1036 | |||
| 1037 | if (ui_browser__show(&menu->b, title, | ||
| 1038 | "ESC: exit, ENTER|->: Browse histograms") < 0) | ||
| 1039 | return -1; | ||
| 1040 | |||
| 1041 | ui_browser__add_exit_keys(&menu->b, exit_keys); | ||
| 991 | 1042 | ||
| 992 | while (nd) { | 1043 | while (1) { |
| 993 | struct hists *hists = rb_entry(nd, struct hists, rb_node); | 1044 | key = ui_browser__run(&menu->b); |
| 994 | const char *ev_name = __event_name(hists->type, hists->config); | ||
| 995 | 1045 | ||
| 996 | key = hists__browse(hists, help, ev_name); | ||
| 997 | switch (key) { | 1046 | switch (key) { |
| 998 | case NEWT_KEY_TAB: | 1047 | case NEWT_KEY_RIGHT: |
| 999 | next = rb_next(nd); | 1048 | case NEWT_KEY_ENTER: |
| 1000 | if (next) | 1049 | if (!menu->selection) |
| 1001 | nd = next; | 1050 | continue; |
| 1051 | pos = menu->selection; | ||
| 1052 | browse_hists: | ||
| 1053 | ev_name = event_name(pos); | ||
| 1054 | key = perf_evsel__hists_browse(pos, help, ev_name, true); | ||
| 1055 | ui_browser__show_title(&menu->b, title); | ||
| 1002 | break; | 1056 | break; |
| 1003 | case NEWT_KEY_UNTAB: | 1057 | case NEWT_KEY_LEFT: |
| 1004 | if (nd == first) | 1058 | continue; |
| 1059 | case NEWT_KEY_ESCAPE: | ||
| 1060 | if (!ui__dialog_yesno("Do you really want to exit?")) | ||
| 1005 | continue; | 1061 | continue; |
| 1006 | nd = rb_prev(nd); | 1062 | /* Fall thru */ |
| 1063 | default: | ||
| 1064 | goto out; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | switch (key) { | ||
| 1068 | case NEWT_KEY_TAB: | ||
| 1069 | if (pos->node.next == &evlist->entries) | ||
| 1070 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
| 1071 | else | ||
| 1072 | pos = list_entry(pos->node.next, struct perf_evsel, node); | ||
| 1073 | goto browse_hists; | ||
| 1074 | case NEWT_KEY_UNTAB: | ||
| 1075 | if (pos->node.prev == &evlist->entries) | ||
| 1076 | pos = list_entry(evlist->entries.prev, struct perf_evsel, node); | ||
| 1077 | else | ||
| 1078 | pos = list_entry(pos->node.prev, struct perf_evsel, node); | ||
| 1079 | goto browse_hists; | ||
| 1080 | case 'q': | ||
| 1081 | case CTRL('c'): | ||
| 1082 | goto out; | ||
| 1007 | default: | 1083 | default: |
| 1008 | return key; | 1084 | break; |
| 1009 | } | 1085 | } |
| 1010 | } | 1086 | } |
| 1011 | 1087 | ||
| 1088 | out: | ||
| 1089 | ui_browser__hide(&menu->b); | ||
| 1012 | return key; | 1090 | return key; |
| 1013 | } | 1091 | } |
| 1092 | |||
| 1093 | static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | ||
| 1094 | const char *help) | ||
| 1095 | { | ||
| 1096 | struct perf_evsel *pos; | ||
| 1097 | struct perf_evsel_menu menu = { | ||
| 1098 | .b = { | ||
| 1099 | .entries = &evlist->entries, | ||
| 1100 | .refresh = ui_browser__list_head_refresh, | ||
| 1101 | .seek = ui_browser__list_head_seek, | ||
| 1102 | .write = perf_evsel_menu__write, | ||
| 1103 | .nr_entries = evlist->nr_entries, | ||
| 1104 | .priv = evlist, | ||
| 1105 | }, | ||
| 1106 | }; | ||
| 1107 | |||
| 1108 | ui_helpline__push("Press ESC to exit"); | ||
| 1109 | |||
| 1110 | list_for_each_entry(pos, &evlist->entries, node) { | ||
| 1111 | const char *ev_name = event_name(pos); | ||
| 1112 | size_t line_len = strlen(ev_name) + 7; | ||
| 1113 | |||
| 1114 | if (menu.b.width < line_len) | ||
| 1115 | menu.b.width = line_len; | ||
| 1116 | /* | ||
| 1117 | * Cache the evsel name, tracepoints have a _high_ cost per | ||
| 1118 | * event_name() call. | ||
| 1119 | */ | ||
| 1120 | if (pos->name == NULL) | ||
| 1121 | pos->name = strdup(ev_name); | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | return perf_evsel_menu__run(&menu, help); | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) | ||
| 1128 | { | ||
| 1129 | |||
| 1130 | if (evlist->nr_entries == 1) { | ||
| 1131 | struct perf_evsel *first = list_entry(evlist->entries.next, | ||
| 1132 | struct perf_evsel, node); | ||
| 1133 | const char *ev_name = event_name(first); | ||
| 1134 | return perf_evsel__hists_browse(first, help, ev_name, false); | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | return __perf_evlist__tui_browse_hists(evlist, help); | ||
| 1138 | } | ||
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c index e35437dfa5b..8462bffe20b 100644 --- a/tools/perf/util/ui/browsers/map.c +++ b/tools/perf/util/ui/browsers/map.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #include "../libslang.h" | 1 | #include "../libslang.h" |
| 2 | #include <elf.h> | 2 | #include <elf.h> |
| 3 | #include <inttypes.h> | ||
| 3 | #include <sys/ttydefaults.h> | 4 | #include <sys/ttydefaults.h> |
| 4 | #include <ctype.h> | 5 | #include <ctype.h> |
| 5 | #include <string.h> | 6 | #include <string.h> |
| @@ -40,7 +41,7 @@ static int ui_entry__read(const char *title, char *bf, size_t size, int width) | |||
| 40 | out_free_form: | 41 | out_free_form: |
| 41 | newtPopWindow(); | 42 | newtPopWindow(); |
| 42 | newtFormDestroy(form); | 43 | newtFormDestroy(form); |
| 43 | return 0; | 44 | return err; |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | struct map_browser { | 47 | struct map_browser { |
| @@ -57,7 +58,7 @@ static void map_browser__write(struct ui_browser *self, void *nd, int row) | |||
| 57 | int width; | 58 | int width; |
| 58 | 59 | ||
| 59 | ui_browser__set_percent_color(self, 0, current_entry); | 60 | ui_browser__set_percent_color(self, 0, current_entry); |
| 60 | slsmg_printf("%*llx %*llx %c ", | 61 | slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ", |
| 61 | mb->addrlen, sym->start, mb->addrlen, sym->end, | 62 | mb->addrlen, sym->start, mb->addrlen, sym->end, |
| 62 | sym->binding == STB_GLOBAL ? 'g' : | 63 | sym->binding == STB_GLOBAL ? 'g' : |
| 63 | sym->binding == STB_LOCAL ? 'l' : 'w'); | 64 | sym->binding == STB_LOCAL ? 'l' : 'w'); |
| @@ -150,6 +151,6 @@ int map__browse(struct map *self) | |||
| 150 | ++mb.b.nr_entries; | 151 | ++mb.b.nr_entries; |
| 151 | } | 152 | } |
| 152 | 153 | ||
| 153 | mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr); | 154 | mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr); |
| 154 | return map_browser__run(&mb); | 155 | return map_browser__run(&mb); |
| 155 | } | 156 | } |
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c new file mode 100644 index 00000000000..5a06538532a --- /dev/null +++ b/tools/perf/util/ui/browsers/top.c | |||
| @@ -0,0 +1,213 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | ||
| 3 | * | ||
| 4 | * Parts came from builtin-{top,stat,record}.c, see those files for further | ||
| 5 | * copyright notes. | ||
| 6 | * | ||
| 7 | * Released under the GPL v2. (and only v2, not any later version) | ||
| 8 | */ | ||
| 9 | #include "../browser.h" | ||
| 10 | #include "../../annotate.h" | ||
| 11 | #include "../helpline.h" | ||
| 12 | #include "../libslang.h" | ||
| 13 | #include "../util.h" | ||
| 14 | #include "../../evlist.h" | ||
| 15 | #include "../../hist.h" | ||
| 16 | #include "../../sort.h" | ||
| 17 | #include "../../symbol.h" | ||
| 18 | #include "../../top.h" | ||
| 19 | |||
| 20 | struct perf_top_browser { | ||
| 21 | struct ui_browser b; | ||
| 22 | struct rb_root root; | ||
| 23 | struct sym_entry *selection; | ||
| 24 | float sum_ksamples; | ||
| 25 | int dso_width; | ||
| 26 | int dso_short_width; | ||
| 27 | int sym_width; | ||
| 28 | }; | ||
| 29 | |||
| 30 | static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row) | ||
| 31 | { | ||
| 32 | struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b); | ||
| 33 | struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node); | ||
| 34 | bool current_entry = ui_browser__is_current_entry(browser, row); | ||
| 35 | struct symbol *symbol = sym_entry__symbol(syme); | ||
| 36 | struct perf_top *top = browser->priv; | ||
| 37 | int width = browser->width; | ||
| 38 | double pcnt; | ||
| 39 | |||
| 40 | pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) / | ||
| 41 | top_browser->sum_ksamples)); | ||
| 42 | ui_browser__set_percent_color(browser, pcnt, current_entry); | ||
| 43 | |||
| 44 | if (top->evlist->nr_entries == 1 || !top->display_weighted) { | ||
| 45 | slsmg_printf("%20.2f ", syme->weight); | ||
| 46 | width -= 24; | ||
| 47 | } else { | ||
| 48 | slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count); | ||
| 49 | width -= 23; | ||
| 50 | } | ||
| 51 | |||
| 52 | slsmg_printf("%4.1f%%", pcnt); | ||
| 53 | width -= 7; | ||
| 54 | |||
| 55 | if (verbose) { | ||
| 56 | slsmg_printf(" %016" PRIx64, symbol->start); | ||
| 57 | width -= 17; | ||
| 58 | } | ||
| 59 | |||
| 60 | slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width, | ||
| 61 | symbol->name); | ||
| 62 | width -= top_browser->sym_width; | ||
| 63 | slsmg_write_nstring(width >= syme->map->dso->long_name_len ? | ||
| 64 | syme->map->dso->long_name : | ||
| 65 | syme->map->dso->short_name, width); | ||
| 66 | |||
| 67 | if (current_entry) | ||
| 68 | top_browser->selection = syme; | ||
| 69 | } | ||
| 70 | |||
| 71 | static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) | ||
| 72 | { | ||
| 73 | struct perf_top *top = browser->b.priv; | ||
| 74 | u64 top_idx = browser->b.top_idx; | ||
| 75 | |||
| 76 | browser->root = RB_ROOT; | ||
| 77 | browser->b.top = NULL; | ||
| 78 | browser->sum_ksamples = perf_top__decay_samples(top, &browser->root); | ||
| 79 | /* | ||
| 80 | * No active symbols | ||
| 81 | */ | ||
| 82 | if (top->rb_entries == 0) | ||
| 83 | return; | ||
| 84 | |||
| 85 | perf_top__find_widths(top, &browser->root, &browser->dso_width, | ||
| 86 | &browser->dso_short_width, | ||
| 87 | &browser->sym_width); | ||
| 88 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) { | ||
| 89 | browser->dso_width = browser->dso_short_width; | ||
| 90 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) | ||
| 91 | browser->sym_width = browser->b.width - browser->dso_width - 29; | ||
| 92 | } | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Adjust the ui_browser indexes since the entries in the browser->root | ||
| 96 | * rb_tree may have changed, then seek it from start, so that we get a | ||
| 97 | * possible new top of the screen. | ||
| 98 | */ | ||
| 99 | browser->b.nr_entries = top->rb_entries; | ||
| 100 | |||
| 101 | if (top_idx >= browser->b.nr_entries) { | ||
| 102 | if (browser->b.height >= browser->b.nr_entries) | ||
| 103 | top_idx = browser->b.nr_entries - browser->b.height; | ||
| 104 | else | ||
| 105 | top_idx = 0; | ||
| 106 | } | ||
| 107 | |||
| 108 | if (browser->b.index >= top_idx + browser->b.height) | ||
| 109 | browser->b.index = top_idx + browser->b.index - browser->b.top_idx; | ||
| 110 | |||
| 111 | if (browser->b.index >= browser->b.nr_entries) | ||
| 112 | browser->b.index = browser->b.nr_entries - 1; | ||
| 113 | |||
| 114 | browser->b.top_idx = top_idx; | ||
| 115 | browser->b.seek(&browser->b, top_idx, SEEK_SET); | ||
| 116 | } | ||
| 117 | |||
| 118 | static void perf_top_browser__annotate(struct perf_top_browser *browser) | ||
| 119 | { | ||
| 120 | struct sym_entry *syme = browser->selection; | ||
| 121 | struct symbol *sym = sym_entry__symbol(syme); | ||
| 122 | struct annotation *notes = symbol__annotation(sym); | ||
| 123 | struct perf_top *top = browser->b.priv; | ||
| 124 | |||
| 125 | if (notes->src != NULL) | ||
| 126 | goto do_annotation; | ||
| 127 | |||
| 128 | pthread_mutex_lock(¬es->lock); | ||
| 129 | |||
| 130 | top->sym_filter_entry = NULL; | ||
| 131 | |||
| 132 | if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) { | ||
| 133 | pr_err("Not enough memory for annotating '%s' symbol!\n", | ||
| 134 | sym->name); | ||
| 135 | pthread_mutex_unlock(¬es->lock); | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | |||
| 139 | top->sym_filter_entry = syme; | ||
| 140 | |||
| 141 | pthread_mutex_unlock(¬es->lock); | ||
| 142 | do_annotation: | ||
| 143 | symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000); | ||
| 144 | } | ||
| 145 | |||
| 146 | static int perf_top_browser__run(struct perf_top_browser *browser) | ||
| 147 | { | ||
| 148 | int key; | ||
| 149 | char title[160]; | ||
| 150 | struct perf_top *top = browser->b.priv; | ||
| 151 | int delay_msecs = top->delay_secs * 1000; | ||
| 152 | int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; | ||
| 153 | |||
| 154 | perf_top_browser__update_rb_tree(browser); | ||
| 155 | perf_top__header_snprintf(top, title, sizeof(title)); | ||
| 156 | perf_top__reset_sample_counters(top); | ||
| 157 | |||
| 158 | if (ui_browser__show(&browser->b, title, | ||
| 159 | "ESC: exit, ENTER|->|a: Live Annotate") < 0) | ||
| 160 | return -1; | ||
| 161 | |||
| 162 | newtFormSetTimer(browser->b.form, delay_msecs); | ||
| 163 | ui_browser__add_exit_keys(&browser->b, exit_keys); | ||
| 164 | |||
| 165 | while (1) { | ||
| 166 | key = ui_browser__run(&browser->b); | ||
| 167 | |||
| 168 | switch (key) { | ||
| 169 | case -1: | ||
| 170 | /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ | ||
| 171 | perf_top_browser__update_rb_tree(browser); | ||
| 172 | perf_top__header_snprintf(top, title, sizeof(title)); | ||
| 173 | perf_top__reset_sample_counters(top); | ||
| 174 | ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT); | ||
| 175 | SLsmg_gotorc(0, 0); | ||
| 176 | slsmg_write_nstring(title, browser->b.width); | ||
| 177 | break; | ||
| 178 | case 'a': | ||
| 179 | case NEWT_KEY_RIGHT: | ||
| 180 | case NEWT_KEY_ENTER: | ||
| 181 | if (browser->selection) | ||
| 182 | perf_top_browser__annotate(browser); | ||
| 183 | break; | ||
| 184 | case NEWT_KEY_LEFT: | ||
| 185 | continue; | ||
| 186 | case NEWT_KEY_ESCAPE: | ||
| 187 | if (!ui__dialog_yesno("Do you really want to exit?")) | ||
| 188 | continue; | ||
| 189 | /* Fall thru */ | ||
| 190 | default: | ||
| 191 | goto out; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | out: | ||
| 195 | ui_browser__hide(&browser->b); | ||
| 196 | return key; | ||
| 197 | } | ||
| 198 | |||
| 199 | int perf_top__tui_browser(struct perf_top *top) | ||
| 200 | { | ||
| 201 | struct perf_top_browser browser = { | ||
| 202 | .b = { | ||
| 203 | .entries = &browser.root, | ||
| 204 | .refresh = ui_browser__rb_tree_refresh, | ||
| 205 | .seek = ui_browser__rb_tree_seek, | ||
| 206 | .write = perf_top_browser__write, | ||
| 207 | .priv = top, | ||
| 208 | }, | ||
| 209 | }; | ||
| 210 | |||
| 211 | ui_helpline__push("Press <- or ESC to exit"); | ||
| 212 | return perf_top_browser__run(&browser); | ||
| 213 | } | ||
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c index 8d79daa4458..f36d2ff509e 100644 --- a/tools/perf/util/ui/helpline.c +++ b/tools/perf/util/ui/helpline.c | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include "../debug.h" | 6 | #include "../debug.h" |
| 7 | #include "helpline.h" | 7 | #include "helpline.h" |
| 8 | #include "ui.h" | ||
| 8 | 9 | ||
| 9 | void ui_helpline__pop(void) | 10 | void ui_helpline__pop(void) |
| 10 | { | 11 | { |
| @@ -55,7 +56,8 @@ int ui_helpline__show_help(const char *format, va_list ap) | |||
| 55 | int ret; | 56 | int ret; |
| 56 | static int backlog; | 57 | static int backlog; |
| 57 | 58 | ||
| 58 | ret = vsnprintf(ui_helpline__last_msg + backlog, | 59 | pthread_mutex_lock(&ui__lock); |
| 60 | ret = vsnprintf(ui_helpline__last_msg + backlog, | ||
| 59 | sizeof(ui_helpline__last_msg) - backlog, format, ap); | 61 | sizeof(ui_helpline__last_msg) - backlog, format, ap); |
| 60 | backlog += ret; | 62 | backlog += ret; |
| 61 | 63 | ||
| @@ -64,6 +66,7 @@ int ui_helpline__show_help(const char *format, va_list ap) | |||
| 64 | newtRefresh(); | 66 | newtRefresh(); |
| 65 | backlog = 0; | 67 | backlog = 0; |
| 66 | } | 68 | } |
| 69 | pthread_mutex_unlock(&ui__lock); | ||
| 67 | 70 | ||
| 68 | return ret; | 71 | return ret; |
| 69 | } | 72 | } |
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h index 5623da8e808..2b63e1c9b18 100644 --- a/tools/perf/util/ui/libslang.h +++ b/tools/perf/util/ui/libslang.h | |||
| @@ -13,11 +13,11 @@ | |||
| 13 | 13 | ||
| 14 | #if SLANG_VERSION < 20104 | 14 | #if SLANG_VERSION < 20104 |
| 15 | #define slsmg_printf(msg, args...) \ | 15 | #define slsmg_printf(msg, args...) \ |
| 16 | SLsmg_printf((char *)msg, ##args) | 16 | SLsmg_printf((char *)(msg), ##args) |
| 17 | #define slsmg_write_nstring(msg, len) \ | 17 | #define slsmg_write_nstring(msg, len) \ |
| 18 | SLsmg_write_nstring((char *)msg, len) | 18 | SLsmg_write_nstring((char *)(msg), len) |
| 19 | #define sltt_set_color(obj, name, fg, bg) \ | 19 | #define sltt_set_color(obj, name, fg, bg) \ |
| 20 | SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg) | 20 | SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg)) |
| 21 | #else | 21 | #else |
| 22 | #define slsmg_printf SLsmg_printf | 22 | #define slsmg_printf SLsmg_printf |
| 23 | #define slsmg_write_nstring SLsmg_write_nstring | 23 | #define slsmg_write_nstring SLsmg_write_nstring |
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c index 662085032eb..ee46d671db5 100644 --- a/tools/perf/util/ui/setup.c +++ b/tools/perf/util/ui/setup.c | |||
| @@ -6,6 +6,9 @@ | |||
| 6 | #include "../debug.h" | 6 | #include "../debug.h" |
| 7 | #include "browser.h" | 7 | #include "browser.h" |
| 8 | #include "helpline.h" | 8 | #include "helpline.h" |
| 9 | #include "ui.h" | ||
| 10 | |||
| 11 | pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; | ||
| 9 | 12 | ||
| 10 | static void newt_suspend(void *d __used) | 13 | static void newt_suspend(void *d __used) |
| 11 | { | 14 | { |
| @@ -14,11 +17,12 @@ static void newt_suspend(void *d __used) | |||
| 14 | newtResume(); | 17 | newtResume(); |
| 15 | } | 18 | } |
| 16 | 19 | ||
| 17 | void setup_browser(void) | 20 | void setup_browser(bool fallback_to_pager) |
| 18 | { | 21 | { |
| 19 | if (!isatty(1) || !use_browser || dump_trace) { | 22 | if (!isatty(1) || !use_browser || dump_trace) { |
| 20 | use_browser = 0; | 23 | use_browser = 0; |
| 21 | setup_pager(); | 24 | if (fallback_to_pager) |
| 25 | setup_pager(); | ||
| 22 | return; | 26 | return; |
| 23 | } | 27 | } |
| 24 | 28 | ||
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h new file mode 100644 index 00000000000..d264e059c82 --- /dev/null +++ b/tools/perf/util/ui/ui.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef _PERF_UI_H_ | ||
| 2 | #define _PERF_UI_H_ 1 | ||
| 3 | |||
| 4 | #include <pthread.h> | ||
| 5 | |||
| 6 | extern pthread_mutex_t ui__lock; | ||
| 7 | |||
| 8 | #endif /* _PERF_UI_H_ */ | ||
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c index 7b5a8926624..fdf1fc8f08b 100644 --- a/tools/perf/util/ui/util.c +++ b/tools/perf/util/ui/util.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "../debug.h" | 9 | #include "../debug.h" |
| 10 | #include "browser.h" | 10 | #include "browser.h" |
| 11 | #include "helpline.h" | 11 | #include "helpline.h" |
| 12 | #include "ui.h" | ||
| 12 | #include "util.h" | 13 | #include "util.h" |
| 13 | 14 | ||
| 14 | static void newt_form__set_exit_keys(newtComponent self) | 15 | static void newt_form__set_exit_keys(newtComponent self) |
| @@ -118,10 +119,12 @@ void ui__warning(const char *format, ...) | |||
| 118 | va_list args; | 119 | va_list args; |
| 119 | 120 | ||
| 120 | va_start(args, format); | 121 | va_start(args, format); |
| 121 | if (use_browser > 0) | 122 | if (use_browser > 0) { |
| 123 | pthread_mutex_lock(&ui__lock); | ||
| 122 | newtWinMessagev((char *)warning_str, (char *)ok, | 124 | newtWinMessagev((char *)warning_str, (char *)ok, |
| 123 | (char *)format, args); | 125 | (char *)format, args); |
| 124 | else | 126 | pthread_mutex_unlock(&ui__lock); |
| 127 | } else | ||
| 125 | vfprintf(stderr, format, args); | 128 | vfprintf(stderr, format, args); |
| 126 | va_end(args); | 129 | va_end(args); |
| 127 | } | 130 | } |
