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);
32 * When debugging newt problems it was useful to be able to "unroll"
33 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
34 * a source file with the sequence of calls to these methods, to then
35 * tweak the arrays to get the intended results, so I'm keeping this code
36 * here, may be useful again in the future.
40 static void newt_checkbox_tree__add(newtComponent tree, const char *str,
41 void *priv, int *indexes)
44 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
45 int i = 0, len = 40 - strlen(str);
48 "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
49 len, len, " ", str, priv);
50 while (indexes[i] != NEWT_ARG_LAST) {
51 if (indexes[i] != NEWT_ARG_APPEND)
52 fprintf(stderr, " %d,", indexes[i]);
54 fprintf(stderr, " %s,", "NEWT_ARG_APPEND");
57 fprintf(stderr, " %s", " NEWT_ARG_LAST);\n");
60 newtCheckboxTreeAddArray(tree, str, priv, 0, indexes);
63 static char *callchain_list__sym_name(struct callchain_list *self,
64 char *bf, size_t bfsize)
67 return self->sym->name;
69 snprintf(bf, bfsize, "%#Lx", self->ip);
73 static void __callchain__append_graph_browser(struct callchain_node *self,
74 newtComponent tree, u64 total,
75 int *indexes, int depth)
78 u64 new_total, remaining;
81 if (callchain_param.mode == CHAIN_GRAPH_REL)
82 new_total = self->children_hit;
86 remaining = new_total;
87 node = rb_first(&self->rb_root);
89 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
90 struct rb_node *next = rb_next(node);
91 u64 cumul = cumul_hits(child);
92 struct callchain_list *chain;
93 int first = true, printed = 0;
97 indexes[depth] = NEWT_ARG_APPEND;
98 indexes[depth + 1] = NEWT_ARG_LAST;
100 list_for_each_entry(chain, &child->val, list) {
101 char ipstr[BITS_PER_LONG / 4 + 1],
103 const char *str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
106 double percent = cumul * 100.0 / new_total;
109 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
110 str = "Not enough memory!";
114 indexes[depth] = idx;
115 indexes[depth + 1] = NEWT_ARG_APPEND;
116 indexes[depth + 2] = NEWT_ARG_LAST;
119 newt_checkbox_tree__add(tree, str, chain->sym, indexes);
124 indexes[depth] = idx;
126 indexes[depth + 1] = chain_idx;
129 __callchain__append_graph_browser(child, tree, new_total, indexes,
130 depth + (chain_idx != -1 ? 2 : 1));
135 static void callchain__append_graph_browser(struct callchain_node *self,
136 newtComponent tree, u64 total,
137 int *indexes, int parent_idx)
139 struct callchain_list *chain;
142 indexes[1] = NEWT_ARG_APPEND;
143 indexes[2] = NEWT_ARG_LAST;
145 list_for_each_entry(chain, &self->val, list) {
146 char ipstr[BITS_PER_LONG / 4 + 1], *str;
148 if (chain->ip >= PERF_CONTEXT_MAX)
151 if (!i++ && sort__first_dimension == SORT_SYM)
154 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
155 newt_checkbox_tree__add(tree, str, chain->sym, indexes);
158 indexes[1] = parent_idx;
159 indexes[2] = NEWT_ARG_APPEND;
160 indexes[3] = NEWT_ARG_LAST;
161 __callchain__append_graph_browser(self, tree, total, indexes, 2);
164 static void hist_entry__append_callchain_browser(struct hist_entry *self,
165 newtComponent tree, u64 total, int parent_idx)
167 struct rb_node *rb_node;
168 int indexes[1024] = { [0] = parent_idx, };
170 struct callchain_node *chain;
172 rb_node = rb_first(&self->sorted_chain);
174 chain = rb_entry(rb_node, struct callchain_node, rb_node);
175 switch (callchain_param.mode) {
178 case CHAIN_GRAPH_ABS: /* falldown */
179 case CHAIN_GRAPH_REL:
180 callchain__append_graph_browser(chain, tree, total, indexes, idx++);
186 rb_node = rb_next(rb_node);
191 * FIXME: get lib/string.c linked with perf somehow
193 static char *skip_spaces(const char *str)
195 while (isspace(*str))
200 static char *strim(char *s)
211 while (end >= s && isspace(*end))
218 static size_t hist_entry__append_browser(struct hist_entry *self,
219 newtComponent tree, u64 total)
224 if (symbol_conf.exclude_other && !self->parent)
227 fp = fmemopen(bf, sizeof(bf), "w");
231 hist_entry__fprintf(self, NULL, false, 0, fp, total);
235 * FIXME: We shouldn't need to trim, as the printing routines shouldn't
236 * add spaces it in the first place, the stdio output routines should
237 * call a __snprintf method instead of the current __print (that
238 * actually is a __fprintf) one, but get the raw string and _then_ add
239 * the newline, as this is a detail of stdio printing, not needed in
240 * other UIs, e.g. newt.
244 if (symbol_conf.use_callchain) {
247 indexes[0] = NEWT_ARG_APPEND;
248 indexes[1] = NEWT_ARG_LAST;
249 newt_checkbox_tree__add(tree, s, self->sym, indexes);
251 newtListboxAppendEntry(tree, s, self->sym);
256 static void symbol__annotate_browser(const struct symbol *self)
260 newtComponent form, tree;
261 struct newtExitStruct es;
263 size_t line_len, max_line_len = 0;
264 size_t max_usable_width;
270 if (asprintf(&str, "perf annotate %s 2>&1 | expand", self->name) < 0)
273 fp = popen(str, "r");
277 newtPushHelpLine("Press ESC to exit");
278 newtGetScreenSize(&cols, &rows);
279 tree = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL);
282 if (getline(&line, &line_len, fp) < 0 || !line_len)
284 while (line_len != 0 && isspace(line[line_len - 1]))
285 line[--line_len] = '\0';
287 if (line_len > max_line_len)
288 max_line_len = line_len;
289 newtListboxAppendEntry(tree, line, NULL);
294 max_usable_width = cols - 22;
295 if (max_line_len > max_usable_width)
296 max_line_len = max_usable_width;
298 newtListboxSetWidth(tree, max_line_len);
300 newtCenteredWindow(max_line_len + 2, rows - 5, self->name);
301 form = newt_form__new();
302 newtFormAddComponents(form, tree, NULL);
304 newtFormRun(form, &es);
305 newtFormDestroy(form);
312 void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
313 const char *helpline)
315 struct sort_entry *se;
319 char *col_width = symbol_conf.col_width_list_str;
323 newtComponent form, tree;
324 struct newtExitStruct es;
326 snprintf(str, sizeof(str), "Samples: %Ld", session_total);
327 newtDrawRootText(0, 0, str);
328 newtPushHelpLine(helpline);
330 newtGetScreenSize(&cols, &rows);
332 if (symbol_conf.use_callchain)
333 tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
336 tree = newtListbox(0, 0, rows - 5, (NEWT_FLAG_SCROLL |
337 NEWT_FLAG_RETURNEXIT));
339 list_for_each_entry(se, &hist_entry__sort_list, list) {
342 width = strlen(se->header);
344 if (symbol_conf.col_width_list_str) {
346 *se->width = atoi(col_width);
347 col_width = strchr(col_width, ',');
352 *se->width = max(*se->width, width);
357 for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
358 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
359 int len = hist_entry__append_browser(h, tree, session_total);
362 if (symbol_conf.use_callchain) {
363 hist_entry__append_callchain_browser(h, tree, session_total, idx++);
372 if (!symbol_conf.use_callchain)
373 newtListboxSetWidth(tree, max_len);
375 newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0),
377 form = newt_form__new();
378 newtFormAddHotKey(form, 'A');
379 newtFormAddHotKey(form, 'a');
380 newtFormAddComponents(form, tree, NULL);
383 const struct symbol *selection;
385 newtFormRun(form, &es);
386 if (es.reason == NEWT_EXIT_HOTKEY &&
387 toupper(es.u.key) != 'A')
389 if (!symbol_conf.use_callchain)
390 selection = newtListboxGetCurrent(tree);
392 selection = newtCheckboxTreeGetCurrent(tree);
393 symbol__annotate_browser(selection);
396 newtFormDestroy(form);
400 static char browser__last_msg[1024];
402 int browser__show_help(const char *format, va_list ap)
407 ret = vsnprintf(browser__last_msg + backlog,
408 sizeof(browser__last_msg) - backlog, format, ap);
411 if (browser__last_msg[backlog - 1] == '\n') {
413 newtPushHelpLine(browser__last_msg);
421 void setup_browser(void)
429 newtPushHelpLine(" ");
432 void exit_browser(bool wait_for_ok)
436 char title[] = "Fatal Error", ok[] = "Ok";
437 newtWinMessage(title, ok, browser__last_msg);