blob: c65838c99354db9c8b853829ea7d2aaf475065ef [file] [log] [blame]
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001#define _GNU_SOURCE
2#include <stdio.h>
3#undef _GNU_SOURCE
Arnaldo Carvalho de Melo32ec6ac2010-05-18 00:23:14 -03004/*
5 * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
6 * the build if it isn't defined. Use the equivalent one that glibc
7 * has on features.h.
8 */
9#include <features.h>
10#ifndef HAVE_LONG_LONG
11#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
12#endif
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -030013#include <slang.h>
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -030014#include <stdlib.h>
15#include <newt.h>
Arnaldo Carvalho de Melo7081e082010-03-12 10:48:12 -030016#include <sys/ttydefaults.h>
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -030017
18#include "cache.h"
19#include "hist.h"
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -030020#include "pstack.h"
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -030021#include "session.h"
22#include "sort.h"
23#include "symbol.h"
24
Arnaldo Carvalho de Melodc4ff192010-05-17 12:25:09 -030025#if SLANG_VERSION < 20104
26#define slsmg_printf(msg, args...) SLsmg_printf((char *)msg, ##args)
27#define slsmg_write_nstring(msg, len) SLsmg_write_nstring((char *)msg, len)
28#define sltt_set_color(obj, name, fg, bg) SLtt_set_color(obj,(char *)name,\
29 (char *)fg, (char *)bg)
30#else
31#define slsmg_printf SLsmg_printf
32#define slsmg_write_nstring SLsmg_write_nstring
33#define sltt_set_color SLtt_set_color
34#endif
35
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -030036struct ui_progress {
37 newtComponent form, scale;
38};
39
40struct ui_progress *ui_progress__new(const char *title, u64 total)
41{
42 struct ui_progress *self = malloc(sizeof(*self));
43
44 if (self != NULL) {
45 int cols;
46 newtGetScreenSize(&cols, NULL);
47 cols -= 4;
48 newtCenteredWindow(cols, 1, title);
49 self->form = newtForm(NULL, NULL, 0);
50 if (self->form == NULL)
51 goto out_free_self;
52 self->scale = newtScale(0, 0, cols, total);
53 if (self->scale == NULL)
54 goto out_free_form;
Arnaldo Carvalho de Melo7f826452010-05-10 10:51:25 -030055 newtFormAddComponent(self->form, self->scale);
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -030056 newtRefresh();
57 }
58
59 return self;
60
61out_free_form:
62 newtFormDestroy(self->form);
63out_free_self:
64 free(self);
65 return NULL;
66}
67
68void ui_progress__update(struct ui_progress *self, u64 curr)
69{
70 newtScaleSet(self->scale, curr);
71 newtRefresh();
72}
73
74void ui_progress__delete(struct ui_progress *self)
75{
76 newtFormDestroy(self->form);
77 newtPopWindow();
78 free(self);
79}
80
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -030081static void ui_helpline__pop(void)
82{
83 newtPopHelpLine();
84}
85
86static void ui_helpline__push(const char *msg)
87{
88 newtPushHelpLine(msg);
89}
90
91static void ui_helpline__vpush(const char *fmt, va_list ap)
92{
93 char *s;
94
95 if (vasprintf(&s, fmt, ap) < 0)
96 vfprintf(stderr, fmt, ap);
97 else {
98 ui_helpline__push(s);
99 free(s);
100 }
101}
102
103static void ui_helpline__fpush(const char *fmt, ...)
104{
105 va_list ap;
106
107 va_start(ap, fmt);
108 ui_helpline__vpush(fmt, ap);
109 va_end(ap);
110}
111
112static void ui_helpline__puts(const char *msg)
113{
114 ui_helpline__pop();
115 ui_helpline__push(msg);
116}
117
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300118static char browser__last_msg[1024];
119
120int browser__show_help(const char *format, va_list ap)
121{
122 int ret;
123 static int backlog;
124
125 ret = vsnprintf(browser__last_msg + backlog,
126 sizeof(browser__last_msg) - backlog, format, ap);
127 backlog += ret;
128
129 if (browser__last_msg[backlog - 1] == '\n') {
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -0300130 ui_helpline__puts(browser__last_msg);
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300131 newtRefresh();
132 backlog = 0;
133 }
134
135 return ret;
136}
137
Arnaldo Carvalho de Melo7081e082010-03-12 10:48:12 -0300138static void newt_form__set_exit_keys(newtComponent self)
139{
Arnaldo Carvalho de Meloa308f3a2010-05-16 20:29:38 -0300140 newtFormAddHotKey(self, NEWT_KEY_LEFT);
Arnaldo Carvalho de Melo7081e082010-03-12 10:48:12 -0300141 newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
142 newtFormAddHotKey(self, 'Q');
143 newtFormAddHotKey(self, 'q');
144 newtFormAddHotKey(self, CTRL('c'));
145}
146
147static newtComponent newt_form__new(void)
148{
149 newtComponent self = newtForm(NULL, NULL, 0);
150 if (self)
151 newt_form__set_exit_keys(self);
152 return self;
153}
154
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300155static int popup_menu(int argc, char * const argv[])
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300156{
157 struct newtExitStruct es;
158 int i, rc = -1, max_len = 5;
159 newtComponent listbox, form = newt_form__new();
160
161 if (form == NULL)
162 return -1;
163
164 listbox = newtListbox(0, 0, argc, NEWT_FLAG_RETURNEXIT);
165 if (listbox == NULL)
166 goto out_destroy_form;
167
Arnaldo Carvalho de Melo7f826452010-05-10 10:51:25 -0300168 newtFormAddComponent(form, listbox);
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300169
170 for (i = 0; i < argc; ++i) {
171 int len = strlen(argv[i]);
172 if (len > max_len)
173 max_len = len;
174 if (newtListboxAddEntry(listbox, argv[i], (void *)(long)i))
175 goto out_destroy_form;
176 }
177
178 newtCenteredWindow(max_len, argc, NULL);
179 newtFormRun(form, &es);
180 rc = newtListboxGetCurrent(listbox) - NULL;
181 if (es.reason == NEWT_EXIT_HOTKEY)
182 rc = -1;
183 newtPopWindow();
184out_destroy_form:
185 newtFormDestroy(form);
186 return rc;
187}
188
Arnaldo Carvalho de Meloa9a4ab72010-05-16 21:04:27 -0300189static int ui__help_window(const char *text)
190{
191 struct newtExitStruct es;
192 newtComponent tb, form = newt_form__new();
193 int rc = -1;
194 int max_len = 0, nr_lines = 0;
195 const char *t;
196
197 if (form == NULL)
198 return -1;
199
200 t = text;
201 while (1) {
202 const char *sep = strchr(t, '\n');
203 int len;
204
205 if (sep == NULL)
206 sep = strchr(t, '\0');
207 len = sep - t;
208 if (max_len < len)
209 max_len = len;
210 ++nr_lines;
211 if (*sep == '\0')
212 break;
213 t = sep + 1;
214 }
215
216 tb = newtTextbox(0, 0, max_len, nr_lines, 0);
217 if (tb == NULL)
218 goto out_destroy_form;
219
220 newtTextboxSetText(tb, text);
221 newtFormAddComponent(form, tb);
222 newtCenteredWindow(max_len, nr_lines, NULL);
223 newtFormRun(form, &es);
224 newtPopWindow();
225 rc = 0;
226out_destroy_form:
227 newtFormDestroy(form);
228 return rc;
229}
230
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300231static bool dialog_yesno(const char *msg)
232{
233 /* newtWinChoice should really be accepting const char pointers... */
234 char yes[] = "Yes", no[] = "No";
Arnaldo Carvalho de Meloc0ed55d2010-04-05 12:04:23 -0300235 return newtWinChoice(NULL, yes, no, (char *)msg) == 1;
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300236}
237
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300238#define HE_COLORSET_TOP 50
239#define HE_COLORSET_MEDIUM 51
240#define HE_COLORSET_NORMAL 52
241#define HE_COLORSET_SELECTED 53
242#define HE_COLORSET_CODE 54
243
244static int ui_browser__percent_color(double percent, bool current)
245{
246 if (current)
247 return HE_COLORSET_SELECTED;
248 if (percent >= MIN_RED)
249 return HE_COLORSET_TOP;
250 if (percent >= MIN_GREEN)
251 return HE_COLORSET_MEDIUM;
252 return HE_COLORSET_NORMAL;
253}
254
255struct ui_browser {
256 newtComponent form, sb;
257 u64 index, first_visible_entry_idx;
258 void *first_visible_entry, *entries;
259 u16 top, left, width, height;
260 void *priv;
261 u32 nr_entries;
262};
263
264static void ui_browser__refresh_dimensions(struct ui_browser *self)
265{
266 int cols, rows;
267 newtGetScreenSize(&cols, &rows);
268
269 if (self->width > cols - 4)
270 self->width = cols - 4;
271 self->height = rows - 5;
272 if (self->height > self->nr_entries)
273 self->height = self->nr_entries;
274 self->top = (rows - self->height) / 2;
275 self->left = (cols - self->width) / 2;
276}
277
278static void ui_browser__reset_index(struct ui_browser *self)
279{
280 self->index = self->first_visible_entry_idx = 0;
281 self->first_visible_entry = NULL;
282}
283
284static int objdump_line__show(struct objdump_line *self, struct list_head *head,
285 int width, struct hist_entry *he, int len,
286 bool current_entry)
287{
288 if (self->offset != -1) {
289 struct symbol *sym = he->ms.sym;
290 unsigned int hits = 0;
291 double percent = 0.0;
292 int color;
293 struct sym_priv *priv = symbol__priv(sym);
294 struct sym_ext *sym_ext = priv->ext;
295 struct sym_hist *h = priv->hist;
296 s64 offset = self->offset;
297 struct objdump_line *next = objdump__get_next_ip_line(head, self);
298
299 while (offset < (s64)len &&
300 (next == NULL || offset < next->offset)) {
301 if (sym_ext) {
302 percent += sym_ext[offset].percent;
303 } else
304 hits += h->ip[offset];
305
306 ++offset;
307 }
308
309 if (sym_ext == NULL && h->sum)
310 percent = 100.0 * hits / h->sum;
311
312 color = ui_browser__percent_color(percent, current_entry);
313 SLsmg_set_color(color);
Arnaldo Carvalho de Melodc4ff192010-05-17 12:25:09 -0300314 slsmg_printf(" %7.2f ", percent);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300315 if (!current_entry)
316 SLsmg_set_color(HE_COLORSET_CODE);
317 } else {
318 int color = ui_browser__percent_color(0, current_entry);
319 SLsmg_set_color(color);
Arnaldo Carvalho de Melodc4ff192010-05-17 12:25:09 -0300320 slsmg_write_nstring(" ", 9);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300321 }
322
323 SLsmg_write_char(':');
Arnaldo Carvalho de Melodc4ff192010-05-17 12:25:09 -0300324 slsmg_write_nstring(" ", 8);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300325 if (!*self->line)
Arnaldo Carvalho de Melodc4ff192010-05-17 12:25:09 -0300326 slsmg_write_nstring(" ", width - 18);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300327 else
Arnaldo Carvalho de Melodc4ff192010-05-17 12:25:09 -0300328 slsmg_write_nstring(self->line, width - 18);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300329
330 return 0;
331}
332
333static int ui_browser__refresh_entries(struct ui_browser *self)
334{
335 struct objdump_line *pos;
336 struct list_head *head = self->entries;
337 struct hist_entry *he = self->priv;
338 int row = 0;
339 int len = he->ms.sym->end - he->ms.sym->start;
340
341 if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries)
342 self->first_visible_entry = head->next;
343
344 pos = list_entry(self->first_visible_entry, struct objdump_line, node);
345
346 list_for_each_entry_from(pos, head, node) {
347 bool current_entry = (self->first_visible_entry_idx + row) == self->index;
348 SLsmg_gotorc(self->top + row, self->left);
349 objdump_line__show(pos, head, self->width,
350 he, len, current_entry);
351 if (++row == self->height)
352 break;
353 }
354
355 SLsmg_set_color(HE_COLORSET_NORMAL);
356 SLsmg_fill_region(self->top + row, self->left,
357 self->height - row, self->width, ' ');
358
359 return 0;
360}
361
362static int ui_browser__run(struct ui_browser *self, const char *title,
363 struct newtExitStruct *es)
364{
365 if (self->form) {
366 newtFormDestroy(self->form);
367 newtPopWindow();
368 }
369
370 ui_browser__refresh_dimensions(self);
371 newtCenteredWindow(self->width + 2, self->height, title);
372 self->form = newt_form__new();
373 if (self->form == NULL)
374 return -1;
375
376 self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height,
377 HE_COLORSET_NORMAL,
378 HE_COLORSET_SELECTED);
379 if (self->sb == NULL)
380 return -1;
381
382 newtFormAddHotKey(self->form, NEWT_KEY_UP);
383 newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
384 newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
385 newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
Arnaldo Carvalho de Melo17930b42010-05-19 16:03:51 -0300386 newtFormAddHotKey(self->form, ' ');
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300387 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
388 newtFormAddHotKey(self->form, NEWT_KEY_END);
389
390 if (ui_browser__refresh_entries(self) < 0)
391 return -1;
392 newtFormAddComponent(self->form, self->sb);
393
394 while (1) {
395 unsigned int offset;
396
397 newtFormRun(self->form, es);
398
399 if (es->reason != NEWT_EXIT_HOTKEY)
400 break;
401 switch (es->u.key) {
402 case NEWT_KEY_DOWN:
403 if (self->index == self->nr_entries - 1)
404 break;
405 ++self->index;
406 if (self->index == self->first_visible_entry_idx + self->height) {
407 struct list_head *pos = self->first_visible_entry;
408 ++self->first_visible_entry_idx;
409 self->first_visible_entry = pos->next;
410 }
411 break;
412 case NEWT_KEY_UP:
413 if (self->index == 0)
414 break;
415 --self->index;
416 if (self->index < self->first_visible_entry_idx) {
417 struct list_head *pos = self->first_visible_entry;
418 --self->first_visible_entry_idx;
419 self->first_visible_entry = pos->prev;
420 }
421 break;
422 case NEWT_KEY_PGDN:
Arnaldo Carvalho de Melo17930b42010-05-19 16:03:51 -0300423 case ' ':
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300424 if (self->first_visible_entry_idx + self->height > self->nr_entries - 1)
425 break;
426
427 offset = self->height;
428 if (self->index + offset > self->nr_entries - 1)
429 offset = self->nr_entries - 1 - self->index;
430 self->index += offset;
431 self->first_visible_entry_idx += offset;
432
433 while (offset--) {
434 struct list_head *pos = self->first_visible_entry;
435 self->first_visible_entry = pos->next;
436 }
437
438 break;
439 case NEWT_KEY_PGUP:
440 if (self->first_visible_entry_idx == 0)
441 break;
442
443 if (self->first_visible_entry_idx < self->height)
444 offset = self->first_visible_entry_idx;
445 else
446 offset = self->height;
447
448 self->index -= offset;
449 self->first_visible_entry_idx -= offset;
450
451 while (offset--) {
452 struct list_head *pos = self->first_visible_entry;
453 self->first_visible_entry = pos->prev;
454 }
455 break;
456 case NEWT_KEY_HOME:
457 ui_browser__reset_index(self);
458 break;
459 case NEWT_KEY_END: {
460 struct list_head *head = self->entries;
461 offset = self->height - 1;
462
463 if (offset > self->nr_entries)
464 offset = self->nr_entries;
465
466 self->index = self->first_visible_entry_idx = self->nr_entries - 1 - offset;
467 self->first_visible_entry = head->prev;
468 while (offset-- != 0) {
469 struct list_head *pos = self->first_visible_entry;
470 self->first_visible_entry = pos->prev;
471 }
472 }
473 break;
474 case NEWT_KEY_ESCAPE:
Arnaldo Carvalho de Melo60553902010-05-15 20:40:34 -0300475 case NEWT_KEY_LEFT:
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300476 case CTRL('c'):
477 case 'Q':
478 case 'q':
479 return 0;
480 default:
481 continue;
482 }
483 if (ui_browser__refresh_entries(self) < 0)
484 return -1;
485 }
486 return 0;
487}
488
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300489/*
490 * When debugging newt problems it was useful to be able to "unroll"
491 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
492 * a source file with the sequence of calls to these methods, to then
493 * tweak the arrays to get the intended results, so I'm keeping this code
494 * here, may be useful again in the future.
495 */
496#undef NEWT_DEBUG
497
498static void newt_checkbox_tree__add(newtComponent tree, const char *str,
499 void *priv, int *indexes)
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300500{
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300501#ifdef NEWT_DEBUG
502 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
503 int i = 0, len = 40 - strlen(str);
504
505 fprintf(stderr,
506 "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
507 len, len, " ", str, priv);
508 while (indexes[i] != NEWT_ARG_LAST) {
509 if (indexes[i] != NEWT_ARG_APPEND)
510 fprintf(stderr, " %d,", indexes[i]);
511 else
512 fprintf(stderr, " %s,", "NEWT_ARG_APPEND");
513 ++i;
514 }
515 fprintf(stderr, " %s", " NEWT_ARG_LAST);\n");
516 fflush(stderr);
517#endif
518 newtCheckboxTreeAddArray(tree, str, priv, 0, indexes);
519}
520
521static char *callchain_list__sym_name(struct callchain_list *self,
522 char *bf, size_t bfsize)
523{
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300524 if (self->ms.sym)
525 return self->ms.sym->name;
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300526
527 snprintf(bf, bfsize, "%#Lx", self->ip);
528 return bf;
529}
530
531static void __callchain__append_graph_browser(struct callchain_node *self,
532 newtComponent tree, u64 total,
533 int *indexes, int depth)
534{
535 struct rb_node *node;
536 u64 new_total, remaining;
537 int idx = 0;
538
539 if (callchain_param.mode == CHAIN_GRAPH_REL)
540 new_total = self->children_hit;
541 else
542 new_total = total;
543
544 remaining = new_total;
545 node = rb_first(&self->rb_root);
546 while (node) {
547 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
548 struct rb_node *next = rb_next(node);
549 u64 cumul = cumul_hits(child);
550 struct callchain_list *chain;
551 int first = true, printed = 0;
552 int chain_idx = -1;
553 remaining -= cumul;
554
555 indexes[depth] = NEWT_ARG_APPEND;
556 indexes[depth + 1] = NEWT_ARG_LAST;
557
558 list_for_each_entry(chain, &child->val, list) {
559 char ipstr[BITS_PER_LONG / 4 + 1],
560 *alloc_str = NULL;
561 const char *str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
562
563 if (first) {
564 double percent = cumul * 100.0 / new_total;
565
566 first = false;
567 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
568 str = "Not enough memory!";
569 else
570 str = alloc_str;
571 } else {
572 indexes[depth] = idx;
573 indexes[depth + 1] = NEWT_ARG_APPEND;
574 indexes[depth + 2] = NEWT_ARG_LAST;
575 ++chain_idx;
576 }
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -0300577 newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300578 free(alloc_str);
579 ++printed;
580 }
581
582 indexes[depth] = idx;
583 if (chain_idx != -1)
584 indexes[depth + 1] = chain_idx;
585 if (printed != 0)
586 ++idx;
587 __callchain__append_graph_browser(child, tree, new_total, indexes,
588 depth + (chain_idx != -1 ? 2 : 1));
589 node = next;
590 }
591}
592
593static void callchain__append_graph_browser(struct callchain_node *self,
594 newtComponent tree, u64 total,
595 int *indexes, int parent_idx)
596{
597 struct callchain_list *chain;
598 int i = 0;
599
600 indexes[1] = NEWT_ARG_APPEND;
601 indexes[2] = NEWT_ARG_LAST;
602
603 list_for_each_entry(chain, &self->val, list) {
604 char ipstr[BITS_PER_LONG / 4 + 1], *str;
605
606 if (chain->ip >= PERF_CONTEXT_MAX)
607 continue;
608
609 if (!i++ && sort__first_dimension == SORT_SYM)
610 continue;
611
612 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -0300613 newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300614 }
615
616 indexes[1] = parent_idx;
617 indexes[2] = NEWT_ARG_APPEND;
618 indexes[3] = NEWT_ARG_LAST;
619 __callchain__append_graph_browser(self, tree, total, indexes, 2);
620}
621
622static void hist_entry__append_callchain_browser(struct hist_entry *self,
623 newtComponent tree, u64 total, int parent_idx)
624{
625 struct rb_node *rb_node;
626 int indexes[1024] = { [0] = parent_idx, };
627 int idx = 0;
628 struct callchain_node *chain;
629
630 rb_node = rb_first(&self->sorted_chain);
631 while (rb_node) {
632 chain = rb_entry(rb_node, struct callchain_node, rb_node);
633 switch (callchain_param.mode) {
634 case CHAIN_FLAT:
635 break;
636 case CHAIN_GRAPH_ABS: /* falldown */
637 case CHAIN_GRAPH_REL:
638 callchain__append_graph_browser(chain, tree, total, indexes, idx++);
639 break;
640 case CHAIN_NONE:
641 default:
642 break;
643 }
644 rb_node = rb_next(rb_node);
645 }
646}
647
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300648static size_t hist_entry__append_browser(struct hist_entry *self,
649 newtComponent tree, u64 total)
650{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300651 char s[256];
652 size_t ret;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300653
654 if (symbol_conf.exclude_other && !self->parent)
655 return 0;
656
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300657 ret = hist_entry__snprintf(self, s, sizeof(s), NULL,
658 false, 0, false, total);
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300659 if (symbol_conf.use_callchain) {
660 int indexes[2];
661
662 indexes[0] = NEWT_ARG_APPEND;
663 indexes[1] = NEWT_ARG_LAST;
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -0300664 newt_checkbox_tree__add(tree, s, &self->ms, indexes);
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300665 } else
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -0300666 newtListboxAppendEntry(tree, s, &self->ms);
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300667
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300668 return ret;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300669}
670
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300671static void hist_entry__annotate_browser(struct hist_entry *self)
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300672{
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300673 struct ui_browser browser;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300674 struct newtExitStruct es;
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300675 struct objdump_line *pos, *n;
676 LIST_HEAD(head);
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300677
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300678 if (self->ms.sym == NULL)
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300679 return;
680
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300681 if (hist_entry__annotate(self, &head) < 0)
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300682 return;
683
Arnaldo Carvalho de Melo60553902010-05-15 20:40:34 -0300684 ui_helpline__push("Press <- or ESC to exit");
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300685
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300686 memset(&browser, 0, sizeof(browser));
687 browser.entries = &head;
688 browser.priv = self;
689 list_for_each_entry(pos, &head, node) {
690 size_t line_len = strlen(pos->line);
691 if (browser.width < line_len)
692 browser.width = line_len;
693 ++browser.nr_entries;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300694 }
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300695
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300696 browser.width += 18; /* Percentage */
697 ui_browser__run(&browser, self->ms.sym->name, &es);
698 newtFormDestroy(browser.form);
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300699 newtPopWindow();
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300700 list_for_each_entry_safe(pos, n, &head, node) {
701 list_del(&pos->node);
702 objdump_line__free(pos);
703 }
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -0300704 ui_helpline__pop();
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300705}
706
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300707static const void *newt__symbol_tree_get_current(newtComponent self)
708{
709 if (symbol_conf.use_callchain)
710 return newtCheckboxTreeGetCurrent(self);
711 return newtListboxGetCurrent(self);
712}
713
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300714static void hist_browser__selection(newtComponent self, void *data)
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300715{
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -0300716 const struct map_symbol **symbol_ptr = data;
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300717 *symbol_ptr = newt__symbol_tree_get_current(self);
718}
719
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300720struct hist_browser {
721 newtComponent form, tree;
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -0300722 const struct map_symbol *selection;
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300723};
724
725static struct hist_browser *hist_browser__new(void)
726{
727 struct hist_browser *self = malloc(sizeof(*self));
728
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300729 if (self != NULL)
730 self->form = NULL;
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300731
732 return self;
733}
734
735static void hist_browser__delete(struct hist_browser *self)
736{
737 newtFormDestroy(self->form);
738 newtPopWindow();
739 free(self);
740}
741
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -0300742static int hist_browser__populate(struct hist_browser *self, struct hists *hists,
743 const char *title)
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300744{
745 int max_len = 0, idx, cols, rows;
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300746 struct ui_progress *progress;
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300747 struct rb_node *nd;
748 u64 curr_hist = 0;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300749 char seq[] = ".", unit;
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300750 char str[256];
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300751 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300752
753 if (self->form) {
754 newtFormDestroy(self->form);
755 newtPopWindow();
756 }
757
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300758 nr_events = convert_unit(nr_events, &unit);
759 snprintf(str, sizeof(str), "Events: %lu%c ",
760 nr_events, unit);
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300761 newtDrawRootText(0, 0, str);
762
763 newtGetScreenSize(NULL, &rows);
764
765 if (symbol_conf.use_callchain)
766 self->tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
767 NEWT_FLAG_SCROLL);
768 else
769 self->tree = newtListbox(0, 0, rows - 5,
770 (NEWT_FLAG_SCROLL |
771 NEWT_FLAG_RETURNEXIT));
772
773 newtComponentAddCallback(self->tree, hist_browser__selection,
774 &self->selection);
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300775
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -0300776 progress = ui_progress__new("Adding entries to the browser...",
777 hists->nr_entries);
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300778 if (progress == NULL)
779 return -1;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300780
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300781 idx = 0;
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -0300782 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300783 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300784 int len;
785
786 if (h->filtered)
787 continue;
788
Arnaldo Carvalho de Melocee75ac2010-05-14 13:16:55 -0300789 len = hist_entry__append_browser(h, self->tree, hists->stats.total_period);
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300790 if (len > max_len)
791 max_len = len;
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -0300792 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300793 hist_entry__append_callchain_browser(h, self->tree,
Arnaldo Carvalho de Melocee75ac2010-05-14 13:16:55 -0300794 hists->stats.total_period, idx++);
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300795 ++curr_hist;
796 if (curr_hist % 5)
797 ui_progress__update(progress, curr_hist);
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300798 }
799
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300800 ui_progress__delete(progress);
801
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300802 newtGetScreenSize(&cols, &rows);
803
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300804 if (max_len > cols)
805 max_len = cols - 3;
806
807 if (!symbol_conf.use_callchain)
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300808 newtListboxSetWidth(self->tree, max_len);
Arnaldo Carvalho de Melo4ded2b22010-03-22 17:52:49 -0300809
810 newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0),
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -0300811 rows - 5, title);
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300812 self->form = newt_form__new();
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300813 if (self->form == NULL)
814 return -1;
815
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300816 newtFormAddHotKey(self->form, 'A');
817 newtFormAddHotKey(self->form, 'a');
Arnaldo Carvalho de Melo9d192e12010-05-15 21:15:01 -0300818 newtFormAddHotKey(self->form, 'D');
819 newtFormAddHotKey(self->form, 'd');
820 newtFormAddHotKey(self->form, 'T');
821 newtFormAddHotKey(self->form, 't');
Arnaldo Carvalho de Meloa9a4ab72010-05-16 21:04:27 -0300822 newtFormAddHotKey(self->form, '?');
823 newtFormAddHotKey(self->form, 'H');
824 newtFormAddHotKey(self->form, 'h');
825 newtFormAddHotKey(self->form, NEWT_KEY_F1);
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300826 newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
827 newtFormAddComponents(self->form, self->tree, NULL);
828 self->selection = newt__symbol_tree_get_current(self->tree);
829
830 return 0;
831}
832
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300833static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -0300834{
835 int *indexes;
836
837 if (!symbol_conf.use_callchain)
838 goto out;
839
840 indexes = newtCheckboxTreeFindItem(self->tree, (void *)self->selection);
841 if (indexes) {
842 bool is_hist_entry = indexes[1] == NEWT_ARG_LAST;
843 free(indexes);
844 if (is_hist_entry)
845 goto out;
846 }
847 return NULL;
848out:
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300849 return container_of(self->selection, struct hist_entry, ms);
850}
851
852static struct thread *hist_browser__selected_thread(struct hist_browser *self)
853{
854 struct hist_entry *he = hist_browser__selected_entry(self);
855 return he ? he->thread : NULL;
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -0300856}
857
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -0300858static int hist_browser__title(char *bf, size_t size, const char *input_name,
859 const struct dso *dso, const struct thread *thread)
860{
861 int printed = 0;
862
863 if (thread)
864 printed += snprintf(bf + printed, size - printed,
865 "Thread: %s(%d)",
866 (thread->comm_set ? thread->comm : ""),
867 thread->pid);
868 if (dso)
869 printed += snprintf(bf + printed, size - printed,
870 "%sDSO: %s", thread ? " " : "",
871 dso->short_name);
872 return printed ?: snprintf(bf, size, "Report: %s", input_name);
873}
874
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -0300875int hists__browse(struct hists *self, const char *helpline, const char *input_name)
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300876{
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300877 struct hist_browser *browser = hist_browser__new();
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -0300878 struct pstack *fstack = pstack__new(2);
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -0300879 const struct thread *thread_filter = NULL;
880 const struct dso *dso_filter = NULL;
881 struct newtExitStruct es;
882 char msg[160];
883 int err = -1;
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300884
885 if (browser == NULL)
886 return -1;
887
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -0300888 fstack = pstack__new(2);
889 if (fstack == NULL)
890 goto out;
891
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -0300892 ui_helpline__push(helpline);
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300893
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -0300894 hist_browser__title(msg, sizeof(msg), input_name,
895 dso_filter, thread_filter);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -0300896 if (hist_browser__populate(browser, self, msg) < 0)
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -0300897 goto out_free_stack;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300898
899 while (1) {
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -0300900 const struct thread *thread;
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -0300901 const struct dso *dso;
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300902 char *options[16];
903 int nr_options = 0, choice = 0, i,
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -0300904 annotate = -2, zoom_dso = -2, zoom_thread = -2;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300905
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300906 newtFormRun(browser->form, &es);
Arnaldo Carvalho de Melo9d192e12010-05-15 21:15:01 -0300907
908 thread = hist_browser__selected_thread(browser);
909 dso = browser->selection->map ? browser->selection->map->dso : NULL;
910
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300911 if (es.reason == NEWT_EXIT_HOTKEY) {
Arnaldo Carvalho de Meloa9a4ab72010-05-16 21:04:27 -0300912 if (es.u.key == NEWT_KEY_F1)
913 goto do_help;
914
Arnaldo Carvalho de Melo9d192e12010-05-15 21:15:01 -0300915 switch (toupper(es.u.key)) {
916 case 'A':
Arnaldo Carvalho de Melo6e78c9f2010-05-22 11:20:24 -0300917 if (browser->selection->map == NULL &&
918 browser->selection->map->dso->annotate_warned)
919 continue;
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -0300920 goto do_annotate;
Arnaldo Carvalho de Melo9d192e12010-05-15 21:15:01 -0300921 case 'D':
922 goto zoom_dso;
923 case 'T':
924 goto zoom_thread;
Arnaldo Carvalho de Meloa9a4ab72010-05-16 21:04:27 -0300925 case 'H':
926 case '?':
927do_help:
928 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n"
929 "<- Zoom out\n"
930 "a Annotate current symbol\n"
931 "h/?/F1 Show this window\n"
932 "d Zoom into current DSO\n"
933 "t Zoom into current Thread\n"
934 "q/CTRL+C Exit browser");
935 continue;
Arnaldo Carvalho de Melo9d192e12010-05-15 21:15:01 -0300936 default:;
937 }
Arnaldo Carvalho de Melo29351db2010-05-15 21:06:58 -0300938 if (toupper(es.u.key) == 'Q' ||
939 es.u.key == CTRL('c'))
940 break;
941 if (es.u.key == NEWT_KEY_ESCAPE) {
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300942 if (dialog_yesno("Do you really want to exit?"))
943 break;
944 else
945 continue;
946 }
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -0300947
948 if (es.u.key == NEWT_KEY_LEFT) {
949 const void *top;
950
951 if (pstack__empty(fstack))
952 continue;
953 top = pstack__pop(fstack);
954 if (top == &dso_filter)
955 goto zoom_out_dso;
956 if (top == &thread_filter)
957 goto zoom_out_thread;
958 continue;
959 }
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300960 }
961
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300962 if (browser->selection->sym != NULL &&
Arnaldo Carvalho de Melo6e78c9f2010-05-22 11:20:24 -0300963 !browser->selection->map->dso->annotate_warned &&
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300964 asprintf(&options[nr_options], "Annotate %s",
965 browser->selection->sym->name) > 0)
966 annotate = nr_options++;
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300967
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -0300968 if (thread != NULL &&
969 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -0300970 (thread_filter ? "out of" : "into"),
971 (thread->comm_set ? thread->comm : ""),
972 thread->pid) > 0)
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -0300973 zoom_thread = nr_options++;
974
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -0300975 if (dso != NULL &&
976 asprintf(&options[nr_options], "Zoom %s %s DSO",
977 (dso_filter ? "out of" : "into"),
978 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
979 zoom_dso = nr_options++;
980
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300981 options[nr_options++] = (char *)"Exit";
982
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300983 choice = popup_menu(nr_options, options);
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300984
985 for (i = 0; i < nr_options - 1; ++i)
986 free(options[i]);
987
Arnaldo Carvalho de Melo53c54012010-03-24 16:40:14 -0300988 if (choice == nr_options - 1)
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -0300989 break;
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -0300990
991 if (choice == -1)
992 continue;
Arnaldo Carvalho de Meloc1ec5fe2010-05-15 20:45:31 -0300993
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -0300994 if (choice == annotate) {
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -0300995 struct hist_entry *he;
Arnaldo Carvalho de Meloc1ec5fe2010-05-15 20:45:31 -0300996do_annotate:
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -0300997 if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
Arnaldo Carvalho de Melo6e78c9f2010-05-22 11:20:24 -0300998 browser->selection->map->dso->annotate_warned = 1;
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -0300999 ui_helpline__puts("No vmlinux file found, can't "
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -03001000 "annotate with just a "
1001 "kallsyms file");
1002 continue;
1003 }
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001004
1005 he = hist_browser__selected_entry(browser);
1006 if (he == NULL)
1007 continue;
1008
1009 hist_entry__annotate_browser(he);
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -03001010 } else if (choice == zoom_dso) {
Arnaldo Carvalho de Melo9d192e12010-05-15 21:15:01 -03001011zoom_dso:
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001012 if (dso_filter) {
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -03001013 pstack__remove(fstack, &dso_filter);
1014zoom_out_dso:
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -03001015 ui_helpline__pop();
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001016 dso_filter = NULL;
1017 } else {
Arnaldo Carvalho de Melo9d192e12010-05-15 21:15:01 -03001018 if (dso == NULL)
1019 continue;
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -03001020 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -03001021 dso->kernel ? "the Kernel" : dso->short_name);
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001022 dso_filter = dso;
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -03001023 pstack__push(fstack, &dso_filter);
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001024 }
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001025 hists__filter_by_dso(self, dso_filter);
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001026 hist_browser__title(msg, sizeof(msg), input_name,
1027 dso_filter, thread_filter);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001028 if (hist_browser__populate(browser, self, msg) < 0)
Arnaldo Carvalho de Melo83753192010-04-03 16:30:44 -03001029 goto out;
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -03001030 } else if (choice == zoom_thread) {
Arnaldo Carvalho de Melo9d192e12010-05-15 21:15:01 -03001031zoom_thread:
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001032 if (thread_filter) {
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -03001033 pstack__remove(fstack, &thread_filter);
1034zoom_out_thread:
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -03001035 ui_helpline__pop();
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001036 thread_filter = NULL;
1037 } else {
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -03001038 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -03001039 thread->comm_set ? thread->comm : "",
1040 thread->pid);
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001041 thread_filter = thread;
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -03001042 pstack__push(fstack, &thread_filter);
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001043 }
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001044 hists__filter_by_thread(self, thread_filter);
Arnaldo Carvalho de Melo6e7ab4c2010-04-05 12:02:18 -03001045 hist_browser__title(msg, sizeof(msg), input_name,
1046 dso_filter, thread_filter);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001047 if (hist_browser__populate(browser, self, msg) < 0)
Arnaldo Carvalho de Meloa5e29ac2010-04-03 22:44:37 -03001048 goto out;
Arnaldo Carvalho de Melod5679ae2010-03-24 16:40:19 -03001049 }
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001050 }
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -03001051 err = 0;
Arnaldo Carvalho de Melo3e1bbdc32010-05-14 20:05:21 -03001052out_free_stack:
1053 pstack__delete(fstack);
Arnaldo Carvalho de Meloe65713e2010-04-03 11:25:56 -03001054out:
1055 hist_browser__delete(browser);
1056 return err;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001057}
1058
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001059static struct newtPercentTreeColors {
1060 const char *topColorFg, *topColorBg;
1061 const char *mediumColorFg, *mediumColorBg;
1062 const char *normalColorFg, *normalColorBg;
1063 const char *selColorFg, *selColorBg;
1064 const char *codeColorFg, *codeColorBg;
1065} defaultPercentTreeColors = {
1066 "red", "lightgray",
1067 "green", "lightgray",
1068 "black", "lightgray",
1069 "lightgray", "magenta",
1070 "blue", "lightgray",
1071};
1072
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001073void setup_browser(void)
1074{
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001075 struct newtPercentTreeColors *c = &defaultPercentTreeColors;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001076
Arnaldo Carvalho de Melo5d06e692010-05-20 22:01:10 -03001077 if (!isatty(1) || !use_browser) {
1078 setup_pager();
1079 return;
1080 }
1081
1082 use_browser = 1;
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001083 newtInit();
1084 newtCls();
Arnaldo Carvalho de Melo3798ed72010-05-11 18:01:23 -03001085 ui_helpline__puts(" ");
Arnaldo Carvalho de Melodc4ff192010-05-17 12:25:09 -03001086 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
1087 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
1088 sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg);
1089 sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg);
1090 sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001091}
1092
Arnaldo Carvalho de Melof3a1f0e2010-03-22 13:10:25 -03001093void exit_browser(bool wait_for_ok)
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001094{
Arnaldo Carvalho de Melo5d06e692010-05-20 22:01:10 -03001095 if (use_browser > 0) {
Arnaldo Carvalho de Melof3a1f0e2010-03-22 13:10:25 -03001096 if (wait_for_ok) {
1097 char title[] = "Fatal Error", ok[] = "Ok";
1098 newtWinMessage(title, ok, browser__last_msg);
1099 }
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001100 newtFinished();
Arnaldo Carvalho de Melof3a1f0e2010-03-22 13:10:25 -03001101 }
Arnaldo Carvalho de Melof9224c52010-03-11 20:12:44 -03001102}