7 #include <sys/ttydefaults.h>
15 static void newt_form__set_exit_keys(newtComponent self
)
17 newtFormAddHotKey(self
, NEWT_KEY_ESCAPE
);
18 newtFormAddHotKey(self
, 'Q');
19 newtFormAddHotKey(self
, 'q');
20 newtFormAddHotKey(self
, CTRL('c'));
23 static newtComponent
newt_form__new(void)
25 newtComponent self
= newtForm(NULL
, NULL
, 0);
27 newt_form__set_exit_keys(self
);
31 static int popup_menu(int argc
, const char *argv
[])
33 struct newtExitStruct es
;
34 int i
, rc
= -1, max_len
= 5;
35 newtComponent listbox
, form
= newt_form__new();
40 listbox
= newtListbox(0, 0, argc
, NEWT_FLAG_RETURNEXIT
);
42 goto out_destroy_form
;
44 newtFormAddComponents(form
, listbox
, NULL
);
46 for (i
= 0; i
< argc
; ++i
) {
47 int len
= strlen(argv
[i
]);
50 if (newtListboxAddEntry(listbox
, argv
[i
], (void *)(long)i
))
51 goto out_destroy_form
;
54 newtCenteredWindow(max_len
, argc
, NULL
);
55 newtFormRun(form
, &es
);
56 rc
= newtListboxGetCurrent(listbox
) - NULL
;
57 if (es
.reason
== NEWT_EXIT_HOTKEY
)
61 newtFormDestroy(form
);
65 static bool dialog_yesno(const char *msg
)
67 /* newtWinChoice should really be accepting const char pointers... */
68 char yes
[] = "Yes", no
[] = "No";
69 return newtWinChoice(NULL
, no
, yes
, (char *)msg
) == 2;
73 * When debugging newt problems it was useful to be able to "unroll"
74 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
75 * a source file with the sequence of calls to these methods, to then
76 * tweak the arrays to get the intended results, so I'm keeping this code
77 * here, may be useful again in the future.
81 static void newt_checkbox_tree__add(newtComponent tree
, const char *str
,
82 void *priv
, int *indexes
)
85 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
86 int i
= 0, len
= 40 - strlen(str
);
89 "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
90 len
, len
, " ", str
, priv
);
91 while (indexes
[i
] != NEWT_ARG_LAST
) {
92 if (indexes
[i
] != NEWT_ARG_APPEND
)
93 fprintf(stderr
, " %d,", indexes
[i
]);
95 fprintf(stderr
, " %s,", "NEWT_ARG_APPEND");
98 fprintf(stderr
, " %s", " NEWT_ARG_LAST);\n");
101 newtCheckboxTreeAddArray(tree
, str
, priv
, 0, indexes
);
104 static char *callchain_list__sym_name(struct callchain_list
*self
,
105 char *bf
, size_t bfsize
)
108 return self
->sym
->name
;
110 snprintf(bf
, bfsize
, "%#Lx", self
->ip
);
114 static void __callchain__append_graph_browser(struct callchain_node
*self
,
115 newtComponent tree
, u64 total
,
116 int *indexes
, int depth
)
118 struct rb_node
*node
;
119 u64 new_total
, remaining
;
122 if (callchain_param
.mode
== CHAIN_GRAPH_REL
)
123 new_total
= self
->children_hit
;
127 remaining
= new_total
;
128 node
= rb_first(&self
->rb_root
);
130 struct callchain_node
*child
= rb_entry(node
, struct callchain_node
, rb_node
);
131 struct rb_node
*next
= rb_next(node
);
132 u64 cumul
= cumul_hits(child
);
133 struct callchain_list
*chain
;
134 int first
= true, printed
= 0;
138 indexes
[depth
] = NEWT_ARG_APPEND
;
139 indexes
[depth
+ 1] = NEWT_ARG_LAST
;
141 list_for_each_entry(chain
, &child
->val
, list
) {
142 char ipstr
[BITS_PER_LONG
/ 4 + 1],
144 const char *str
= callchain_list__sym_name(chain
, ipstr
, sizeof(ipstr
));
147 double percent
= cumul
* 100.0 / new_total
;
150 if (asprintf(&alloc_str
, "%2.2f%% %s", percent
, str
) < 0)
151 str
= "Not enough memory!";
155 indexes
[depth
] = idx
;
156 indexes
[depth
+ 1] = NEWT_ARG_APPEND
;
157 indexes
[depth
+ 2] = NEWT_ARG_LAST
;
160 newt_checkbox_tree__add(tree
, str
, chain
->sym
, indexes
);
165 indexes
[depth
] = idx
;
167 indexes
[depth
+ 1] = chain_idx
;
170 __callchain__append_graph_browser(child
, tree
, new_total
, indexes
,
171 depth
+ (chain_idx
!= -1 ? 2 : 1));
176 static void callchain__append_graph_browser(struct callchain_node
*self
,
177 newtComponent tree
, u64 total
,
178 int *indexes
, int parent_idx
)
180 struct callchain_list
*chain
;
183 indexes
[1] = NEWT_ARG_APPEND
;
184 indexes
[2] = NEWT_ARG_LAST
;
186 list_for_each_entry(chain
, &self
->val
, list
) {
187 char ipstr
[BITS_PER_LONG
/ 4 + 1], *str
;
189 if (chain
->ip
>= PERF_CONTEXT_MAX
)
192 if (!i
++ && sort__first_dimension
== SORT_SYM
)
195 str
= callchain_list__sym_name(chain
, ipstr
, sizeof(ipstr
));
196 newt_checkbox_tree__add(tree
, str
, chain
->sym
, indexes
);
199 indexes
[1] = parent_idx
;
200 indexes
[2] = NEWT_ARG_APPEND
;
201 indexes
[3] = NEWT_ARG_LAST
;
202 __callchain__append_graph_browser(self
, tree
, total
, indexes
, 2);
205 static void hist_entry__append_callchain_browser(struct hist_entry
*self
,
206 newtComponent tree
, u64 total
, int parent_idx
)
208 struct rb_node
*rb_node
;
209 int indexes
[1024] = { [0] = parent_idx
, };
211 struct callchain_node
*chain
;
213 rb_node
= rb_first(&self
->sorted_chain
);
215 chain
= rb_entry(rb_node
, struct callchain_node
, rb_node
);
216 switch (callchain_param
.mode
) {
219 case CHAIN_GRAPH_ABS
: /* falldown */
220 case CHAIN_GRAPH_REL
:
221 callchain__append_graph_browser(chain
, tree
, total
, indexes
, idx
++);
227 rb_node
= rb_next(rb_node
);
232 * FIXME: get lib/string.c linked with perf somehow
234 static char *skip_spaces(const char *str
)
236 while (isspace(*str
))
241 static char *strim(char *s
)
252 while (end
>= s
&& isspace(*end
))
259 static size_t hist_entry__append_browser(struct hist_entry
*self
,
260 newtComponent tree
, u64 total
)
265 if (symbol_conf
.exclude_other
&& !self
->parent
)
268 fp
= fmemopen(bf
, sizeof(bf
), "w");
272 hist_entry__fprintf(self
, NULL
, false, 0, fp
, total
);
276 * FIXME: We shouldn't need to trim, as the printing routines shouldn't
277 * add spaces it in the first place, the stdio output routines should
278 * call a __snprintf method instead of the current __print (that
279 * actually is a __fprintf) one, but get the raw string and _then_ add
280 * the newline, as this is a detail of stdio printing, not needed in
281 * other UIs, e.g. newt.
285 if (symbol_conf
.use_callchain
) {
288 indexes
[0] = NEWT_ARG_APPEND
;
289 indexes
[1] = NEWT_ARG_LAST
;
290 newt_checkbox_tree__add(tree
, s
, self
->ms
.sym
, indexes
);
292 newtListboxAppendEntry(tree
, s
, self
->ms
.sym
);
297 static void symbol__annotate_browser(const struct symbol
*self
)
301 newtComponent form
, tree
;
302 struct newtExitStruct es
;
304 size_t line_len
, max_line_len
= 0;
305 size_t max_usable_width
;
311 if (asprintf(&str
, "perf annotate %s 2>&1 | expand", self
->name
) < 0)
314 fp
= popen(str
, "r");
318 newtPushHelpLine("Press ESC to exit");
319 newtGetScreenSize(&cols
, &rows
);
320 tree
= newtListbox(0, 0, rows
- 5, NEWT_FLAG_SCROLL
);
323 if (getline(&line
, &line_len
, fp
) < 0 || !line_len
)
325 while (line_len
!= 0 && isspace(line
[line_len
- 1]))
326 line
[--line_len
] = '\0';
328 if (line_len
> max_line_len
)
329 max_line_len
= line_len
;
330 newtListboxAppendEntry(tree
, line
, NULL
);
335 max_usable_width
= cols
- 22;
336 if (max_line_len
> max_usable_width
)
337 max_line_len
= max_usable_width
;
339 newtListboxSetWidth(tree
, max_line_len
);
341 newtCenteredWindow(max_line_len
+ 2, rows
- 5, self
->name
);
342 form
= newt_form__new();
343 newtFormAddComponents(form
, tree
, NULL
);
345 newtFormRun(form
, &es
);
346 newtFormDestroy(form
);
353 static const void *newt__symbol_tree_get_current(newtComponent self
)
355 if (symbol_conf
.use_callchain
)
356 return newtCheckboxTreeGetCurrent(self
);
357 return newtListboxGetCurrent(self
);
360 static void perf_session__selection(newtComponent self
, void *data
)
362 const struct symbol
**symbol_ptr
= data
;
363 *symbol_ptr
= newt__symbol_tree_get_current(self
);
366 void perf_session__browse_hists(struct rb_root
*hists
, u64 session_total
,
367 const char *helpline
)
369 struct sort_entry
*se
;
373 char *col_width
= symbol_conf
.col_width_list_str
;
377 newtComponent form
, tree
;
378 struct newtExitStruct es
;
379 const struct symbol
*selection
;
381 snprintf(str
, sizeof(str
), "Samples: %Ld", session_total
);
382 newtDrawRootText(0, 0, str
);
383 newtPushHelpLine(helpline
);
385 newtGetScreenSize(&cols
, &rows
);
387 if (symbol_conf
.use_callchain
)
388 tree
= newtCheckboxTreeMulti(0, 0, rows
- 5, seq
,
391 tree
= newtListbox(0, 0, rows
- 5, (NEWT_FLAG_SCROLL
|
392 NEWT_FLAG_RETURNEXIT
));
394 newtComponentAddCallback(tree
, perf_session__selection
, &selection
);
396 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
399 width
= strlen(se
->header
);
401 if (symbol_conf
.col_width_list_str
) {
403 *se
->width
= atoi(col_width
);
404 col_width
= strchr(col_width
, ',');
409 *se
->width
= max(*se
->width
, width
);
414 for (nd
= rb_first(hists
); nd
; nd
= rb_next(nd
)) {
415 struct hist_entry
*h
= rb_entry(nd
, struct hist_entry
, rb_node
);
416 int len
= hist_entry__append_browser(h
, tree
, session_total
);
419 if (symbol_conf
.use_callchain
) {
420 hist_entry__append_callchain_browser(h
, tree
, session_total
, idx
++);
429 if (!symbol_conf
.use_callchain
)
430 newtListboxSetWidth(tree
, max_len
);
432 newtCenteredWindow(max_len
+ (symbol_conf
.use_callchain
? 5 : 0),
434 form
= newt_form__new();
435 newtFormAddHotKey(form
, 'A');
436 newtFormAddHotKey(form
, 'a');
437 newtFormAddHotKey(form
, NEWT_KEY_RIGHT
);
438 newtFormAddComponents(form
, tree
, NULL
);
439 selection
= newt__symbol_tree_get_current(tree
);
443 const char *options
[2];
444 int nr_options
= 0, choice
;
446 newtFormRun(form
, &es
);
447 if (es
.reason
== NEWT_EXIT_HOTKEY
) {
448 if (toupper(es
.u
.key
) == 'A') {
449 symbol__annotate_browser(selection
);
452 if (es
.u
.key
== NEWT_KEY_ESCAPE
||
453 toupper(es
.u
.key
) == 'Q' ||
454 es
.u
.key
== CTRL('c')) {
455 if (dialog_yesno("Do you really want to exit?"))
462 if (selection
!= NULL
) {
463 snprintf(annotate
, sizeof(annotate
),
464 "Annotate %s", selection
->name
);
465 options
[nr_options
++] = annotate
;
468 options
[nr_options
++] = "Exit";
469 choice
= popup_menu(nr_options
, options
);
470 if (choice
== nr_options
- 1)
472 else if (selection
!= NULL
&& choice
>= 0)
473 symbol__annotate_browser(selection
);
476 newtFormDestroy(form
);
480 static char browser__last_msg
[1024];
482 int browser__show_help(const char *format
, va_list ap
)
487 ret
= vsnprintf(browser__last_msg
+ backlog
,
488 sizeof(browser__last_msg
) - backlog
, format
, ap
);
491 if (browser__last_msg
[backlog
- 1] == '\n') {
493 newtPushHelpLine(browser__last_msg
);
501 void setup_browser(void)
509 newtPushHelpLine(" ");
512 void exit_browser(bool wait_for_ok
)
516 char title
[] = "Fatal Error", ok
[] = "Ok";
517 newtWinMessage(title
, ok
, browser__last_msg
);
This page took 0.049632 seconds and 6 git commands to generate.