aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-08-25 16:18:35 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-08-25 16:18:35 -0400
commit3c916cc28ca31892d96215eaf99c1d592884961d (patch)
tree93c3e3237b9b6afdb64d3fb99c6d681010c682a7 /tools
parent163caed90203a7cab66326ce2be138715dc7c5da (diff)
perf hists browser: Introduce "expand/collapse all callchains" action
When looking at a callchains enabled perf data file one can find it tiresome to start with all callchains collapsed and then to have to go one by one expanding them. So associate 'E' with "Expand all callchains" and 'C' with "Collapse all callchains". This way now one can have the top level view and then switch to/from having all callchains expanded. More work is needed to allow expanding just from one branch down to its leaves. Reported-by: Christoph Hellwig <hch@infradead.org> Cc: Christoph Hellwig <hch@infradead.org> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/ui/browsers/hists.c112
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
61static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
62{
63 self->unfolded = unfold ? self->has_children : false;
64}
65
61static int callchain_node__count_rows_rb_tree(struct callchain_node *self) 66static 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
204static 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
227static 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
245static 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
258static 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
270static 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
283static 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
199static int hist_browser__run(struct hist_browser *self, const char *title) 291static 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 '?':
757do_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");