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
, const char *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
));
404 newtGetScreenSize(NULL
, &rows
);
406 if (symbol_conf
.use_callchain
)
407 self
->tree
= newtCheckboxTreeMulti(0, 0, rows
- 5, seq
,
410 self
->tree
= newtListbox(0, 0, rows
- 5,
412 NEWT_FLAG_RETURNEXIT
));
413 newtComponentAddCallback(self
->tree
, hist_browser__selection
,
420 static void hist_browser__delete(struct hist_browser
*self
)
422 newtFormDestroy(self
->form
);
427 static int hist_browser__populate(struct hist_browser
*self
, struct rb_root
*hists
,
428 u64 nr_hists
, u64 session_total
)
430 int max_len
= 0, idx
, cols
, rows
;
431 struct ui_progress
*progress
;
435 progress
= ui_progress__new("Adding entries to the browser...", nr_hists
);
436 if (progress
== NULL
)
440 for (nd
= rb_first(hists
); nd
; nd
= rb_next(nd
)) {
441 struct hist_entry
*h
= rb_entry(nd
, struct hist_entry
, rb_node
);
442 int len
= hist_entry__append_browser(h
, self
->tree
, session_total
);
445 if (symbol_conf
.use_callchain
)
446 hist_entry__append_callchain_browser(h
, self
->tree
,
447 session_total
, idx
++);
450 ui_progress__update(progress
, curr_hist
);
453 ui_progress__delete(progress
);
455 newtGetScreenSize(&cols
, &rows
);
460 if (!symbol_conf
.use_callchain
)
461 newtListboxSetWidth(self
->tree
, max_len
);
463 newtCenteredWindow(max_len
+ (symbol_conf
.use_callchain
? 5 : 0),
465 self
->form
= newt_form__new();
466 newtFormAddHotKey(self
->form
, 'A');
467 newtFormAddHotKey(self
->form
, 'a');
468 newtFormAddHotKey(self
->form
, NEWT_KEY_RIGHT
);
469 newtFormAddComponents(self
->form
, self
->tree
, NULL
);
470 self
->selection
= newt__symbol_tree_get_current(self
->tree
);
475 int perf_session__browse_hists(struct rb_root
*hists
, u64 nr_hists
,
476 u64 session_total
, const char *helpline
,
477 const char *input_name
)
479 struct newtExitStruct es
;
482 struct hist_browser
*browser
= hist_browser__new();
487 snprintf(str
, sizeof(str
), "Samples: %Ld", session_total
);
488 newtDrawRootText(0, 0, str
);
489 newtPushHelpLine(helpline
);
491 if (hist_browser__populate(browser
, hists
, nr_hists
, session_total
) < 0)
496 const char *options
[2];
497 int nr_options
= 0, choice
= 0;
499 newtFormRun(browser
->form
, &es
);
500 if (es
.reason
== NEWT_EXIT_HOTKEY
) {
501 if (toupper(es
.u
.key
) == 'A')
503 if (es
.u
.key
== NEWT_KEY_ESCAPE
||
504 toupper(es
.u
.key
) == 'Q' ||
505 es
.u
.key
== CTRL('c')) {
506 if (dialog_yesno("Do you really want to exit?"))
513 if (browser
->selection
->sym
!= NULL
) {
514 snprintf(annotate
, sizeof(annotate
),
515 "Annotate %s", browser
->selection
->sym
->name
);
516 options
[nr_options
++] = annotate
;
519 options
[nr_options
++] = "Exit";
520 choice
= popup_menu(nr_options
, options
);
521 if (choice
== nr_options
- 1)
524 if (browser
->selection
->sym
!= NULL
&& choice
>= 0) {
525 if (browser
->selection
->map
->dso
->origin
== DSO__ORIG_KERNEL
) {
527 newtPushHelpLine("No vmlinux file found, can't "
528 "annotate with just a "
532 map_symbol__annotate_browser(browser
->selection
,
538 hist_browser__delete(browser
);
542 void setup_browser(void)
550 newtPushHelpLine(" ");
553 void exit_browser(bool wait_for_ok
)
557 char title
[] = "Fatal Error", ok
[] = "Ok";
558 newtWinMessage(title
, ok
, browser__last_msg
);
This page took 0.049606 seconds and 6 git commands to generate.