diff options
Diffstat (limited to 'tools/perf/util/newt.c')
-rw-r--r-- | tools/perf/util/newt.c | 501 |
1 files changed, 370 insertions, 131 deletions
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index e283a6e6b6e0..ba6acd04c082 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <stdio.h> | 2 | #include <stdio.h> |
3 | #undef _GNU_SOURCE | 3 | #undef _GNU_SOURCE |
4 | 4 | ||
5 | #include <slang.h> | ||
5 | #include <stdlib.h> | 6 | #include <stdlib.h> |
6 | #include <newt.h> | 7 | #include <newt.h> |
7 | #include <sys/ttydefaults.h> | 8 | #include <sys/ttydefaults.h> |
@@ -57,6 +58,43 @@ void ui_progress__delete(struct ui_progress *self) | |||
57 | free(self); | 58 | free(self); |
58 | } | 59 | } |
59 | 60 | ||
61 | static void ui_helpline__pop(void) | ||
62 | { | ||
63 | newtPopHelpLine(); | ||
64 | } | ||
65 | |||
66 | static void ui_helpline__push(const char *msg) | ||
67 | { | ||
68 | newtPushHelpLine(msg); | ||
69 | } | ||
70 | |||
71 | static void ui_helpline__vpush(const char *fmt, va_list ap) | ||
72 | { | ||
73 | char *s; | ||
74 | |||
75 | if (vasprintf(&s, fmt, ap) < 0) | ||
76 | vfprintf(stderr, fmt, ap); | ||
77 | else { | ||
78 | ui_helpline__push(s); | ||
79 | free(s); | ||
80 | } | ||
81 | } | ||
82 | |||
83 | static void ui_helpline__fpush(const char *fmt, ...) | ||
84 | { | ||
85 | va_list ap; | ||
86 | |||
87 | va_start(ap, fmt); | ||
88 | ui_helpline__vpush(fmt, ap); | ||
89 | va_end(ap); | ||
90 | } | ||
91 | |||
92 | static void ui_helpline__puts(const char *msg) | ||
93 | { | ||
94 | ui_helpline__pop(); | ||
95 | ui_helpline__push(msg); | ||
96 | } | ||
97 | |||
60 | static char browser__last_msg[1024]; | 98 | static char browser__last_msg[1024]; |
61 | 99 | ||
62 | int browser__show_help(const char *format, va_list ap) | 100 | int browser__show_help(const char *format, va_list ap) |
@@ -69,8 +107,7 @@ int browser__show_help(const char *format, va_list ap) | |||
69 | backlog += ret; | 107 | backlog += ret; |
70 | 108 | ||
71 | if (browser__last_msg[backlog - 1] == '\n') { | 109 | if (browser__last_msg[backlog - 1] == '\n') { |
72 | newtPopHelpLine(); | 110 | ui_helpline__puts(browser__last_msg); |
73 | newtPushHelpLine(browser__last_msg); | ||
74 | newtRefresh(); | 111 | newtRefresh(); |
75 | backlog = 0; | 112 | backlog = 0; |
76 | } | 113 | } |
@@ -135,6 +172,254 @@ static bool dialog_yesno(const char *msg) | |||
135 | return newtWinChoice(NULL, yes, no, (char *)msg) == 1; | 172 | return newtWinChoice(NULL, yes, no, (char *)msg) == 1; |
136 | } | 173 | } |
137 | 174 | ||
175 | #define HE_COLORSET_TOP 50 | ||
176 | #define HE_COLORSET_MEDIUM 51 | ||
177 | #define HE_COLORSET_NORMAL 52 | ||
178 | #define HE_COLORSET_SELECTED 53 | ||
179 | #define HE_COLORSET_CODE 54 | ||
180 | |||
181 | static int ui_browser__percent_color(double percent, bool current) | ||
182 | { | ||
183 | if (current) | ||
184 | return HE_COLORSET_SELECTED; | ||
185 | if (percent >= MIN_RED) | ||
186 | return HE_COLORSET_TOP; | ||
187 | if (percent >= MIN_GREEN) | ||
188 | return HE_COLORSET_MEDIUM; | ||
189 | return HE_COLORSET_NORMAL; | ||
190 | } | ||
191 | |||
192 | struct ui_browser { | ||
193 | newtComponent form, sb; | ||
194 | u64 index, first_visible_entry_idx; | ||
195 | void *first_visible_entry, *entries; | ||
196 | u16 top, left, width, height; | ||
197 | void *priv; | ||
198 | u32 nr_entries; | ||
199 | }; | ||
200 | |||
201 | static void ui_browser__refresh_dimensions(struct ui_browser *self) | ||
202 | { | ||
203 | int cols, rows; | ||
204 | newtGetScreenSize(&cols, &rows); | ||
205 | |||
206 | if (self->width > cols - 4) | ||
207 | self->width = cols - 4; | ||
208 | self->height = rows - 5; | ||
209 | if (self->height > self->nr_entries) | ||
210 | self->height = self->nr_entries; | ||
211 | self->top = (rows - self->height) / 2; | ||
212 | self->left = (cols - self->width) / 2; | ||
213 | } | ||
214 | |||
215 | static void ui_browser__reset_index(struct ui_browser *self) | ||
216 | { | ||
217 | self->index = self->first_visible_entry_idx = 0; | ||
218 | self->first_visible_entry = NULL; | ||
219 | } | ||
220 | |||
221 | static int objdump_line__show(struct objdump_line *self, struct list_head *head, | ||
222 | int width, struct hist_entry *he, int len, | ||
223 | bool current_entry) | ||
224 | { | ||
225 | if (self->offset != -1) { | ||
226 | struct symbol *sym = he->ms.sym; | ||
227 | unsigned int hits = 0; | ||
228 | double percent = 0.0; | ||
229 | int color; | ||
230 | struct sym_priv *priv = symbol__priv(sym); | ||
231 | struct sym_ext *sym_ext = priv->ext; | ||
232 | struct sym_hist *h = priv->hist; | ||
233 | s64 offset = self->offset; | ||
234 | struct objdump_line *next = objdump__get_next_ip_line(head, self); | ||
235 | |||
236 | while (offset < (s64)len && | ||
237 | (next == NULL || offset < next->offset)) { | ||
238 | if (sym_ext) { | ||
239 | percent += sym_ext[offset].percent; | ||
240 | } else | ||
241 | hits += h->ip[offset]; | ||
242 | |||
243 | ++offset; | ||
244 | } | ||
245 | |||
246 | if (sym_ext == NULL && h->sum) | ||
247 | percent = 100.0 * hits / h->sum; | ||
248 | |||
249 | color = ui_browser__percent_color(percent, current_entry); | ||
250 | SLsmg_set_color(color); | ||
251 | SLsmg_printf(" %7.2f ", percent); | ||
252 | if (!current_entry) | ||
253 | SLsmg_set_color(HE_COLORSET_CODE); | ||
254 | } else { | ||
255 | int color = ui_browser__percent_color(0, current_entry); | ||
256 | SLsmg_set_color(color); | ||
257 | SLsmg_write_nstring(" ", 9); | ||
258 | } | ||
259 | |||
260 | SLsmg_write_char(':'); | ||
261 | SLsmg_write_nstring(" ", 8); | ||
262 | if (!*self->line) | ||
263 | SLsmg_write_nstring(" ", width - 18); | ||
264 | else | ||
265 | SLsmg_write_nstring(self->line, width - 18); | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int ui_browser__refresh_entries(struct ui_browser *self) | ||
271 | { | ||
272 | struct objdump_line *pos; | ||
273 | struct list_head *head = self->entries; | ||
274 | struct hist_entry *he = self->priv; | ||
275 | int row = 0; | ||
276 | int len = he->ms.sym->end - he->ms.sym->start; | ||
277 | |||
278 | if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries) | ||
279 | self->first_visible_entry = head->next; | ||
280 | |||
281 | pos = list_entry(self->first_visible_entry, struct objdump_line, node); | ||
282 | |||
283 | list_for_each_entry_from(pos, head, node) { | ||
284 | bool current_entry = (self->first_visible_entry_idx + row) == self->index; | ||
285 | SLsmg_gotorc(self->top + row, self->left); | ||
286 | objdump_line__show(pos, head, self->width, | ||
287 | he, len, current_entry); | ||
288 | if (++row == self->height) | ||
289 | break; | ||
290 | } | ||
291 | |||
292 | SLsmg_set_color(HE_COLORSET_NORMAL); | ||
293 | SLsmg_fill_region(self->top + row, self->left, | ||
294 | self->height - row, self->width, ' '); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int ui_browser__run(struct ui_browser *self, const char *title, | ||
300 | struct newtExitStruct *es) | ||
301 | { | ||
302 | if (self->form) { | ||
303 | newtFormDestroy(self->form); | ||
304 | newtPopWindow(); | ||
305 | } | ||
306 | |||
307 | ui_browser__refresh_dimensions(self); | ||
308 | newtCenteredWindow(self->width + 2, self->height, title); | ||
309 | self->form = newt_form__new(); | ||
310 | if (self->form == NULL) | ||
311 | return -1; | ||
312 | |||
313 | self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height, | ||
314 | HE_COLORSET_NORMAL, | ||
315 | HE_COLORSET_SELECTED); | ||
316 | if (self->sb == NULL) | ||
317 | return -1; | ||
318 | |||
319 | newtFormAddHotKey(self->form, NEWT_KEY_UP); | ||
320 | newtFormAddHotKey(self->form, NEWT_KEY_DOWN); | ||
321 | newtFormAddHotKey(self->form, NEWT_KEY_PGUP); | ||
322 | newtFormAddHotKey(self->form, NEWT_KEY_PGDN); | ||
323 | newtFormAddHotKey(self->form, NEWT_KEY_HOME); | ||
324 | newtFormAddHotKey(self->form, NEWT_KEY_END); | ||
325 | |||
326 | if (ui_browser__refresh_entries(self) < 0) | ||
327 | return -1; | ||
328 | newtFormAddComponent(self->form, self->sb); | ||
329 | |||
330 | while (1) { | ||
331 | unsigned int offset; | ||
332 | |||
333 | newtFormRun(self->form, es); | ||
334 | |||
335 | if (es->reason != NEWT_EXIT_HOTKEY) | ||
336 | break; | ||
337 | switch (es->u.key) { | ||
338 | case NEWT_KEY_DOWN: | ||
339 | if (self->index == self->nr_entries - 1) | ||
340 | break; | ||
341 | ++self->index; | ||
342 | if (self->index == self->first_visible_entry_idx + self->height) { | ||
343 | struct list_head *pos = self->first_visible_entry; | ||
344 | ++self->first_visible_entry_idx; | ||
345 | self->first_visible_entry = pos->next; | ||
346 | } | ||
347 | break; | ||
348 | case NEWT_KEY_UP: | ||
349 | if (self->index == 0) | ||
350 | break; | ||
351 | --self->index; | ||
352 | if (self->index < self->first_visible_entry_idx) { | ||
353 | struct list_head *pos = self->first_visible_entry; | ||
354 | --self->first_visible_entry_idx; | ||
355 | self->first_visible_entry = pos->prev; | ||
356 | } | ||
357 | break; | ||
358 | case NEWT_KEY_PGDN: | ||
359 | if (self->first_visible_entry_idx + self->height > self->nr_entries - 1) | ||
360 | break; | ||
361 | |||
362 | offset = self->height; | ||
363 | if (self->index + offset > self->nr_entries - 1) | ||
364 | offset = self->nr_entries - 1 - self->index; | ||
365 | self->index += offset; | ||
366 | self->first_visible_entry_idx += offset; | ||
367 | |||
368 | while (offset--) { | ||
369 | struct list_head *pos = self->first_visible_entry; | ||
370 | self->first_visible_entry = pos->next; | ||
371 | } | ||
372 | |||
373 | break; | ||
374 | case NEWT_KEY_PGUP: | ||
375 | if (self->first_visible_entry_idx == 0) | ||
376 | break; | ||
377 | |||
378 | if (self->first_visible_entry_idx < self->height) | ||
379 | offset = self->first_visible_entry_idx; | ||
380 | else | ||
381 | offset = self->height; | ||
382 | |||
383 | self->index -= offset; | ||
384 | self->first_visible_entry_idx -= offset; | ||
385 | |||
386 | while (offset--) { | ||
387 | struct list_head *pos = self->first_visible_entry; | ||
388 | self->first_visible_entry = pos->prev; | ||
389 | } | ||
390 | break; | ||
391 | case NEWT_KEY_HOME: | ||
392 | ui_browser__reset_index(self); | ||
393 | break; | ||
394 | case NEWT_KEY_END: { | ||
395 | struct list_head *head = self->entries; | ||
396 | offset = self->height - 1; | ||
397 | |||
398 | if (offset > self->nr_entries) | ||
399 | offset = self->nr_entries; | ||
400 | |||
401 | self->index = self->first_visible_entry_idx = self->nr_entries - 1 - offset; | ||
402 | self->first_visible_entry = head->prev; | ||
403 | while (offset-- != 0) { | ||
404 | struct list_head *pos = self->first_visible_entry; | ||
405 | self->first_visible_entry = pos->prev; | ||
406 | } | ||
407 | } | ||
408 | break; | ||
409 | case NEWT_KEY_ESCAPE: | ||
410 | case CTRL('c'): | ||
411 | case 'Q': | ||
412 | case 'q': | ||
413 | return 0; | ||
414 | default: | ||
415 | continue; | ||
416 | } | ||
417 | if (ui_browser__refresh_entries(self) < 0) | ||
418 | return -1; | ||
419 | } | ||
420 | return 0; | ||
421 | } | ||
422 | |||
138 | /* | 423 | /* |
139 | * When debugging newt problems it was useful to be able to "unroll" | 424 | * When debugging newt problems it was useful to be able to "unroll" |
140 | * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate | 425 | * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate |
@@ -317,62 +602,40 @@ static size_t hist_entry__append_browser(struct hist_entry *self, | |||
317 | return ret; | 602 | return ret; |
318 | } | 603 | } |
319 | 604 | ||
320 | static void map_symbol__annotate_browser(const struct map_symbol *self, | 605 | static void hist_entry__annotate_browser(struct hist_entry *self) |
321 | const char *input_name) | ||
322 | { | 606 | { |
323 | FILE *fp; | 607 | struct ui_browser browser; |
324 | int cols, rows; | ||
325 | newtComponent form, tree; | ||
326 | struct newtExitStruct es; | 608 | struct newtExitStruct es; |
327 | char *str; | 609 | struct objdump_line *pos, *n; |
328 | size_t line_len, max_line_len = 0; | 610 | LIST_HEAD(head); |
329 | size_t max_usable_width; | ||
330 | char *line = NULL; | ||
331 | 611 | ||
332 | if (self->sym == NULL) | 612 | if (self->ms.sym == NULL) |
333 | return; | 613 | return; |
334 | 614 | ||
335 | if (asprintf(&str, "perf annotate -i \"%s\" -d \"%s\" %s 2>&1 | expand", | 615 | if (hist_entry__annotate(self, &head) < 0) |
336 | input_name, self->map->dso->name, self->sym->name) < 0) | ||
337 | return; | 616 | return; |
338 | 617 | ||
339 | fp = popen(str, "r"); | 618 | ui_helpline__push("Press ESC to exit"); |
340 | if (fp == NULL) | ||
341 | goto out_free_str; | ||
342 | |||
343 | newtPushHelpLine("Press ESC to exit"); | ||
344 | newtGetScreenSize(&cols, &rows); | ||
345 | tree = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL); | ||
346 | |||
347 | while (!feof(fp)) { | ||
348 | if (getline(&line, &line_len, fp) < 0 || !line_len) | ||
349 | break; | ||
350 | while (line_len != 0 && isspace(line[line_len - 1])) | ||
351 | line[--line_len] = '\0'; | ||
352 | 619 | ||
353 | if (line_len > max_line_len) | 620 | memset(&browser, 0, sizeof(browser)); |
354 | max_line_len = line_len; | 621 | browser.entries = &head; |
355 | newtListboxAppendEntry(tree, line, NULL); | 622 | browser.priv = self; |
623 | list_for_each_entry(pos, &head, node) { | ||
624 | size_t line_len = strlen(pos->line); | ||
625 | if (browser.width < line_len) | ||
626 | browser.width = line_len; | ||
627 | ++browser.nr_entries; | ||
356 | } | 628 | } |
357 | fclose(fp); | ||
358 | free(line); | ||
359 | 629 | ||
360 | max_usable_width = cols - 22; | 630 | browser.width += 18; /* Percentage */ |
361 | if (max_line_len > max_usable_width) | 631 | ui_browser__run(&browser, self->ms.sym->name, &es); |
362 | max_line_len = max_usable_width; | 632 | newtFormDestroy(browser.form); |
363 | |||
364 | newtListboxSetWidth(tree, max_line_len); | ||
365 | |||
366 | newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name); | ||
367 | form = newt_form__new(); | ||
368 | newtFormAddComponent(form, tree); | ||
369 | |||
370 | newtFormRun(form, &es); | ||
371 | newtFormDestroy(form); | ||
372 | newtPopWindow(); | 633 | newtPopWindow(); |
373 | newtPopHelpLine(); | 634 | list_for_each_entry_safe(pos, n, &head, node) { |
374 | out_free_str: | 635 | list_del(&pos->node); |
375 | free(str); | 636 | objdump_line__free(pos); |
637 | } | ||
638 | ui_helpline__pop(); | ||
376 | } | 639 | } |
377 | 640 | ||
378 | static const void *newt__symbol_tree_get_current(newtComponent self) | 641 | static const void *newt__symbol_tree_get_current(newtComponent self) |
@@ -410,8 +673,8 @@ static void hist_browser__delete(struct hist_browser *self) | |||
410 | free(self); | 673 | free(self); |
411 | } | 674 | } |
412 | 675 | ||
413 | static int hist_browser__populate(struct hist_browser *self, struct rb_root *hists, | 676 | static int hist_browser__populate(struct hist_browser *self, struct hists *hists, |
414 | u64 nr_hists, u64 session_total, const char *title) | 677 | const char *title) |
415 | { | 678 | { |
416 | int max_len = 0, idx, cols, rows; | 679 | int max_len = 0, idx, cols, rows; |
417 | struct ui_progress *progress; | 680 | struct ui_progress *progress; |
@@ -426,7 +689,7 @@ static int hist_browser__populate(struct hist_browser *self, struct rb_root *his | |||
426 | } | 689 | } |
427 | 690 | ||
428 | snprintf(str, sizeof(str), "Samples: %Ld ", | 691 | snprintf(str, sizeof(str), "Samples: %Ld ", |
429 | session_total); | 692 | hists->stats.total); |
430 | newtDrawRootText(0, 0, str); | 693 | newtDrawRootText(0, 0, str); |
431 | 694 | ||
432 | newtGetScreenSize(NULL, &rows); | 695 | newtGetScreenSize(NULL, &rows); |
@@ -442,24 +705,25 @@ static int hist_browser__populate(struct hist_browser *self, struct rb_root *his | |||
442 | newtComponentAddCallback(self->tree, hist_browser__selection, | 705 | newtComponentAddCallback(self->tree, hist_browser__selection, |
443 | &self->selection); | 706 | &self->selection); |
444 | 707 | ||
445 | progress = ui_progress__new("Adding entries to the browser...", nr_hists); | 708 | progress = ui_progress__new("Adding entries to the browser...", |
709 | hists->nr_entries); | ||
446 | if (progress == NULL) | 710 | if (progress == NULL) |
447 | return -1; | 711 | return -1; |
448 | 712 | ||
449 | idx = 0; | 713 | idx = 0; |
450 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { | 714 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
451 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 715 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
452 | int len; | 716 | int len; |
453 | 717 | ||
454 | if (h->filtered) | 718 | if (h->filtered) |
455 | continue; | 719 | continue; |
456 | 720 | ||
457 | len = hist_entry__append_browser(h, self->tree, session_total); | 721 | len = hist_entry__append_browser(h, self->tree, hists->stats.total); |
458 | if (len > max_len) | 722 | if (len > max_len) |
459 | max_len = len; | 723 | max_len = len; |
460 | if (symbol_conf.use_callchain) | 724 | if (symbol_conf.use_callchain) |
461 | hist_entry__append_callchain_browser(h, self->tree, | 725 | hist_entry__append_callchain_browser(h, self->tree, |
462 | session_total, idx++); | 726 | hists->stats.total, idx++); |
463 | ++curr_hist; | 727 | ++curr_hist; |
464 | if (curr_hist % 5) | 728 | if (curr_hist % 5) |
465 | ui_progress__update(progress, curr_hist); | 729 | ui_progress__update(progress, curr_hist); |
@@ -490,58 +754,7 @@ static int hist_browser__populate(struct hist_browser *self, struct rb_root *his | |||
490 | return 0; | 754 | return 0; |
491 | } | 755 | } |
492 | 756 | ||
493 | enum hist_filter { | 757 | static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self) |
494 | HIST_FILTER__DSO, | ||
495 | HIST_FILTER__THREAD, | ||
496 | }; | ||
497 | |||
498 | static u64 hists__filter_by_dso(struct rb_root *hists, const struct dso *dso, | ||
499 | u64 *session_total) | ||
500 | { | ||
501 | struct rb_node *nd; | ||
502 | u64 nr_hists = 0; | ||
503 | |||
504 | *session_total = 0; | ||
505 | |||
506 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { | ||
507 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
508 | |||
509 | if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) { | ||
510 | h->filtered |= (1 << HIST_FILTER__DSO); | ||
511 | continue; | ||
512 | } | ||
513 | h->filtered &= ~(1 << HIST_FILTER__DSO); | ||
514 | ++nr_hists; | ||
515 | *session_total += h->count; | ||
516 | } | ||
517 | |||
518 | return nr_hists; | ||
519 | } | ||
520 | |||
521 | static u64 hists__filter_by_thread(struct rb_root *hists, const struct thread *thread, | ||
522 | u64 *session_total) | ||
523 | { | ||
524 | struct rb_node *nd; | ||
525 | u64 nr_hists = 0; | ||
526 | |||
527 | *session_total = 0; | ||
528 | |||
529 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { | ||
530 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
531 | |||
532 | if (thread != NULL && h->thread != thread) { | ||
533 | h->filtered |= (1 << HIST_FILTER__THREAD); | ||
534 | continue; | ||
535 | } | ||
536 | h->filtered &= ~(1 << HIST_FILTER__THREAD); | ||
537 | ++nr_hists; | ||
538 | *session_total += h->count; | ||
539 | } | ||
540 | |||
541 | return nr_hists; | ||
542 | } | ||
543 | |||
544 | static struct thread *hist_browser__selected_thread(struct hist_browser *self) | ||
545 | { | 758 | { |
546 | int *indexes; | 759 | int *indexes; |
547 | 760 | ||
@@ -557,7 +770,13 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self) | |||
557 | } | 770 | } |
558 | return NULL; | 771 | return NULL; |
559 | out: | 772 | out: |
560 | return *(struct thread **)(self->selection + 1); | 773 | return container_of(self->selection, struct hist_entry, ms); |
774 | } | ||
775 | |||
776 | static struct thread *hist_browser__selected_thread(struct hist_browser *self) | ||
777 | { | ||
778 | struct hist_entry *he = hist_browser__selected_entry(self); | ||
779 | return he ? he->thread : NULL; | ||
561 | } | 780 | } |
562 | 781 | ||
563 | static int hist_browser__title(char *bf, size_t size, const char *input_name, | 782 | static int hist_browser__title(char *bf, size_t size, const char *input_name, |
@@ -577,9 +796,7 @@ static int hist_browser__title(char *bf, size_t size, const char *input_name, | |||
577 | return printed ?: snprintf(bf, size, "Report: %s", input_name); | 796 | return printed ?: snprintf(bf, size, "Report: %s", input_name); |
578 | } | 797 | } |
579 | 798 | ||
580 | int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, | 799 | int hists__browse(struct hists *self, const char *helpline, const char *input_name) |
581 | u64 session_total, const char *helpline, | ||
582 | const char *input_name) | ||
583 | { | 800 | { |
584 | struct hist_browser *browser = hist_browser__new(); | 801 | struct hist_browser *browser = hist_browser__new(); |
585 | const struct thread *thread_filter = NULL; | 802 | const struct thread *thread_filter = NULL; |
@@ -591,11 +808,11 @@ int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, | |||
591 | if (browser == NULL) | 808 | if (browser == NULL) |
592 | return -1; | 809 | return -1; |
593 | 810 | ||
594 | newtPushHelpLine(helpline); | 811 | ui_helpline__push(helpline); |
595 | 812 | ||
596 | hist_browser__title(msg, sizeof(msg), input_name, | 813 | hist_browser__title(msg, sizeof(msg), input_name, |
597 | dso_filter, thread_filter); | 814 | dso_filter, thread_filter); |
598 | if (hist_browser__populate(browser, hists, nr_hists, session_total, msg) < 0) | 815 | if (hist_browser__populate(browser, self, msg) < 0) |
599 | goto out; | 816 | goto out; |
600 | 817 | ||
601 | while (1) { | 818 | while (1) { |
@@ -653,46 +870,48 @@ int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, | |||
653 | continue; | 870 | continue; |
654 | do_annotate: | 871 | do_annotate: |
655 | if (choice == annotate) { | 872 | if (choice == annotate) { |
873 | struct hist_entry *he; | ||
874 | |||
656 | if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { | 875 | if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { |
657 | newtPopHelpLine(); | 876 | ui_helpline__puts("No vmlinux file found, can't " |
658 | newtPushHelpLine("No vmlinux file found, can't " | ||
659 | "annotate with just a " | 877 | "annotate with just a " |
660 | "kallsyms file"); | 878 | "kallsyms file"); |
661 | continue; | 879 | continue; |
662 | } | 880 | } |
663 | map_symbol__annotate_browser(browser->selection, input_name); | 881 | |
882 | he = hist_browser__selected_entry(browser); | ||
883 | if (he == NULL) | ||
884 | continue; | ||
885 | |||
886 | hist_entry__annotate_browser(he); | ||
664 | } else if (choice == zoom_dso) { | 887 | } else if (choice == zoom_dso) { |
665 | if (dso_filter) { | 888 | if (dso_filter) { |
666 | newtPopHelpLine(); | 889 | ui_helpline__pop(); |
667 | dso_filter = NULL; | 890 | dso_filter = NULL; |
668 | } else { | 891 | } else { |
669 | snprintf(msg, sizeof(msg), | 892 | ui_helpline__fpush("To zoom out press -> + \"Zoom out of %s DSO\"", |
670 | "To zoom out press -> + \"Zoom out of %s DSO\"", | 893 | dso->kernel ? "the Kernel" : dso->short_name); |
671 | dso->kernel ? "the Kernel" : dso->short_name); | ||
672 | newtPushHelpLine(msg); | ||
673 | dso_filter = dso; | 894 | dso_filter = dso; |
674 | } | 895 | } |
675 | nr_hists = hists__filter_by_dso(hists, dso_filter, &session_total); | 896 | hists__filter_by_dso(self, dso_filter); |
676 | hist_browser__title(msg, sizeof(msg), input_name, | 897 | hist_browser__title(msg, sizeof(msg), input_name, |
677 | dso_filter, thread_filter); | 898 | dso_filter, thread_filter); |
678 | if (hist_browser__populate(browser, hists, nr_hists, session_total, msg) < 0) | 899 | if (hist_browser__populate(browser, self, msg) < 0) |
679 | goto out; | 900 | goto out; |
680 | } else if (choice == zoom_thread) { | 901 | } else if (choice == zoom_thread) { |
681 | if (thread_filter) { | 902 | if (thread_filter) { |
682 | newtPopHelpLine(); | 903 | ui_helpline__pop(); |
683 | thread_filter = NULL; | 904 | thread_filter = NULL; |
684 | } else { | 905 | } else { |
685 | snprintf(msg, sizeof(msg), | 906 | ui_helpline__fpush("To zoom out press -> + \"Zoom out of %s(%d) thread\"", |
686 | "To zoom out press -> + \"Zoom out of %s(%d) thread\"", | 907 | thread->comm_set ? thread->comm : "", |
687 | (thread->comm_set ? thread->comm : ""), | 908 | thread->pid); |
688 | thread->pid); | ||
689 | newtPushHelpLine(msg); | ||
690 | thread_filter = thread; | 909 | thread_filter = thread; |
691 | } | 910 | } |
692 | nr_hists = hists__filter_by_thread(hists, thread_filter, &session_total); | 911 | hists__filter_by_thread(self, thread_filter); |
693 | hist_browser__title(msg, sizeof(msg), input_name, | 912 | hist_browser__title(msg, sizeof(msg), input_name, |
694 | dso_filter, thread_filter); | 913 | dso_filter, thread_filter); |
695 | if (hist_browser__populate(browser, hists, nr_hists, session_total, msg) < 0) | 914 | if (hist_browser__populate(browser, self, msg) < 0) |
696 | goto out; | 915 | goto out; |
697 | } | 916 | } |
698 | } | 917 | } |
@@ -702,15 +921,35 @@ out: | |||
702 | return err; | 921 | return err; |
703 | } | 922 | } |
704 | 923 | ||
924 | static struct newtPercentTreeColors { | ||
925 | const char *topColorFg, *topColorBg; | ||
926 | const char *mediumColorFg, *mediumColorBg; | ||
927 | const char *normalColorFg, *normalColorBg; | ||
928 | const char *selColorFg, *selColorBg; | ||
929 | const char *codeColorFg, *codeColorBg; | ||
930 | } defaultPercentTreeColors = { | ||
931 | "red", "lightgray", | ||
932 | "green", "lightgray", | ||
933 | "black", "lightgray", | ||
934 | "lightgray", "magenta", | ||
935 | "blue", "lightgray", | ||
936 | }; | ||
937 | |||
705 | void setup_browser(void) | 938 | void setup_browser(void) |
706 | { | 939 | { |
940 | struct newtPercentTreeColors *c = &defaultPercentTreeColors; | ||
707 | if (!isatty(1)) | 941 | if (!isatty(1)) |
708 | return; | 942 | return; |
709 | 943 | ||
710 | use_browser = true; | 944 | use_browser = true; |
711 | newtInit(); | 945 | newtInit(); |
712 | newtCls(); | 946 | newtCls(); |
713 | newtPushHelpLine(" "); | 947 | ui_helpline__puts(" "); |
948 | SLtt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); | ||
949 | SLtt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); | ||
950 | SLtt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg); | ||
951 | SLtt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg); | ||
952 | SLtt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg); | ||
714 | } | 953 | } |
715 | 954 | ||
716 | void exit_browser(bool wait_for_ok) | 955 | void exit_browser(bool wait_for_ok) |