diff options
Diffstat (limited to 'tools/perf')
| -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"); |
