diff options
-rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 112 |
1 files changed, 106 insertions, 6 deletions
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index c17611fb5c0b..2fc1ba3a4680 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
@@ -58,6 +58,11 @@ static char callchain_list__folded(const struct callchain_list *self) | |||
58 | return map_symbol__folded(&self->ms); | 58 | return map_symbol__folded(&self->ms); |
59 | } | 59 | } |
60 | 60 | ||
61 | static void map_symbol__set_folding(struct map_symbol *self, bool unfold) | ||
62 | { | ||
63 | self->unfolded = unfold ? self->has_children : false; | ||
64 | } | ||
65 | |||
61 | static int callchain_node__count_rows_rb_tree(struct callchain_node *self) | 66 | static int callchain_node__count_rows_rb_tree(struct callchain_node *self) |
62 | { | 67 | { |
63 | int n = 0; | 68 | int n = 0; |
@@ -196,11 +201,98 @@ static bool hist_browser__toggle_fold(struct hist_browser *self) | |||
196 | return false; | 201 | return false; |
197 | } | 202 | } |
198 | 203 | ||
204 | static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold) | ||
205 | { | ||
206 | int n = 0; | ||
207 | struct rb_node *nd; | ||
208 | |||
209 | for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { | ||
210 | struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); | ||
211 | struct callchain_list *chain; | ||
212 | bool has_children = false; | ||
213 | |||
214 | list_for_each_entry(chain, &child->val, list) { | ||
215 | ++n; | ||
216 | map_symbol__set_folding(&chain->ms, unfold); | ||
217 | has_children = chain->ms.has_children; | ||
218 | } | ||
219 | |||
220 | if (has_children) | ||
221 | n += callchain_node__set_folding_rb_tree(child, unfold); | ||
222 | } | ||
223 | |||
224 | return n; | ||
225 | } | ||
226 | |||
227 | static int callchain_node__set_folding(struct callchain_node *node, bool unfold) | ||
228 | { | ||
229 | struct callchain_list *chain; | ||
230 | bool has_children = false; | ||
231 | int n = 0; | ||
232 | |||
233 | list_for_each_entry(chain, &node->val, list) { | ||
234 | ++n; | ||
235 | map_symbol__set_folding(&chain->ms, unfold); | ||
236 | has_children = chain->ms.has_children; | ||
237 | } | ||
238 | |||
239 | if (has_children) | ||
240 | n += callchain_node__set_folding_rb_tree(node, unfold); | ||
241 | |||
242 | return n; | ||
243 | } | ||
244 | |||
245 | static int callchain__set_folding(struct rb_root *chain, bool unfold) | ||
246 | { | ||
247 | struct rb_node *nd; | ||
248 | int n = 0; | ||
249 | |||
250 | for (nd = rb_first(chain); nd; nd = rb_next(nd)) { | ||
251 | struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); | ||
252 | n += callchain_node__set_folding(node, unfold); | ||
253 | } | ||
254 | |||
255 | return n; | ||
256 | } | ||
257 | |||
258 | static void hist_entry__set_folding(struct hist_entry *self, bool unfold) | ||
259 | { | ||
260 | hist_entry__init_have_children(self); | ||
261 | map_symbol__set_folding(&self->ms, unfold); | ||
262 | |||
263 | if (self->ms.has_children) { | ||
264 | int n = callchain__set_folding(&self->sorted_chain, unfold); | ||
265 | self->nr_rows = unfold ? n : 0; | ||
266 | } else | ||
267 | self->nr_rows = 0; | ||
268 | } | ||
269 | |||
270 | static void hists__set_folding(struct hists *self, bool unfold) | ||
271 | { | ||
272 | struct rb_node *nd; | ||
273 | |||
274 | self->nr_entries = 0; | ||
275 | |||
276 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { | ||
277 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); | ||
278 | hist_entry__set_folding(he, unfold); | ||
279 | self->nr_entries += 1 + he->nr_rows; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | static void hist_browser__set_folding(struct hist_browser *self, bool unfold) | ||
284 | { | ||
285 | hists__set_folding(self->hists, unfold); | ||
286 | self->b.nr_entries = self->hists->nr_entries; | ||
287 | /* Go to the start, we may be way after valid entries after a collapse */ | ||
288 | ui_browser__reset_index(&self->b); | ||
289 | } | ||
290 | |||
199 | static int hist_browser__run(struct hist_browser *self, const char *title) | 291 | static int hist_browser__run(struct hist_browser *self, const char *title) |
200 | { | 292 | { |
201 | int key; | 293 | int key; |
202 | int exit_keys[] = { 'a', '?', 'h', 'd', 'D', 't', NEWT_KEY_ENTER, | 294 | int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', |
203 | NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 0, }; | 295 | NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 0, }; |
204 | char str[256], unit; | 296 | char str[256], unit; |
205 | unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE]; | 297 | unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE]; |
206 | 298 | ||
@@ -237,7 +329,15 @@ static int hist_browser__run(struct hist_browser *self, const char *title) | |||
237 | self->b.top_idx, | 329 | self->b.top_idx, |
238 | h->row_offset, h->nr_rows); | 330 | h->row_offset, h->nr_rows); |
239 | } | 331 | } |
240 | continue; | 332 | break; |
333 | case 'C': | ||
334 | /* Collapse the whole world. */ | ||
335 | hist_browser__set_folding(self, false); | ||
336 | break; | ||
337 | case 'E': | ||
338 | /* Expand the whole world. */ | ||
339 | hist_browser__set_folding(self, true); | ||
340 | break; | ||
241 | case NEWT_KEY_ENTER: | 341 | case NEWT_KEY_ENTER: |
242 | if (hist_browser__toggle_fold(self)) | 342 | if (hist_browser__toggle_fold(self)) |
243 | break; | 343 | break; |
@@ -734,8 +834,6 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
734 | dso = browser->selection->map ? browser->selection->map->dso : NULL; | 834 | dso = browser->selection->map ? browser->selection->map->dso : NULL; |
735 | 835 | ||
736 | switch (key) { | 836 | switch (key) { |
737 | case NEWT_KEY_F1: | ||
738 | goto do_help; | ||
739 | case NEWT_KEY_TAB: | 837 | case NEWT_KEY_TAB: |
740 | case NEWT_KEY_UNTAB: | 838 | case NEWT_KEY_UNTAB: |
741 | /* | 839 | /* |
@@ -752,13 +850,15 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name) | |||
752 | goto zoom_dso; | 850 | goto zoom_dso; |
753 | case 't': | 851 | case 't': |
754 | goto zoom_thread; | 852 | goto zoom_thread; |
853 | case NEWT_KEY_F1: | ||
755 | case 'h': | 854 | case 'h': |
756 | case '?': | 855 | case '?': |
757 | do_help: | ||
758 | ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" | 856 | ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" |
759 | "<- Zoom out\n" | 857 | "<- Zoom out\n" |
760 | "a Annotate current symbol\n" | 858 | "a Annotate current symbol\n" |
761 | "h/?/F1 Show this window\n" | 859 | "h/?/F1 Show this window\n" |
860 | "C Collapse all callchains\n" | ||
861 | "E Expand all callchains\n" | ||
762 | "d Zoom into current DSO\n" | 862 | "d Zoom into current DSO\n" |
763 | "t Zoom into current Thread\n" | 863 | "t Zoom into current Thread\n" |
764 | "q/CTRL+C Exit browser"); | 864 | "q/CTRL+C Exit browser"); |