aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/newt.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/newt.c')
-rw-r--r--tools/perf/util/newt.c291
1 files changed, 259 insertions, 32 deletions
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
index 3c2ef95d940a..12b229bb9dc1 100644
--- a/tools/perf/util/newt.c
+++ b/tools/perf/util/newt.c
@@ -28,11 +28,197 @@ static newtComponent newt_form__new(void)
28 return self; 28 return self;
29} 29}
30 30
31/*
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.
37 */
38#undef NEWT_DEBUG
39
40static void newt_checkbox_tree__add(newtComponent tree, const char *str,
41 void *priv, int *indexes)
42{
43#ifdef NEWT_DEBUG
44 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
45 int i = 0, len = 40 - strlen(str);
46
47 fprintf(stderr,
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]);
53 else
54 fprintf(stderr, " %s,", "NEWT_ARG_APPEND");
55 ++i;
56 }
57 fprintf(stderr, " %s", " NEWT_ARG_LAST);\n");
58 fflush(stderr);
59#endif
60 newtCheckboxTreeAddArray(tree, str, priv, 0, indexes);
61}
62
63static char *callchain_list__sym_name(struct callchain_list *self,
64 char *bf, size_t bfsize)
65{
66 if (self->sym)
67 return self->sym->name;
68
69 snprintf(bf, bfsize, "%#Lx", self->ip);
70 return bf;
71}
72
73static void __callchain__append_graph_browser(struct callchain_node *self,
74 newtComponent tree, u64 total,
75 int *indexes, int depth)
76{
77 struct rb_node *node;
78 u64 new_total, remaining;
79 int idx = 0;
80
81 if (callchain_param.mode == CHAIN_GRAPH_REL)
82 new_total = self->children_hit;
83 else
84 new_total = total;
85
86 remaining = new_total;
87 node = rb_first(&self->rb_root);
88 while (node) {
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;
94 int chain_idx = -1;
95 remaining -= cumul;
96
97 indexes[depth] = NEWT_ARG_APPEND;
98 indexes[depth + 1] = NEWT_ARG_LAST;
99
100 list_for_each_entry(chain, &child->val, list) {
101 char ipstr[BITS_PER_LONG / 4 + 1],
102 *alloc_str = NULL;
103 const char *str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
104
105 if (first) {
106 double percent = cumul * 100.0 / new_total;
107
108 first = false;
109 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
110 str = "Not enough memory!";
111 else
112 str = alloc_str;
113 } else {
114 indexes[depth] = idx;
115 indexes[depth + 1] = NEWT_ARG_APPEND;
116 indexes[depth + 2] = NEWT_ARG_LAST;
117 ++chain_idx;
118 }
119 newt_checkbox_tree__add(tree, str, chain->sym, indexes);
120 free(alloc_str);
121 ++printed;
122 }
123
124 indexes[depth] = idx;
125 if (chain_idx != -1)
126 indexes[depth + 1] = chain_idx;
127 if (printed != 0)
128 ++idx;
129 __callchain__append_graph_browser(child, tree, new_total, indexes,
130 depth + (chain_idx != -1 ? 2 : 1));
131 node = next;
132 }
133}
134
135static void callchain__append_graph_browser(struct callchain_node *self,
136 newtComponent tree, u64 total,
137 int *indexes, int parent_idx)
138{
139 struct callchain_list *chain;
140 int i = 0;
141
142 indexes[1] = NEWT_ARG_APPEND;
143 indexes[2] = NEWT_ARG_LAST;
144
145 list_for_each_entry(chain, &self->val, list) {
146 char ipstr[BITS_PER_LONG / 4 + 1], *str;
147
148 if (chain->ip >= PERF_CONTEXT_MAX)
149 continue;
150
151 if (!i++ && sort__first_dimension == SORT_SYM)
152 continue;
153
154 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
155 newt_checkbox_tree__add(tree, str, chain->sym, indexes);
156 }
157
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);
162}
163
164static void hist_entry__append_callchain_browser(struct hist_entry *self,
165 newtComponent tree, u64 total, int parent_idx)
166{
167 struct rb_node *rb_node;
168 int indexes[1024] = { [0] = parent_idx, };
169 int idx = 0;
170 struct callchain_node *chain;
171
172 rb_node = rb_first(&self->sorted_chain);
173 while (rb_node) {
174 chain = rb_entry(rb_node, struct callchain_node, rb_node);
175 switch (callchain_param.mode) {
176 case CHAIN_FLAT:
177 break;
178 case CHAIN_GRAPH_ABS: /* falldown */
179 case CHAIN_GRAPH_REL:
180 callchain__append_graph_browser(chain, tree, total, indexes, idx++);
181 break;
182 case CHAIN_NONE:
183 default:
184 break;
185 }
186 rb_node = rb_next(rb_node);
187 }
188}
189
190/*
191 * FIXME: get lib/string.c linked with perf somehow
192 */
193static char *skip_spaces(const char *str)
194{
195 while (isspace(*str))
196 ++str;
197 return (char *)str;
198}
199
200static char *strim(char *s)
201{
202 size_t size;
203 char *end;
204
205 s = skip_spaces(s);
206 size = strlen(s);
207 if (!size)
208 return s;
209
210 end = s + size - 1;
211 while (end >= s && isspace(*end))
212 end--;
213 *(end + 1) = '\0';
214
215 return s;
216}
217
31static size_t hist_entry__append_browser(struct hist_entry *self, 218static size_t hist_entry__append_browser(struct hist_entry *self,
32 newtComponent listbox, u64 total) 219 newtComponent tree, u64 total)
33{ 220{
34 char bf[1024]; 221 char bf[1024], *s;
35 size_t len;
36 FILE *fp; 222 FILE *fp;
37 223
38 if (symbol_conf.exclude_other && !self->parent) 224 if (symbol_conf.exclude_other && !self->parent)
@@ -42,28 +228,46 @@ static size_t hist_entry__append_browser(struct hist_entry *self,
42 if (fp == NULL) 228 if (fp == NULL)
43 return 0; 229 return 0;
44 230
45 len = hist_entry__fprintf(self, NULL, false, 0, fp, total); 231 hist_entry__fprintf(self, NULL, false, 0, fp, total);
46
47 fclose(fp); 232 fclose(fp);
48 newtListboxAppendEntry(listbox, bf, self); 233
49 return len; 234 /*
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.
241 */
242 s = strim(bf);
243
244 if (symbol_conf.use_callchain) {
245 int indexes[2];
246
247 indexes[0] = NEWT_ARG_APPEND;
248 indexes[1] = NEWT_ARG_LAST;
249 newt_checkbox_tree__add(tree, s, self->sym, indexes);
250 } else
251 newtListboxAppendEntry(tree, s, self->sym);
252
253 return strlen(s);
50} 254}
51 255
52static void hist_entry__annotate_browser(struct hist_entry *self) 256static void symbol__annotate_browser(const struct symbol *self)
53{ 257{
54 FILE *fp; 258 FILE *fp;
55 int cols, rows; 259 int cols, rows;
56 newtComponent form, listbox; 260 newtComponent form, tree;
57 struct newtExitStruct es; 261 struct newtExitStruct es;
58 char *str; 262 char *str;
59 size_t line_len, max_line_len = 0; 263 size_t line_len, max_line_len = 0;
60 size_t max_usable_width; 264 size_t max_usable_width;
61 char *line = NULL; 265 char *line = NULL;
62 266
63 if (self->sym == NULL) 267 if (self == NULL)
64 return; 268 return;
65 269
66 if (asprintf(&str, "perf annotate %s 2>&1 | expand", self->sym->name) < 0) 270 if (asprintf(&str, "perf annotate %s 2>&1 | expand", self->name) < 0)
67 return; 271 return;
68 272
69 fp = popen(str, "r"); 273 fp = popen(str, "r");
@@ -72,7 +276,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self)
72 276
73 newtPushHelpLine("Press ESC to exit"); 277 newtPushHelpLine("Press ESC to exit");
74 newtGetScreenSize(&cols, &rows); 278 newtGetScreenSize(&cols, &rows);
75 listbox = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL); 279 tree = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL);
76 280
77 while (!feof(fp)) { 281 while (!feof(fp)) {
78 if (getline(&line, &line_len, fp) < 0 || !line_len) 282 if (getline(&line, &line_len, fp) < 0 || !line_len)
@@ -82,7 +286,7 @@ static void hist_entry__annotate_browser(struct hist_entry *self)
82 286
83 if (line_len > max_line_len) 287 if (line_len > max_line_len)
84 max_line_len = line_len; 288 max_line_len = line_len;
85 newtListboxAppendEntry(listbox, line, NULL); 289 newtListboxAppendEntry(tree, line, NULL);
86 } 290 }
87 fclose(fp); 291 fclose(fp);
88 free(line); 292 free(line);
@@ -91,11 +295,11 @@ static void hist_entry__annotate_browser(struct hist_entry *self)
91 if (max_line_len > max_usable_width) 295 if (max_line_len > max_usable_width)
92 max_line_len = max_usable_width; 296 max_line_len = max_usable_width;
93 297
94 newtListboxSetWidth(listbox, max_line_len); 298 newtListboxSetWidth(tree, max_line_len);
95 299
96 newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name); 300 newtCenteredWindow(max_line_len + 2, rows - 5, self->name);
97 form = newt_form__new(); 301 form = newt_form__new();
98 newtFormAddComponents(form, listbox, NULL); 302 newtFormAddComponents(form, tree, NULL);
99 303
100 newtFormRun(form, &es); 304 newtFormRun(form, &es);
101 newtFormDestroy(form); 305 newtFormDestroy(form);
@@ -110,25 +314,27 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
110{ 314{
111 struct sort_entry *se; 315 struct sort_entry *se;
112 struct rb_node *nd; 316 struct rb_node *nd;
317 char seq[] = ".";
113 unsigned int width; 318 unsigned int width;
114 char *col_width = symbol_conf.col_width_list_str; 319 char *col_width = symbol_conf.col_width_list_str;
115 int rows; 320 int rows, cols, idx;
116 size_t max_len = 0; 321 int max_len = 0;
117 char str[1024]; 322 char str[1024];
118 newtComponent form, listbox; 323 newtComponent form, tree;
119 struct newtExitStruct es; 324 struct newtExitStruct es;
120 325
121 snprintf(str, sizeof(str), "Samples: %Ld", session_total); 326 snprintf(str, sizeof(str), "Samples: %Ld", session_total);
122 newtDrawRootText(0, 0, str); 327 newtDrawRootText(0, 0, str);
123 newtPushHelpLine(helpline); 328 newtPushHelpLine(helpline);
124 329
125 newtGetScreenSize(NULL, &rows); 330 newtGetScreenSize(&cols, &rows);
126
127 form = newt_form__new();
128 331
129 listbox = newtListbox(1, 1, rows - 2, (NEWT_FLAG_SCROLL | 332 if (symbol_conf.use_callchain)
130 NEWT_FLAG_BORDER | 333 tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
131 NEWT_FLAG_RETURNEXIT)); 334 NEWT_FLAG_SCROLL);
335 else
336 tree = newtListbox(0, 0, rows - 5, (NEWT_FLAG_SCROLL |
337 NEWT_FLAG_RETURNEXIT));
132 338
133 list_for_each_entry(se, &hist_entry__sort_list, list) { 339 list_for_each_entry(se, &hist_entry__sort_list, list) {
134 if (se->elide) 340 if (se->elide)
@@ -147,27 +353,48 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
147 } 353 }
148 } 354 }
149 355
356 idx = 0;
150 for (nd = rb_first(hists); nd; nd = rb_next(nd)) { 357 for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
151 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 358 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
152 size_t len = hist_entry__append_browser(h, listbox, session_total); 359 int len = hist_entry__append_browser(h, tree, session_total);
153 if (len > max_len) 360 if (len > max_len)
154 max_len = len; 361 max_len = len;
362 if (symbol_conf.use_callchain) {
363 hist_entry__append_callchain_browser(h, tree, session_total, idx++);
364 if (idx > 3300)
365 break;
366 }
155 } 367 }
156 368
157 newtListboxSetWidth(listbox, max_len); 369 if (max_len > cols)
158 newtFormAddComponents(form, listbox, NULL); 370 max_len = cols - 3;
371
372 if (!symbol_conf.use_callchain)
373 newtListboxSetWidth(tree, max_len);
374
375 newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0),
376 rows - 5, "Report");
377 form = newt_form__new();
378 newtFormAddHotKey(form, 'A');
379 newtFormAddHotKey(form, 'a');
380 newtFormAddComponents(form, tree, NULL);
159 381
160 while (1) { 382 while (1) {
161 struct hist_entry *selection; 383 const struct symbol *selection;
162 384
163 newtFormRun(form, &es); 385 newtFormRun(form, &es);
164 if (es.reason == NEWT_EXIT_HOTKEY) 386 if (es.reason == NEWT_EXIT_HOTKEY &&
387 toupper(es.u.key) != 'A')
165 break; 388 break;
166 selection = newtListboxGetCurrent(listbox); 389 if (!symbol_conf.use_callchain)
167 hist_entry__annotate_browser(selection); 390 selection = newtListboxGetCurrent(tree);
391 else
392 selection = newtCheckboxTreeGetCurrent(tree);
393 symbol__annotate_browser(selection);
168 } 394 }
169 395
170 newtFormDestroy(form); 396 newtFormDestroy(form);
397 newtPopWindow();
171} 398}
172 399
173static char browser__last_msg[1024]; 400static char browser__last_msg[1024];