e283a6e6b6e051956575926ef824bdd76f8360fa
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 newtFormAddComponent(self
->form
, self
->scale
);
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 newtFormAddComponent(form
, listbox
);
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
, yes
, no
, (char *)msg
) == 1;
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 newtFormAddComponent(form
, tree
);
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
, const char *title
)
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
, const 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 static int hist_browser__title(char *bf
, size_t size
, const char *input_name
,
564 const struct dso
*dso
, const struct thread
*thread
)
569 printed
+= snprintf(bf
+ printed
, size
- printed
,
571 (thread
->comm_set
? thread
->comm
: ""),
574 printed
+= snprintf(bf
+ printed
, size
- printed
,
575 "%sDSO: %s", thread
? " " : "",
577 return printed
?: snprintf(bf
, size
, "Report: %s", input_name
);
580 int perf_session__browse_hists(struct rb_root
*hists
, u64 nr_hists
,
581 u64 session_total
, const char *helpline
,
582 const char *input_name
)
584 struct hist_browser
*browser
= hist_browser__new();
585 const struct thread
*thread_filter
= NULL
;
586 const struct dso
*dso_filter
= NULL
;
587 struct newtExitStruct es
;
594 newtPushHelpLine(helpline
);
596 hist_browser__title(msg
, sizeof(msg
), input_name
,
597 dso_filter
, thread_filter
);
598 if (hist_browser__populate(browser
, hists
, nr_hists
, session_total
, msg
) < 0)
602 const struct thread
*thread
;
603 const struct dso
*dso
;
605 int nr_options
= 0, choice
= 0, i
,
606 annotate
= -2, zoom_dso
= -2, zoom_thread
= -2;
608 newtFormRun(browser
->form
, &es
);
609 if (es
.reason
== NEWT_EXIT_HOTKEY
) {
610 if (toupper(es
.u
.key
) == 'A')
612 if (es
.u
.key
== NEWT_KEY_ESCAPE
||
613 toupper(es
.u
.key
) == 'Q' ||
614 es
.u
.key
== CTRL('c')) {
615 if (dialog_yesno("Do you really want to exit?"))
622 if (browser
->selection
->sym
!= NULL
&&
623 asprintf(&options
[nr_options
], "Annotate %s",
624 browser
->selection
->sym
->name
) > 0)
625 annotate
= nr_options
++;
627 thread
= hist_browser__selected_thread(browser
);
628 if (thread
!= NULL
&&
629 asprintf(&options
[nr_options
], "Zoom %s %s(%d) thread",
630 (thread_filter
? "out of" : "into"),
631 (thread
->comm_set
? thread
->comm
: ""),
633 zoom_thread
= nr_options
++;
635 dso
= browser
->selection
->map
? browser
->selection
->map
->dso
: NULL
;
637 asprintf(&options
[nr_options
], "Zoom %s %s DSO",
638 (dso_filter
? "out of" : "into"),
639 (dso
->kernel
? "the Kernel" : dso
->short_name
)) > 0)
640 zoom_dso
= nr_options
++;
642 options
[nr_options
++] = (char *)"Exit";
644 choice
= popup_menu(nr_options
, options
);
646 for (i
= 0; i
< nr_options
- 1; ++i
)
649 if (choice
== nr_options
- 1)
655 if (choice
== annotate
) {
656 if (browser
->selection
->map
->dso
->origin
== DSO__ORIG_KERNEL
) {
658 newtPushHelpLine("No vmlinux file found, can't "
659 "annotate with just a "
663 map_symbol__annotate_browser(browser
->selection
, input_name
);
664 } else if (choice
== zoom_dso
) {
669 snprintf(msg
, sizeof(msg
),
670 "To zoom out press -> + \"Zoom out of %s DSO\"",
671 dso
->kernel
? "the Kernel" : dso
->short_name
);
672 newtPushHelpLine(msg
);
675 nr_hists
= hists__filter_by_dso(hists
, dso_filter
, &session_total
);
676 hist_browser__title(msg
, sizeof(msg
), input_name
,
677 dso_filter
, thread_filter
);
678 if (hist_browser__populate(browser
, hists
, nr_hists
, session_total
, msg
) < 0)
680 } else if (choice
== zoom_thread
) {
683 thread_filter
= NULL
;
685 snprintf(msg
, sizeof(msg
),
686 "To zoom out press -> + \"Zoom out of %s(%d) thread\"",
687 (thread
->comm_set
? thread
->comm
: ""),
689 newtPushHelpLine(msg
);
690 thread_filter
= thread
;
692 nr_hists
= hists__filter_by_thread(hists
, thread_filter
, &session_total
);
693 hist_browser__title(msg
, sizeof(msg
), input_name
,
694 dso_filter
, thread_filter
);
695 if (hist_browser__populate(browser
, hists
, nr_hists
, session_total
, msg
) < 0)
701 hist_browser__delete(browser
);
705 void setup_browser(void)
713 newtPushHelpLine(" ");
716 void exit_browser(bool wait_for_ok
)
720 char title
[] = "Fatal Error", ok
[] = "Ok";
721 newtWinMessage(title
, ok
, browser__last_msg
);
This page took 0.081677 seconds and 4 git commands to generate.