]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - tools/perf/util/newt.c
7 #include <sys/ttydefaults.h>
16 newtComponent form
, scale
;
19 struct ui_progress
*ui_progress__new(const char *title
, u64 total
)
21 struct ui_progress
*self
= malloc(sizeof(*self
));
25 newtGetScreenSize(&cols
, NULL
);
27 newtCenteredWindow(cols
, 1, title
);
28 self
->form
= newtForm(NULL
, NULL
, 0);
29 if (self
->form
== NULL
)
31 self
->scale
= newtScale(0, 0, cols
, total
);
32 if (self
->scale
== NULL
)
34 newtFormAddComponents(self
->form
, self
->scale
, NULL
);
41 newtFormDestroy(self
->form
);
47 void ui_progress__update(struct ui_progress
*self
, u64 curr
)
49 newtScaleSet(self
->scale
, curr
);
53 void ui_progress__delete(struct ui_progress
*self
)
55 newtFormDestroy(self
->form
);
60 static char browser__last_msg
[1024];
62 int browser__show_help(const char *format
, va_list ap
)
67 ret
= vsnprintf(browser__last_msg
+ backlog
,
68 sizeof(browser__last_msg
) - backlog
, format
, ap
);
71 if (browser__last_msg
[backlog
- 1] == '\n') {
73 newtPushHelpLine(browser__last_msg
);
81 static void newt_form__set_exit_keys(newtComponent self
)
83 newtFormAddHotKey(self
, NEWT_KEY_ESCAPE
);
84 newtFormAddHotKey(self
, 'Q');
85 newtFormAddHotKey(self
, 'q');
86 newtFormAddHotKey(self
, CTRL('c'));
89 static newtComponent
newt_form__new(void)
91 newtComponent self
= newtForm(NULL
, NULL
, 0);
93 newt_form__set_exit_keys(self
);
97 static int popup_menu(int argc
, char * const argv
[])
99 struct newtExitStruct es
;
100 int i
, rc
= -1, max_len
= 5;
101 newtComponent listbox
, form
= newt_form__new();
106 listbox
= newtListbox(0, 0, argc
, NEWT_FLAG_RETURNEXIT
);
108 goto out_destroy_form
;
110 newtFormAddComponents(form
, listbox
, NULL
);
112 for (i
= 0; i
< argc
; ++i
) {
113 int len
= strlen(argv
[i
]);
116 if (newtListboxAddEntry(listbox
, argv
[i
], (void *)(long)i
))
117 goto out_destroy_form
;
120 newtCenteredWindow(max_len
, argc
, NULL
);
121 newtFormRun(form
, &es
);
122 rc
= newtListboxGetCurrent(listbox
) - NULL
;
123 if (es
.reason
== NEWT_EXIT_HOTKEY
)
127 newtFormDestroy(form
);
131 static bool dialog_yesno(const char *msg
)
133 /* newtWinChoice should really be accepting const char pointers... */
134 char yes
[] = "Yes", no
[] = "No";
135 return newtWinChoice(NULL
, no
, yes
, (char *)msg
) == 2;
139 * When debugging newt problems it was useful to be able to "unroll"
140 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
141 * a source file with the sequence of calls to these methods, to then
142 * tweak the arrays to get the intended results, so I'm keeping this code
143 * here, may be useful again in the future.
147 static void newt_checkbox_tree__add(newtComponent tree
, const char *str
,
148 void *priv
, int *indexes
)
151 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
152 int i
= 0, len
= 40 - strlen(str
);
155 "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
156 len
, len
, " ", str
, priv
);
157 while (indexes
[i
] != NEWT_ARG_LAST
) {
158 if (indexes
[i
] != NEWT_ARG_APPEND
)
159 fprintf(stderr
, " %d,", indexes
[i
]);
161 fprintf(stderr
, " %s,", "NEWT_ARG_APPEND");
164 fprintf(stderr
, " %s", " NEWT_ARG_LAST);\n");
167 newtCheckboxTreeAddArray(tree
, str
, priv
, 0, indexes
);
170 static char *callchain_list__sym_name(struct callchain_list
*self
,
171 char *bf
, size_t bfsize
)
174 return self
->ms
.sym
->name
;
176 snprintf(bf
, bfsize
, "%#Lx", self
->ip
);
180 static void __callchain__append_graph_browser(struct callchain_node
*self
,
181 newtComponent tree
, u64 total
,
182 int *indexes
, int depth
)
184 struct rb_node
*node
;
185 u64 new_total
, remaining
;
188 if (callchain_param
.mode
== CHAIN_GRAPH_REL
)
189 new_total
= self
->children_hit
;
193 remaining
= new_total
;
194 node
= rb_first(&self
->rb_root
);
196 struct callchain_node
*child
= rb_entry(node
, struct callchain_node
, rb_node
);
197 struct rb_node
*next
= rb_next(node
);
198 u64 cumul
= cumul_hits(child
);
199 struct callchain_list
*chain
;
200 int first
= true, printed
= 0;
204 indexes
[depth
] = NEWT_ARG_APPEND
;
205 indexes
[depth
+ 1] = NEWT_ARG_LAST
;
207 list_for_each_entry(chain
, &child
->val
, list
) {
208 char ipstr
[BITS_PER_LONG
/ 4 + 1],
210 const char *str
= callchain_list__sym_name(chain
, ipstr
, sizeof(ipstr
));
213 double percent
= cumul
* 100.0 / new_total
;
216 if (asprintf(&alloc_str
, "%2.2f%% %s", percent
, str
) < 0)
217 str
= "Not enough memory!";
221 indexes
[depth
] = idx
;
222 indexes
[depth
+ 1] = NEWT_ARG_APPEND
;
223 indexes
[depth
+ 2] = NEWT_ARG_LAST
;
226 newt_checkbox_tree__add(tree
, str
, &chain
->ms
, indexes
);
231 indexes
[depth
] = idx
;
233 indexes
[depth
+ 1] = chain_idx
;
236 __callchain__append_graph_browser(child
, tree
, new_total
, indexes
,
237 depth
+ (chain_idx
!= -1 ? 2 : 1));
242 static void callchain__append_graph_browser(struct callchain_node
*self
,
243 newtComponent tree
, u64 total
,
244 int *indexes
, int parent_idx
)
246 struct callchain_list
*chain
;
249 indexes
[1] = NEWT_ARG_APPEND
;
250 indexes
[2] = NEWT_ARG_LAST
;
252 list_for_each_entry(chain
, &self
->val
, list
) {
253 char ipstr
[BITS_PER_LONG
/ 4 + 1], *str
;
255 if (chain
->ip
>= PERF_CONTEXT_MAX
)
258 if (!i
++ && sort__first_dimension
== SORT_SYM
)
261 str
= callchain_list__sym_name(chain
, ipstr
, sizeof(ipstr
));
262 newt_checkbox_tree__add(tree
, str
, &chain
->ms
, indexes
);
265 indexes
[1] = parent_idx
;
266 indexes
[2] = NEWT_ARG_APPEND
;
267 indexes
[3] = NEWT_ARG_LAST
;
268 __callchain__append_graph_browser(self
, tree
, total
, indexes
, 2);
271 static void hist_entry__append_callchain_browser(struct hist_entry
*self
,
272 newtComponent tree
, u64 total
, int parent_idx
)
274 struct rb_node
*rb_node
;
275 int indexes
[1024] = { [0] = parent_idx
, };
277 struct callchain_node
*chain
;
279 rb_node
= rb_first(&self
->sorted_chain
);
281 chain
= rb_entry(rb_node
, struct callchain_node
, rb_node
);
282 switch (callchain_param
.mode
) {
285 case CHAIN_GRAPH_ABS
: /* falldown */
286 case CHAIN_GRAPH_REL
:
287 callchain__append_graph_browser(chain
, tree
, total
, indexes
, idx
++);
293 rb_node
= rb_next(rb_node
);
297 static size_t hist_entry__append_browser(struct hist_entry
*self
,
298 newtComponent tree
, u64 total
)
303 if (symbol_conf
.exclude_other
&& !self
->parent
)
306 ret
= hist_entry__snprintf(self
, s
, sizeof(s
), NULL
,
307 false, 0, false, total
);
308 if (symbol_conf
.use_callchain
) {
311 indexes
[0] = NEWT_ARG_APPEND
;
312 indexes
[1] = NEWT_ARG_LAST
;
313 newt_checkbox_tree__add(tree
, s
, &self
->ms
, indexes
);
315 newtListboxAppendEntry(tree
, s
, &self
->ms
);
320 static void map_symbol__annotate_browser(const struct map_symbol
*self
,
321 const char *input_name
)
325 newtComponent form
, tree
;
326 struct newtExitStruct es
;
328 size_t line_len
, max_line_len
= 0;
329 size_t max_usable_width
;
332 if (self
->sym
== NULL
)
335 if (asprintf(&str
, "perf annotate -i \"%s\" -d \"%s\" %s 2>&1 | expand",
336 input_name
, self
->map
->dso
->name
, self
->sym
->name
) < 0)
339 fp
= popen(str
, "r");
343 newtPushHelpLine("Press ESC to exit");
344 newtGetScreenSize(&cols
, &rows
);
345 tree
= newtListbox(0, 0, rows
- 5, NEWT_FLAG_SCROLL
);
348 if (getline(&line
, &line_len
, fp
) < 0 || !line_len
)
350 while (line_len
!= 0 && isspace(line
[line_len
- 1]))
351 line
[--line_len
] = '\0';
353 if (line_len
> max_line_len
)
354 max_line_len
= line_len
;
355 newtListboxAppendEntry(tree
, line
, NULL
);
360 max_usable_width
= cols
- 22;
361 if (max_line_len
> max_usable_width
)
362 max_line_len
= max_usable_width
;
364 newtListboxSetWidth(tree
, max_line_len
);
366 newtCenteredWindow(max_line_len
+ 2, rows
- 5, self
->sym
->name
);
367 form
= newt_form__new();
368 newtFormAddComponents(form
, tree
, NULL
);
370 newtFormRun(form
, &es
);
371 newtFormDestroy(form
);
378 static const void *newt__symbol_tree_get_current(newtComponent self
)
380 if (symbol_conf
.use_callchain
)
381 return newtCheckboxTreeGetCurrent(self
);
382 return newtListboxGetCurrent(self
);
385 static void hist_browser__selection(newtComponent self
, void *data
)
387 const struct map_symbol
**symbol_ptr
= data
;
388 *symbol_ptr
= newt__symbol_tree_get_current(self
);
391 struct hist_browser
{
392 newtComponent form
, tree
;
393 const struct map_symbol
*selection
;
396 static struct hist_browser
*hist_browser__new(void)
398 struct hist_browser
*self
= malloc(sizeof(*self
));
406 static void hist_browser__delete(struct hist_browser
*self
)
408 newtFormDestroy(self
->form
);
413 static int hist_browser__populate(struct hist_browser
*self
, struct rb_root
*hists
,
414 u64 nr_hists
, u64 session_total
)
416 int max_len
= 0, idx
, cols
, rows
;
417 struct ui_progress
*progress
;
424 newtFormDestroy(self
->form
);
428 snprintf(str
, sizeof(str
), "Samples: %Ld ",
430 newtDrawRootText(0, 0, str
);
432 newtGetScreenSize(NULL
, &rows
);
434 if (symbol_conf
.use_callchain
)
435 self
->tree
= newtCheckboxTreeMulti(0, 0, rows
- 5, seq
,
438 self
->tree
= newtListbox(0, 0, rows
- 5,
440 NEWT_FLAG_RETURNEXIT
));
442 newtComponentAddCallback(self
->tree
, hist_browser__selection
,
445 progress
= ui_progress__new("Adding entries to the browser...", nr_hists
);
446 if (progress
== NULL
)
450 for (nd
= rb_first(hists
); nd
; nd
= rb_next(nd
)) {
451 struct hist_entry
*h
= rb_entry(nd
, struct hist_entry
, rb_node
);
457 len
= hist_entry__append_browser(h
, self
->tree
, session_total
);
460 if (symbol_conf
.use_callchain
)
461 hist_entry__append_callchain_browser(h
, self
->tree
,
462 session_total
, idx
++);
465 ui_progress__update(progress
, curr_hist
);
468 ui_progress__delete(progress
);
470 newtGetScreenSize(&cols
, &rows
);
475 if (!symbol_conf
.use_callchain
)
476 newtListboxSetWidth(self
->tree
, max_len
);
478 newtCenteredWindow(max_len
+ (symbol_conf
.use_callchain
? 5 : 0),
480 self
->form
= newt_form__new();
481 if (self
->form
== NULL
)
484 newtFormAddHotKey(self
->form
, 'A');
485 newtFormAddHotKey(self
->form
, 'a');
486 newtFormAddHotKey(self
->form
, NEWT_KEY_RIGHT
);
487 newtFormAddComponents(self
->form
, self
->tree
, NULL
);
488 self
->selection
= newt__symbol_tree_get_current(self
->tree
);
498 static u64
hists__filter_by_dso(struct rb_root
*hists
, struct dso
*dso
,
506 for (nd
= rb_first(hists
); nd
; nd
= rb_next(nd
)) {
507 struct hist_entry
*h
= rb_entry(nd
, struct hist_entry
, rb_node
);
509 if (dso
!= NULL
&& (h
->ms
.map
== NULL
|| h
->ms
.map
->dso
!= dso
)) {
510 h
->filtered
|= (1 << HIST_FILTER__DSO
);
513 h
->filtered
&= ~(1 << HIST_FILTER__DSO
);
515 *session_total
+= h
->count
;
521 static u64
hists__filter_by_thread(struct rb_root
*hists
, const struct thread
*thread
,
529 for (nd
= rb_first(hists
); nd
; nd
= rb_next(nd
)) {
530 struct hist_entry
*h
= rb_entry(nd
, struct hist_entry
, rb_node
);
532 if (thread
!= NULL
&& h
->thread
!= thread
) {
533 h
->filtered
|= (1 << HIST_FILTER__THREAD
);
536 h
->filtered
&= ~(1 << HIST_FILTER__THREAD
);
538 *session_total
+= h
->count
;
544 static struct thread
*hist_browser__selected_thread(struct hist_browser
*self
)
548 if (!symbol_conf
.use_callchain
)
551 indexes
= newtCheckboxTreeFindItem(self
->tree
, (void *)self
->selection
);
553 bool is_hist_entry
= indexes
[1] == NEWT_ARG_LAST
;
560 return *(struct thread
**)(self
->selection
+ 1);
563 int perf_session__browse_hists(struct rb_root
*hists
, u64 nr_hists
,
564 u64 session_total
, const char *helpline
,
565 const char *input_name
)
567 struct newtExitStruct es
;
568 bool dso_filtered
= false, thread_filtered
= false;
570 struct hist_browser
*browser
= hist_browser__new();
575 newtPushHelpLine(helpline
);
577 if (hist_browser__populate(browser
, hists
, nr_hists
, session_total
) < 0)
581 const struct thread
*thread
;
583 int nr_options
= 0, choice
= 0, i
,
584 annotate
= -2, zoom_dso
= -2, zoom_thread
= -2;
586 newtFormRun(browser
->form
, &es
);
587 if (es
.reason
== NEWT_EXIT_HOTKEY
) {
588 if (toupper(es
.u
.key
) == 'A')
590 if (es
.u
.key
== NEWT_KEY_ESCAPE
||
591 toupper(es
.u
.key
) == 'Q' ||
592 es
.u
.key
== CTRL('c')) {
593 if (dialog_yesno("Do you really want to exit?"))
600 if (browser
->selection
->sym
!= NULL
&&
601 asprintf(&options
[nr_options
], "Annotate %s",
602 browser
->selection
->sym
->name
) > 0)
603 annotate
= nr_options
++;
605 if (browser
->selection
->map
!= NULL
&&
606 asprintf(&options
[nr_options
], "Zoom %s %s DSO",
607 dso_filtered
? "out of" : "into",
608 (browser
->selection
->map
->dso
->kernel
? "the Kernel" :
609 browser
->selection
->map
->dso
->short_name
)) > 0)
610 zoom_dso
= nr_options
++;
612 thread
= hist_browser__selected_thread(browser
);
613 if (thread
!= NULL
&&
614 asprintf(&options
[nr_options
], "Zoom %s %s(%d) thread",
615 (thread_filtered
? "out of" : "into"),
616 (thread
->comm_set
? thread
->comm
: ""), thread
->pid
) > 0)
617 zoom_thread
= nr_options
++;
619 options
[nr_options
++] = (char *)"Exit";
621 choice
= popup_menu(nr_options
, options
);
623 for (i
= 0; i
< nr_options
- 1; ++i
)
626 if (choice
== nr_options
- 1)
632 if (choice
== annotate
) {
633 if (browser
->selection
->map
->dso
->origin
== DSO__ORIG_KERNEL
) {
635 newtPushHelpLine("No vmlinux file found, can't "
636 "annotate with just a "
640 map_symbol__annotate_browser(browser
->selection
,
642 } else if (choice
== zoom_dso
) {
643 nr_hists
= hists__filter_by_dso(hists
,
644 (dso_filtered
? NULL
:
645 browser
->selection
->map
->dso
),
647 dso_filtered
= !dso_filtered
;
648 if (hist_browser__populate(browser
, hists
, nr_hists
, session_total
) < 0)
650 } else if (choice
== zoom_thread
) {
651 nr_hists
= hists__filter_by_thread(hists
,
652 (thread_filtered
? NULL
: thread
),
654 thread_filtered
= !thread_filtered
;
655 if (hist_browser__populate(browser
, hists
, nr_hists
, session_total
) < 0)
661 hist_browser__delete(browser
);
665 void setup_browser(void)
673 newtPushHelpLine(" ");
676 void exit_browser(bool wait_for_ok
)
680 char title
[] = "Fatal Error", ok
[] = "Ok";
681 newtWinMessage(title
, ok
, browser__last_msg
);