1aca7a94dSNamhyung Kim #include <stdio.h> 2aca7a94dSNamhyung Kim #include "../libslang.h" 3aca7a94dSNamhyung Kim #include <stdlib.h> 4aca7a94dSNamhyung Kim #include <string.h> 5aca7a94dSNamhyung Kim #include <linux/rbtree.h> 6aca7a94dSNamhyung Kim 7aca7a94dSNamhyung Kim #include "../../util/evsel.h" 8aca7a94dSNamhyung Kim #include "../../util/evlist.h" 9aca7a94dSNamhyung Kim #include "../../util/hist.h" 10aca7a94dSNamhyung Kim #include "../../util/pstack.h" 11aca7a94dSNamhyung Kim #include "../../util/sort.h" 12aca7a94dSNamhyung Kim #include "../../util/util.h" 1368d80758SNamhyung Kim #include "../../arch/common.h" 14aca7a94dSNamhyung Kim 15aca7a94dSNamhyung Kim #include "../browser.h" 16aca7a94dSNamhyung Kim #include "../helpline.h" 17aca7a94dSNamhyung Kim #include "../util.h" 18aca7a94dSNamhyung Kim #include "../ui.h" 19aca7a94dSNamhyung Kim #include "map.h" 20aca7a94dSNamhyung Kim 21aca7a94dSNamhyung Kim struct hist_browser { 22aca7a94dSNamhyung Kim struct ui_browser b; 23aca7a94dSNamhyung Kim struct hists *hists; 24aca7a94dSNamhyung Kim struct hist_entry *he_selection; 25aca7a94dSNamhyung Kim struct map_symbol *selection; 26aff3f3f6SArnaldo Carvalho de Melo int print_seq; 27a7cb8863SArnaldo Carvalho de Melo bool show_dso; 28064f1981SNamhyung Kim float min_pcnt; 29064f1981SNamhyung Kim u64 nr_pcnt_entries; 30aca7a94dSNamhyung Kim }; 31aca7a94dSNamhyung Kim 32f5951d56SNamhyung Kim extern void hist_browser__init_hpp(void); 33f5951d56SNamhyung Kim 3405e8b080SArnaldo Carvalho de Melo static int hists__browser_title(struct hists *hists, char *bf, size_t size, 35aca7a94dSNamhyung Kim const char *ev_name); 36aca7a94dSNamhyung Kim 3705e8b080SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct hist_browser *browser) 38aca7a94dSNamhyung Kim { 39aca7a94dSNamhyung Kim /* 3 == +/- toggle symbol before actual hist_entry rendering */ 4005e8b080SArnaldo Carvalho de Melo browser->b.width = 3 + (hists__sort_list_width(browser->hists) + 41aca7a94dSNamhyung Kim sizeof("[k]")); 42aca7a94dSNamhyung Kim } 43aca7a94dSNamhyung Kim 4405e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser) 45aca7a94dSNamhyung Kim { 4605e8b080SArnaldo Carvalho de Melo browser->b.nr_entries = browser->hists->nr_entries; 4705e8b080SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(browser); 4805e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 49aca7a94dSNamhyung Kim } 50aca7a94dSNamhyung Kim 51aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded) 52aca7a94dSNamhyung Kim { 53aca7a94dSNamhyung Kim return unfolded ? '-' : '+'; 54aca7a94dSNamhyung Kim } 55aca7a94dSNamhyung Kim 5605e8b080SArnaldo Carvalho de Melo static char map_symbol__folded(const struct map_symbol *ms) 57aca7a94dSNamhyung Kim { 5805e8b080SArnaldo Carvalho de Melo return ms->has_children ? tree__folded_sign(ms->unfolded) : ' '; 59aca7a94dSNamhyung Kim } 60aca7a94dSNamhyung Kim 6105e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he) 62aca7a94dSNamhyung Kim { 6305e8b080SArnaldo Carvalho de Melo return map_symbol__folded(&he->ms); 64aca7a94dSNamhyung Kim } 65aca7a94dSNamhyung Kim 6605e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl) 67aca7a94dSNamhyung Kim { 6805e8b080SArnaldo Carvalho de Melo return map_symbol__folded(&cl->ms); 69aca7a94dSNamhyung Kim } 70aca7a94dSNamhyung Kim 7105e8b080SArnaldo Carvalho de Melo static void map_symbol__set_folding(struct map_symbol *ms, bool unfold) 72aca7a94dSNamhyung Kim { 7305e8b080SArnaldo Carvalho de Melo ms->unfolded = unfold ? ms->has_children : false; 74aca7a94dSNamhyung Kim } 75aca7a94dSNamhyung Kim 7605e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 77aca7a94dSNamhyung Kim { 78aca7a94dSNamhyung Kim int n = 0; 79aca7a94dSNamhyung Kim struct rb_node *nd; 80aca7a94dSNamhyung Kim 8105e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 82aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 83aca7a94dSNamhyung Kim struct callchain_list *chain; 84aca7a94dSNamhyung Kim char folded_sign = ' '; /* No children */ 85aca7a94dSNamhyung Kim 86aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 87aca7a94dSNamhyung Kim ++n; 88aca7a94dSNamhyung Kim /* We need this because we may not have children */ 89aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 90aca7a94dSNamhyung Kim if (folded_sign == '+') 91aca7a94dSNamhyung Kim break; 92aca7a94dSNamhyung Kim } 93aca7a94dSNamhyung Kim 94aca7a94dSNamhyung Kim if (folded_sign == '-') /* Have children and they're unfolded */ 95aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(child); 96aca7a94dSNamhyung Kim } 97aca7a94dSNamhyung Kim 98aca7a94dSNamhyung Kim return n; 99aca7a94dSNamhyung Kim } 100aca7a94dSNamhyung Kim 101aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 102aca7a94dSNamhyung Kim { 103aca7a94dSNamhyung Kim struct callchain_list *chain; 104aca7a94dSNamhyung Kim bool unfolded = false; 105aca7a94dSNamhyung Kim int n = 0; 106aca7a94dSNamhyung Kim 107aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 108aca7a94dSNamhyung Kim ++n; 109aca7a94dSNamhyung Kim unfolded = chain->ms.unfolded; 110aca7a94dSNamhyung Kim } 111aca7a94dSNamhyung Kim 112aca7a94dSNamhyung Kim if (unfolded) 113aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 114aca7a94dSNamhyung Kim 115aca7a94dSNamhyung Kim return n; 116aca7a94dSNamhyung Kim } 117aca7a94dSNamhyung Kim 118aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 119aca7a94dSNamhyung Kim { 120aca7a94dSNamhyung Kim struct rb_node *nd; 121aca7a94dSNamhyung Kim int n = 0; 122aca7a94dSNamhyung Kim 123aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 124aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 125aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 126aca7a94dSNamhyung Kim } 127aca7a94dSNamhyung Kim 128aca7a94dSNamhyung Kim return n; 129aca7a94dSNamhyung Kim } 130aca7a94dSNamhyung Kim 13105e8b080SArnaldo Carvalho de Melo static bool map_symbol__toggle_fold(struct map_symbol *ms) 132aca7a94dSNamhyung Kim { 13305e8b080SArnaldo Carvalho de Melo if (!ms) 134aca7a94dSNamhyung Kim return false; 135aca7a94dSNamhyung Kim 13605e8b080SArnaldo Carvalho de Melo if (!ms->has_children) 137aca7a94dSNamhyung Kim return false; 138aca7a94dSNamhyung Kim 13905e8b080SArnaldo Carvalho de Melo ms->unfolded = !ms->unfolded; 140aca7a94dSNamhyung Kim return true; 141aca7a94dSNamhyung Kim } 142aca7a94dSNamhyung Kim 14305e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 144aca7a94dSNamhyung Kim { 14505e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 146aca7a94dSNamhyung Kim 14705e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 148aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 149aca7a94dSNamhyung Kim struct callchain_list *chain; 150aca7a94dSNamhyung Kim bool first = true; 151aca7a94dSNamhyung Kim 152aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 153aca7a94dSNamhyung Kim if (first) { 154aca7a94dSNamhyung Kim first = false; 155aca7a94dSNamhyung Kim chain->ms.has_children = chain->list.next != &child->val || 156aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 157aca7a94dSNamhyung Kim } else 158aca7a94dSNamhyung Kim chain->ms.has_children = chain->list.next == &child->val && 159aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 160aca7a94dSNamhyung Kim } 161aca7a94dSNamhyung Kim 162aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 163aca7a94dSNamhyung Kim } 164aca7a94dSNamhyung Kim } 165aca7a94dSNamhyung Kim 16605e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children(struct callchain_node *node) 167aca7a94dSNamhyung Kim { 168aca7a94dSNamhyung Kim struct callchain_list *chain; 169aca7a94dSNamhyung Kim 17005e8b080SArnaldo Carvalho de Melo list_for_each_entry(chain, &node->val, list) 17105e8b080SArnaldo Carvalho de Melo chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); 172aca7a94dSNamhyung Kim 17305e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 174aca7a94dSNamhyung Kim } 175aca7a94dSNamhyung Kim 17605e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 177aca7a94dSNamhyung Kim { 178aca7a94dSNamhyung Kim struct rb_node *nd; 179aca7a94dSNamhyung Kim 18005e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 181aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 182aca7a94dSNamhyung Kim callchain_node__init_have_children(node); 183aca7a94dSNamhyung Kim } 184aca7a94dSNamhyung Kim } 185aca7a94dSNamhyung Kim 18605e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 187aca7a94dSNamhyung Kim { 18805e8b080SArnaldo Carvalho de Melo if (!he->init_have_children) { 18905e8b080SArnaldo Carvalho de Melo he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 19005e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 19105e8b080SArnaldo Carvalho de Melo he->init_have_children = true; 192aca7a94dSNamhyung Kim } 193aca7a94dSNamhyung Kim } 194aca7a94dSNamhyung Kim 19505e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 196aca7a94dSNamhyung Kim { 19705e8b080SArnaldo Carvalho de Melo if (map_symbol__toggle_fold(browser->selection)) { 19805e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 199aca7a94dSNamhyung Kim 200aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 20105e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries -= he->nr_rows; 202aca7a94dSNamhyung Kim 203aca7a94dSNamhyung Kim if (he->ms.unfolded) 204aca7a94dSNamhyung Kim he->nr_rows = callchain__count_rows(&he->sorted_chain); 205aca7a94dSNamhyung Kim else 206aca7a94dSNamhyung Kim he->nr_rows = 0; 20705e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries += he->nr_rows; 20805e8b080SArnaldo Carvalho de Melo browser->b.nr_entries = browser->hists->nr_entries; 209aca7a94dSNamhyung Kim 210aca7a94dSNamhyung Kim return true; 211aca7a94dSNamhyung Kim } 212aca7a94dSNamhyung Kim 213aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 214aca7a94dSNamhyung Kim return false; 215aca7a94dSNamhyung Kim } 216aca7a94dSNamhyung Kim 21705e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 218aca7a94dSNamhyung Kim { 219aca7a94dSNamhyung Kim int n = 0; 220aca7a94dSNamhyung Kim struct rb_node *nd; 221aca7a94dSNamhyung Kim 22205e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 223aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 224aca7a94dSNamhyung Kim struct callchain_list *chain; 225aca7a94dSNamhyung Kim bool has_children = false; 226aca7a94dSNamhyung Kim 227aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 228aca7a94dSNamhyung Kim ++n; 229aca7a94dSNamhyung Kim map_symbol__set_folding(&chain->ms, unfold); 230aca7a94dSNamhyung Kim has_children = chain->ms.has_children; 231aca7a94dSNamhyung Kim } 232aca7a94dSNamhyung Kim 233aca7a94dSNamhyung Kim if (has_children) 234aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 235aca7a94dSNamhyung Kim } 236aca7a94dSNamhyung Kim 237aca7a94dSNamhyung Kim return n; 238aca7a94dSNamhyung Kim } 239aca7a94dSNamhyung Kim 240aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 241aca7a94dSNamhyung Kim { 242aca7a94dSNamhyung Kim struct callchain_list *chain; 243aca7a94dSNamhyung Kim bool has_children = false; 244aca7a94dSNamhyung Kim int n = 0; 245aca7a94dSNamhyung Kim 246aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 247aca7a94dSNamhyung Kim ++n; 248aca7a94dSNamhyung Kim map_symbol__set_folding(&chain->ms, unfold); 249aca7a94dSNamhyung Kim has_children = chain->ms.has_children; 250aca7a94dSNamhyung Kim } 251aca7a94dSNamhyung Kim 252aca7a94dSNamhyung Kim if (has_children) 253aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 254aca7a94dSNamhyung Kim 255aca7a94dSNamhyung Kim return n; 256aca7a94dSNamhyung Kim } 257aca7a94dSNamhyung Kim 258aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 259aca7a94dSNamhyung Kim { 260aca7a94dSNamhyung Kim struct rb_node *nd; 261aca7a94dSNamhyung Kim int n = 0; 262aca7a94dSNamhyung Kim 263aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 264aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 265aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 266aca7a94dSNamhyung Kim } 267aca7a94dSNamhyung Kim 268aca7a94dSNamhyung Kim return n; 269aca7a94dSNamhyung Kim } 270aca7a94dSNamhyung Kim 27105e8b080SArnaldo Carvalho de Melo static void hist_entry__set_folding(struct hist_entry *he, bool unfold) 272aca7a94dSNamhyung Kim { 27305e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 27405e8b080SArnaldo Carvalho de Melo map_symbol__set_folding(&he->ms, unfold); 275aca7a94dSNamhyung Kim 27605e8b080SArnaldo Carvalho de Melo if (he->ms.has_children) { 27705e8b080SArnaldo Carvalho de Melo int n = callchain__set_folding(&he->sorted_chain, unfold); 27805e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 279aca7a94dSNamhyung Kim } else 28005e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 281aca7a94dSNamhyung Kim } 282aca7a94dSNamhyung Kim 28305e8b080SArnaldo Carvalho de Melo static void hists__set_folding(struct hists *hists, bool unfold) 284aca7a94dSNamhyung Kim { 285aca7a94dSNamhyung Kim struct rb_node *nd; 286aca7a94dSNamhyung Kim 28705e8b080SArnaldo Carvalho de Melo hists->nr_entries = 0; 288aca7a94dSNamhyung Kim 28905e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 290aca7a94dSNamhyung Kim struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 291aca7a94dSNamhyung Kim hist_entry__set_folding(he, unfold); 29205e8b080SArnaldo Carvalho de Melo hists->nr_entries += 1 + he->nr_rows; 293aca7a94dSNamhyung Kim } 294aca7a94dSNamhyung Kim } 295aca7a94dSNamhyung Kim 29605e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 297aca7a94dSNamhyung Kim { 29805e8b080SArnaldo Carvalho de Melo hists__set_folding(browser->hists, unfold); 29905e8b080SArnaldo Carvalho de Melo browser->b.nr_entries = browser->hists->nr_entries; 300aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 30105e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 302aca7a94dSNamhyung Kim } 303aca7a94dSNamhyung Kim 304aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 305aca7a94dSNamhyung Kim { 306aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 307aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 308aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 309aca7a94dSNamhyung Kim " perf top -r 80\n\n" 310aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 311aca7a94dSNamhyung Kim } 312aca7a94dSNamhyung Kim 313fa5df943SNamhyung Kim static void hist_browser__update_pcnt_entries(struct hist_browser *hb); 314fa5df943SNamhyung Kim 31505e8b080SArnaldo Carvalho de Melo static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 3169783adf7SNamhyung Kim struct hist_browser_timer *hbt) 317aca7a94dSNamhyung Kim { 318aca7a94dSNamhyung Kim int key; 319aca7a94dSNamhyung Kim char title[160]; 3209783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 321aca7a94dSNamhyung Kim 32205e8b080SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 32305e8b080SArnaldo Carvalho de Melo browser->b.nr_entries = browser->hists->nr_entries; 324064f1981SNamhyung Kim if (browser->min_pcnt) 325064f1981SNamhyung Kim browser->b.nr_entries = browser->nr_pcnt_entries; 326aca7a94dSNamhyung Kim 32705e8b080SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(browser); 32805e8b080SArnaldo Carvalho de Melo hists__browser_title(browser->hists, title, sizeof(title), ev_name); 329aca7a94dSNamhyung Kim 33005e8b080SArnaldo Carvalho de Melo if (ui_browser__show(&browser->b, title, 331aca7a94dSNamhyung Kim "Press '?' for help on key bindings") < 0) 332aca7a94dSNamhyung Kim return -1; 333aca7a94dSNamhyung Kim 334aca7a94dSNamhyung Kim while (1) { 33505e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 336aca7a94dSNamhyung Kim 337aca7a94dSNamhyung Kim switch (key) { 338fa5df943SNamhyung Kim case K_TIMER: { 339fa5df943SNamhyung Kim u64 nr_entries; 3409783adf7SNamhyung Kim hbt->timer(hbt->arg); 341fa5df943SNamhyung Kim 342fa5df943SNamhyung Kim if (browser->min_pcnt) { 343fa5df943SNamhyung Kim hist_browser__update_pcnt_entries(browser); 344fa5df943SNamhyung Kim nr_entries = browser->nr_pcnt_entries; 345fa5df943SNamhyung Kim } else { 346fa5df943SNamhyung Kim nr_entries = browser->hists->nr_entries; 347fa5df943SNamhyung Kim } 348fa5df943SNamhyung Kim 349fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 350aca7a94dSNamhyung Kim 35105e8b080SArnaldo Carvalho de Melo if (browser->hists->stats.nr_lost_warned != 35205e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]) { 35305e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 35405e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 35505e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 356aca7a94dSNamhyung Kim } 357aca7a94dSNamhyung Kim 35805e8b080SArnaldo Carvalho de Melo hists__browser_title(browser->hists, title, sizeof(title), ev_name); 35905e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 360aca7a94dSNamhyung Kim continue; 361fa5df943SNamhyung Kim } 362aca7a94dSNamhyung Kim case 'D': { /* Debug */ 363aca7a94dSNamhyung Kim static int seq; 36405e8b080SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, 365aca7a94dSNamhyung Kim struct hist_entry, rb_node); 366aca7a94dSNamhyung Kim ui_helpline__pop(); 367aca7a94dSNamhyung Kim ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 36805e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 36905e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries, 37005e8b080SArnaldo Carvalho de Melo browser->b.height, 37105e8b080SArnaldo Carvalho de Melo browser->b.index, 37205e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 373aca7a94dSNamhyung Kim h->row_offset, h->nr_rows); 374aca7a94dSNamhyung Kim } 375aca7a94dSNamhyung Kim break; 376aca7a94dSNamhyung Kim case 'C': 377aca7a94dSNamhyung Kim /* Collapse the whole world. */ 37805e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 379aca7a94dSNamhyung Kim break; 380aca7a94dSNamhyung Kim case 'E': 381aca7a94dSNamhyung Kim /* Expand the whole world. */ 38205e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 383aca7a94dSNamhyung Kim break; 384aca7a94dSNamhyung Kim case K_ENTER: 38505e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 386aca7a94dSNamhyung Kim break; 387aca7a94dSNamhyung Kim /* fall thru */ 388aca7a94dSNamhyung Kim default: 389aca7a94dSNamhyung Kim goto out; 390aca7a94dSNamhyung Kim } 391aca7a94dSNamhyung Kim } 392aca7a94dSNamhyung Kim out: 39305e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 394aca7a94dSNamhyung Kim return key; 395aca7a94dSNamhyung Kim } 396aca7a94dSNamhyung Kim 39705e8b080SArnaldo Carvalho de Melo static char *callchain_list__sym_name(struct callchain_list *cl, 398a7cb8863SArnaldo Carvalho de Melo char *bf, size_t bfsize, bool show_dso) 399aca7a94dSNamhyung Kim { 400a7cb8863SArnaldo Carvalho de Melo int printed; 401aca7a94dSNamhyung Kim 402a7cb8863SArnaldo Carvalho de Melo if (cl->ms.sym) 403a7cb8863SArnaldo Carvalho de Melo printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name); 404a7cb8863SArnaldo Carvalho de Melo else 405a7cb8863SArnaldo Carvalho de Melo printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip); 406a7cb8863SArnaldo Carvalho de Melo 407a7cb8863SArnaldo Carvalho de Melo if (show_dso) 408a7cb8863SArnaldo Carvalho de Melo scnprintf(bf + printed, bfsize - printed, " %s", 409a7cb8863SArnaldo Carvalho de Melo cl->ms.map ? cl->ms.map->dso->short_name : "unknown"); 410a7cb8863SArnaldo Carvalho de Melo 411aca7a94dSNamhyung Kim return bf; 412aca7a94dSNamhyung Kim } 413aca7a94dSNamhyung Kim 414aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 415aca7a94dSNamhyung Kim 41605e8b080SArnaldo Carvalho de Melo static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser, 417aca7a94dSNamhyung Kim struct callchain_node *chain_node, 418aca7a94dSNamhyung Kim u64 total, int level, 419aca7a94dSNamhyung Kim unsigned short row, 420aca7a94dSNamhyung Kim off_t *row_offset, 421aca7a94dSNamhyung Kim bool *is_current_entry) 422aca7a94dSNamhyung Kim { 423aca7a94dSNamhyung Kim struct rb_node *node; 424aca7a94dSNamhyung Kim int first_row = row, width, offset = level * LEVEL_OFFSET_STEP; 425aca7a94dSNamhyung Kim u64 new_total, remaining; 426aca7a94dSNamhyung Kim 427aca7a94dSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 428aca7a94dSNamhyung Kim new_total = chain_node->children_hit; 429aca7a94dSNamhyung Kim else 430aca7a94dSNamhyung Kim new_total = total; 431aca7a94dSNamhyung Kim 432aca7a94dSNamhyung Kim remaining = new_total; 433aca7a94dSNamhyung Kim node = rb_first(&chain_node->rb_root); 434aca7a94dSNamhyung Kim while (node) { 435aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 436aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 437aca7a94dSNamhyung Kim u64 cumul = callchain_cumul_hits(child); 438aca7a94dSNamhyung Kim struct callchain_list *chain; 439aca7a94dSNamhyung Kim char folded_sign = ' '; 440aca7a94dSNamhyung Kim int first = true; 441aca7a94dSNamhyung Kim int extra_offset = 0; 442aca7a94dSNamhyung Kim 443aca7a94dSNamhyung Kim remaining -= cumul; 444aca7a94dSNamhyung Kim 445aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 446a7cb8863SArnaldo Carvalho de Melo char bf[1024], *alloc_str; 447aca7a94dSNamhyung Kim const char *str; 448aca7a94dSNamhyung Kim int color; 449aca7a94dSNamhyung Kim bool was_first = first; 450aca7a94dSNamhyung Kim 451aca7a94dSNamhyung Kim if (first) 452aca7a94dSNamhyung Kim first = false; 453aca7a94dSNamhyung Kim else 454aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 455aca7a94dSNamhyung Kim 456aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 457aca7a94dSNamhyung Kim if (*row_offset != 0) { 458aca7a94dSNamhyung Kim --*row_offset; 459aca7a94dSNamhyung Kim goto do_next; 460aca7a94dSNamhyung Kim } 461aca7a94dSNamhyung Kim 462aca7a94dSNamhyung Kim alloc_str = NULL; 463a7cb8863SArnaldo Carvalho de Melo str = callchain_list__sym_name(chain, bf, sizeof(bf), 464a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 465aca7a94dSNamhyung Kim if (was_first) { 466aca7a94dSNamhyung Kim double percent = cumul * 100.0 / new_total; 467aca7a94dSNamhyung Kim 468aca7a94dSNamhyung Kim if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 469aca7a94dSNamhyung Kim str = "Not enough memory!"; 470aca7a94dSNamhyung Kim else 471aca7a94dSNamhyung Kim str = alloc_str; 472aca7a94dSNamhyung Kim } 473aca7a94dSNamhyung Kim 474aca7a94dSNamhyung Kim color = HE_COLORSET_NORMAL; 47505e8b080SArnaldo Carvalho de Melo width = browser->b.width - (offset + extra_offset + 2); 47605e8b080SArnaldo Carvalho de Melo if (ui_browser__is_current_entry(&browser->b, row)) { 47705e8b080SArnaldo Carvalho de Melo browser->selection = &chain->ms; 478aca7a94dSNamhyung Kim color = HE_COLORSET_SELECTED; 479aca7a94dSNamhyung Kim *is_current_entry = true; 480aca7a94dSNamhyung Kim } 481aca7a94dSNamhyung Kim 48205e8b080SArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, color); 48305e8b080SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 484aca7a94dSNamhyung Kim slsmg_write_nstring(" ", offset + extra_offset); 485aca7a94dSNamhyung Kim slsmg_printf("%c ", folded_sign); 486aca7a94dSNamhyung Kim slsmg_write_nstring(str, width); 487aca7a94dSNamhyung Kim free(alloc_str); 488aca7a94dSNamhyung Kim 48905e8b080SArnaldo Carvalho de Melo if (++row == browser->b.height) 490aca7a94dSNamhyung Kim goto out; 491aca7a94dSNamhyung Kim do_next: 492aca7a94dSNamhyung Kim if (folded_sign == '+') 493aca7a94dSNamhyung Kim break; 494aca7a94dSNamhyung Kim } 495aca7a94dSNamhyung Kim 496aca7a94dSNamhyung Kim if (folded_sign == '-') { 497aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 49805e8b080SArnaldo Carvalho de Melo row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total, 499aca7a94dSNamhyung Kim new_level, row, row_offset, 500aca7a94dSNamhyung Kim is_current_entry); 501aca7a94dSNamhyung Kim } 50205e8b080SArnaldo Carvalho de Melo if (row == browser->b.height) 503aca7a94dSNamhyung Kim goto out; 504aca7a94dSNamhyung Kim node = next; 505aca7a94dSNamhyung Kim } 506aca7a94dSNamhyung Kim out: 507aca7a94dSNamhyung Kim return row - first_row; 508aca7a94dSNamhyung Kim } 509aca7a94dSNamhyung Kim 51005e8b080SArnaldo Carvalho de Melo static int hist_browser__show_callchain_node(struct hist_browser *browser, 511aca7a94dSNamhyung Kim struct callchain_node *node, 512aca7a94dSNamhyung Kim int level, unsigned short row, 513aca7a94dSNamhyung Kim off_t *row_offset, 514aca7a94dSNamhyung Kim bool *is_current_entry) 515aca7a94dSNamhyung Kim { 516aca7a94dSNamhyung Kim struct callchain_list *chain; 517aca7a94dSNamhyung Kim int first_row = row, 518aca7a94dSNamhyung Kim offset = level * LEVEL_OFFSET_STEP, 51905e8b080SArnaldo Carvalho de Melo width = browser->b.width - offset; 520aca7a94dSNamhyung Kim char folded_sign = ' '; 521aca7a94dSNamhyung Kim 522aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 523a7cb8863SArnaldo Carvalho de Melo char bf[1024], *s; 524aca7a94dSNamhyung Kim int color; 525aca7a94dSNamhyung Kim 526aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 527aca7a94dSNamhyung Kim 528aca7a94dSNamhyung Kim if (*row_offset != 0) { 529aca7a94dSNamhyung Kim --*row_offset; 530aca7a94dSNamhyung Kim continue; 531aca7a94dSNamhyung Kim } 532aca7a94dSNamhyung Kim 533aca7a94dSNamhyung Kim color = HE_COLORSET_NORMAL; 53405e8b080SArnaldo Carvalho de Melo if (ui_browser__is_current_entry(&browser->b, row)) { 53505e8b080SArnaldo Carvalho de Melo browser->selection = &chain->ms; 536aca7a94dSNamhyung Kim color = HE_COLORSET_SELECTED; 537aca7a94dSNamhyung Kim *is_current_entry = true; 538aca7a94dSNamhyung Kim } 539aca7a94dSNamhyung Kim 540a7cb8863SArnaldo Carvalho de Melo s = callchain_list__sym_name(chain, bf, sizeof(bf), 541a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 54205e8b080SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 54305e8b080SArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, color); 544aca7a94dSNamhyung Kim slsmg_write_nstring(" ", offset); 545aca7a94dSNamhyung Kim slsmg_printf("%c ", folded_sign); 546aca7a94dSNamhyung Kim slsmg_write_nstring(s, width - 2); 547aca7a94dSNamhyung Kim 54805e8b080SArnaldo Carvalho de Melo if (++row == browser->b.height) 549aca7a94dSNamhyung Kim goto out; 550aca7a94dSNamhyung Kim } 551aca7a94dSNamhyung Kim 552aca7a94dSNamhyung Kim if (folded_sign == '-') 55305e8b080SArnaldo Carvalho de Melo row += hist_browser__show_callchain_node_rb_tree(browser, node, 55405e8b080SArnaldo Carvalho de Melo browser->hists->stats.total_period, 555aca7a94dSNamhyung Kim level + 1, row, 556aca7a94dSNamhyung Kim row_offset, 557aca7a94dSNamhyung Kim is_current_entry); 558aca7a94dSNamhyung Kim out: 559aca7a94dSNamhyung Kim return row - first_row; 560aca7a94dSNamhyung Kim } 561aca7a94dSNamhyung Kim 56205e8b080SArnaldo Carvalho de Melo static int hist_browser__show_callchain(struct hist_browser *browser, 563aca7a94dSNamhyung Kim struct rb_root *chain, 564aca7a94dSNamhyung Kim int level, unsigned short row, 565aca7a94dSNamhyung Kim off_t *row_offset, 566aca7a94dSNamhyung Kim bool *is_current_entry) 567aca7a94dSNamhyung Kim { 568aca7a94dSNamhyung Kim struct rb_node *nd; 569aca7a94dSNamhyung Kim int first_row = row; 570aca7a94dSNamhyung Kim 571aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 572aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 573aca7a94dSNamhyung Kim 57405e8b080SArnaldo Carvalho de Melo row += hist_browser__show_callchain_node(browser, node, level, 575aca7a94dSNamhyung Kim row, row_offset, 576aca7a94dSNamhyung Kim is_current_entry); 57705e8b080SArnaldo Carvalho de Melo if (row == browser->b.height) 578aca7a94dSNamhyung Kim break; 579aca7a94dSNamhyung Kim } 580aca7a94dSNamhyung Kim 581aca7a94dSNamhyung Kim return row - first_row; 582aca7a94dSNamhyung Kim } 583aca7a94dSNamhyung Kim 58489701460SNamhyung Kim struct hpp_arg { 58589701460SNamhyung Kim struct ui_browser *b; 58689701460SNamhyung Kim char folded_sign; 58789701460SNamhyung Kim bool current_entry; 58889701460SNamhyung Kim }; 58989701460SNamhyung Kim 590*2f6d9009SNamhyung Kim static int __hpp__overhead_callback(struct perf_hpp *hpp, bool front) 5915aed9d24SNamhyung Kim { 592*2f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 593*2f6d9009SNamhyung Kim 594*2f6d9009SNamhyung Kim if (arg->current_entry && arg->b->navkeypressed) 595*2f6d9009SNamhyung Kim ui_browser__set_color(arg->b, HE_COLORSET_SELECTED); 596*2f6d9009SNamhyung Kim else 597*2f6d9009SNamhyung Kim ui_browser__set_color(arg->b, HE_COLORSET_NORMAL); 598*2f6d9009SNamhyung Kim 599*2f6d9009SNamhyung Kim if (front) { 60089701460SNamhyung Kim if (!symbol_conf.use_callchain) 60189701460SNamhyung Kim return 0; 60289701460SNamhyung Kim 60389701460SNamhyung Kim slsmg_printf("%c ", arg->folded_sign); 60489701460SNamhyung Kim return 2; 60589701460SNamhyung Kim } 60689701460SNamhyung Kim 607*2f6d9009SNamhyung Kim return 0; 608*2f6d9009SNamhyung Kim } 609*2f6d9009SNamhyung Kim 610*2f6d9009SNamhyung Kim static int __hpp__color_callback(struct perf_hpp *hpp, bool front __maybe_unused) 61189701460SNamhyung Kim { 61289701460SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 6135aed9d24SNamhyung Kim 614*2f6d9009SNamhyung Kim if (!arg->current_entry || !arg->b->navkeypressed) 615*2f6d9009SNamhyung Kim ui_browser__set_color(arg->b, HE_COLORSET_NORMAL); 616*2f6d9009SNamhyung Kim return 0; 617*2f6d9009SNamhyung Kim } 618*2f6d9009SNamhyung Kim 619*2f6d9009SNamhyung Kim static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 620*2f6d9009SNamhyung Kim { 621*2f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 622*2f6d9009SNamhyung Kim int ret; 623*2f6d9009SNamhyung Kim va_list args; 624*2f6d9009SNamhyung Kim double percent; 625*2f6d9009SNamhyung Kim 626*2f6d9009SNamhyung Kim va_start(args, fmt); 627*2f6d9009SNamhyung Kim percent = va_arg(args, double); 628*2f6d9009SNamhyung Kim va_end(args); 6295aed9d24SNamhyung Kim 63089701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 6315aed9d24SNamhyung Kim 632*2f6d9009SNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, fmt, percent); 63389701460SNamhyung Kim slsmg_printf("%s", hpp->buf); 63489701460SNamhyung Kim 635*2f6d9009SNamhyung Kim advance_hpp(hpp, ret); 6365aed9d24SNamhyung Kim return ret; 637f5951d56SNamhyung Kim } 638f5951d56SNamhyung Kim 63989701460SNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \ 6405aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 6415aed9d24SNamhyung Kim { \ 6425aed9d24SNamhyung Kim return he->stat._field; \ 6435aed9d24SNamhyung Kim } \ 6445aed9d24SNamhyung Kim \ 6452c5d4b4aSJiri Olsa static int \ 6462c5d4b4aSJiri Olsa hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ 6472c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 6485aed9d24SNamhyung Kim struct hist_entry *he) \ 6495aed9d24SNamhyung Kim { \ 650*2f6d9009SNamhyung Kim return __hpp__fmt(hpp, he, __hpp_get_##_field, _cb, " %6.2f%%", \ 651*2f6d9009SNamhyung Kim __hpp__slsmg_color_printf, true); \ 6525aed9d24SNamhyung Kim } 653f5951d56SNamhyung Kim 654*2f6d9009SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period, __hpp__overhead_callback) 655*2f6d9009SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, __hpp__color_callback) 656*2f6d9009SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us, __hpp__color_callback) 657*2f6d9009SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, __hpp__color_callback) 658*2f6d9009SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, __hpp__color_callback) 6595aed9d24SNamhyung Kim 6605aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 661f5951d56SNamhyung Kim 662f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 663f5951d56SNamhyung Kim { 6641d77822eSJiri Olsa perf_hpp__init(); 665f5951d56SNamhyung Kim 666f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 667f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 668f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 669f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 670f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 671f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 672f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 673f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 674f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 675f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 676f5951d56SNamhyung Kim } 677f5951d56SNamhyung Kim 67805e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 679aca7a94dSNamhyung Kim struct hist_entry *entry, 680aca7a94dSNamhyung Kim unsigned short row) 681aca7a94dSNamhyung Kim { 682aca7a94dSNamhyung Kim char s[256]; 6831240005eSJiri Olsa int printed = 0; 68467d25916SNamhyung Kim int width = browser->b.width; 685aca7a94dSNamhyung Kim char folded_sign = ' '; 68605e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 687aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 68863a1a3d8SNamhyung Kim bool first = true; 6891240005eSJiri Olsa struct perf_hpp_fmt *fmt; 690aca7a94dSNamhyung Kim 691aca7a94dSNamhyung Kim if (current_entry) { 69205e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 69305e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 694aca7a94dSNamhyung Kim } 695aca7a94dSNamhyung Kim 696aca7a94dSNamhyung Kim if (symbol_conf.use_callchain) { 697aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 698aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 699aca7a94dSNamhyung Kim } 700aca7a94dSNamhyung Kim 701aca7a94dSNamhyung Kim if (row_offset == 0) { 70289701460SNamhyung Kim struct hpp_arg arg = { 70389701460SNamhyung Kim .b = &browser->b, 70489701460SNamhyung Kim .folded_sign = folded_sign, 70589701460SNamhyung Kim .current_entry = current_entry, 70689701460SNamhyung Kim }; 707f5951d56SNamhyung Kim struct perf_hpp hpp = { 708f5951d56SNamhyung Kim .buf = s, 709f5951d56SNamhyung Kim .size = sizeof(s), 71089701460SNamhyung Kim .ptr = &arg, 711f5951d56SNamhyung Kim }; 712f5951d56SNamhyung Kim 71367d25916SNamhyung Kim ui_browser__gotorc(&browser->b, row, 0); 714f5951d56SNamhyung Kim 7151240005eSJiri Olsa perf_hpp__for_each_format(fmt) { 71663a1a3d8SNamhyung Kim if (!first) { 717f5951d56SNamhyung Kim slsmg_printf(" "); 718f5951d56SNamhyung Kim width -= 2; 719f5951d56SNamhyung Kim } 72063a1a3d8SNamhyung Kim first = false; 721f5951d56SNamhyung Kim 7221240005eSJiri Olsa if (fmt->color) { 7232c5d4b4aSJiri Olsa width -= fmt->color(fmt, &hpp, entry); 724f5951d56SNamhyung Kim } else { 7252c5d4b4aSJiri Olsa width -= fmt->entry(fmt, &hpp, entry); 726f5951d56SNamhyung Kim slsmg_printf("%s", s); 727f5951d56SNamhyung Kim } 728f5951d56SNamhyung Kim } 729aca7a94dSNamhyung Kim 730aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 73105e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 732aca7a94dSNamhyung Kim width += 1; 733aca7a94dSNamhyung Kim 734f5951d56SNamhyung Kim hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists); 735aca7a94dSNamhyung Kim slsmg_write_nstring(s, width); 736aca7a94dSNamhyung Kim ++row; 737aca7a94dSNamhyung Kim ++printed; 738aca7a94dSNamhyung Kim } else 739aca7a94dSNamhyung Kim --row_offset; 740aca7a94dSNamhyung Kim 74105e8b080SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.height) { 74205e8b080SArnaldo Carvalho de Melo printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 743aca7a94dSNamhyung Kim 1, row, &row_offset, 744aca7a94dSNamhyung Kim ¤t_entry); 745aca7a94dSNamhyung Kim if (current_entry) 74605e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 747aca7a94dSNamhyung Kim } 748aca7a94dSNamhyung Kim 749aca7a94dSNamhyung Kim return printed; 750aca7a94dSNamhyung Kim } 751aca7a94dSNamhyung Kim 752aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 753aca7a94dSNamhyung Kim { 754aca7a94dSNamhyung Kim if (browser->top == NULL) { 755aca7a94dSNamhyung Kim struct hist_browser *hb; 756aca7a94dSNamhyung Kim 757aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 758aca7a94dSNamhyung Kim browser->top = rb_first(&hb->hists->entries); 759aca7a94dSNamhyung Kim } 760aca7a94dSNamhyung Kim } 761aca7a94dSNamhyung Kim 76205e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 763aca7a94dSNamhyung Kim { 764aca7a94dSNamhyung Kim unsigned row = 0; 765aca7a94dSNamhyung Kim struct rb_node *nd; 76605e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 767aca7a94dSNamhyung Kim 76805e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 769aca7a94dSNamhyung Kim 77005e8b080SArnaldo Carvalho de Melo for (nd = browser->top; nd; nd = rb_next(nd)) { 771aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 772064f1981SNamhyung Kim float percent = h->stat.period * 100.0 / 773064f1981SNamhyung Kim hb->hists->stats.total_period; 774aca7a94dSNamhyung Kim 775aca7a94dSNamhyung Kim if (h->filtered) 776aca7a94dSNamhyung Kim continue; 777aca7a94dSNamhyung Kim 778064f1981SNamhyung Kim if (percent < hb->min_pcnt) 779064f1981SNamhyung Kim continue; 780064f1981SNamhyung Kim 781aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 78205e8b080SArnaldo Carvalho de Melo if (row == browser->height) 783aca7a94dSNamhyung Kim break; 784aca7a94dSNamhyung Kim } 785aca7a94dSNamhyung Kim 786aca7a94dSNamhyung Kim return row; 787aca7a94dSNamhyung Kim } 788aca7a94dSNamhyung Kim 789064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 790064f1981SNamhyung Kim struct hists *hists, 791064f1981SNamhyung Kim float min_pcnt) 792aca7a94dSNamhyung Kim { 793aca7a94dSNamhyung Kim while (nd != NULL) { 794aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 795064f1981SNamhyung Kim float percent = h->stat.period * 100.0 / 796064f1981SNamhyung Kim hists->stats.total_period; 797064f1981SNamhyung Kim 798064f1981SNamhyung Kim if (percent < min_pcnt) 799064f1981SNamhyung Kim return NULL; 800064f1981SNamhyung Kim 801aca7a94dSNamhyung Kim if (!h->filtered) 802aca7a94dSNamhyung Kim return nd; 803aca7a94dSNamhyung Kim 804aca7a94dSNamhyung Kim nd = rb_next(nd); 805aca7a94dSNamhyung Kim } 806aca7a94dSNamhyung Kim 807aca7a94dSNamhyung Kim return NULL; 808aca7a94dSNamhyung Kim } 809aca7a94dSNamhyung Kim 810064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 811064f1981SNamhyung Kim struct hists *hists, 812064f1981SNamhyung Kim float min_pcnt) 813aca7a94dSNamhyung Kim { 814aca7a94dSNamhyung Kim while (nd != NULL) { 815aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 816064f1981SNamhyung Kim float percent = h->stat.period * 100.0 / 817064f1981SNamhyung Kim hists->stats.total_period; 818064f1981SNamhyung Kim 819064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 820aca7a94dSNamhyung Kim return nd; 821aca7a94dSNamhyung Kim 822aca7a94dSNamhyung Kim nd = rb_prev(nd); 823aca7a94dSNamhyung Kim } 824aca7a94dSNamhyung Kim 825aca7a94dSNamhyung Kim return NULL; 826aca7a94dSNamhyung Kim } 827aca7a94dSNamhyung Kim 82805e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 829aca7a94dSNamhyung Kim off_t offset, int whence) 830aca7a94dSNamhyung Kim { 831aca7a94dSNamhyung Kim struct hist_entry *h; 832aca7a94dSNamhyung Kim struct rb_node *nd; 833aca7a94dSNamhyung Kim bool first = true; 834064f1981SNamhyung Kim struct hist_browser *hb; 835064f1981SNamhyung Kim 836064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 837aca7a94dSNamhyung Kim 83805e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 839aca7a94dSNamhyung Kim return; 840aca7a94dSNamhyung Kim 84105e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 842aca7a94dSNamhyung Kim 843aca7a94dSNamhyung Kim switch (whence) { 844aca7a94dSNamhyung Kim case SEEK_SET: 845064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 846064f1981SNamhyung Kim hb->hists, hb->min_pcnt); 847aca7a94dSNamhyung Kim break; 848aca7a94dSNamhyung Kim case SEEK_CUR: 84905e8b080SArnaldo Carvalho de Melo nd = browser->top; 850aca7a94dSNamhyung Kim goto do_offset; 851aca7a94dSNamhyung Kim case SEEK_END: 852064f1981SNamhyung Kim nd = hists__filter_prev_entries(rb_last(browser->entries), 853064f1981SNamhyung Kim hb->hists, hb->min_pcnt); 854aca7a94dSNamhyung Kim first = false; 855aca7a94dSNamhyung Kim break; 856aca7a94dSNamhyung Kim default: 857aca7a94dSNamhyung Kim return; 858aca7a94dSNamhyung Kim } 859aca7a94dSNamhyung Kim 860aca7a94dSNamhyung Kim /* 861aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 862aca7a94dSNamhyung Kim * row_offset: 863aca7a94dSNamhyung Kim */ 86405e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 865aca7a94dSNamhyung Kim h->row_offset = 0; 866aca7a94dSNamhyung Kim 867aca7a94dSNamhyung Kim /* 868aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 869aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 870aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 871aca7a94dSNamhyung Kim * 872aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 873aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 874aca7a94dSNamhyung Kim * 875aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 876aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 877aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 878aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 879aca7a94dSNamhyung Kim */ 880aca7a94dSNamhyung Kim do_offset: 881aca7a94dSNamhyung Kim if (offset > 0) { 882aca7a94dSNamhyung Kim do { 883aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 884aca7a94dSNamhyung Kim if (h->ms.unfolded) { 885aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 886aca7a94dSNamhyung Kim if (offset > remaining) { 887aca7a94dSNamhyung Kim offset -= remaining; 888aca7a94dSNamhyung Kim h->row_offset = 0; 889aca7a94dSNamhyung Kim } else { 890aca7a94dSNamhyung Kim h->row_offset += offset; 891aca7a94dSNamhyung Kim offset = 0; 89205e8b080SArnaldo Carvalho de Melo browser->top = nd; 893aca7a94dSNamhyung Kim break; 894aca7a94dSNamhyung Kim } 895aca7a94dSNamhyung Kim } 896064f1981SNamhyung Kim nd = hists__filter_entries(rb_next(nd), hb->hists, 897064f1981SNamhyung Kim hb->min_pcnt); 898aca7a94dSNamhyung Kim if (nd == NULL) 899aca7a94dSNamhyung Kim break; 900aca7a94dSNamhyung Kim --offset; 90105e8b080SArnaldo Carvalho de Melo browser->top = nd; 902aca7a94dSNamhyung Kim } while (offset != 0); 903aca7a94dSNamhyung Kim } else if (offset < 0) { 904aca7a94dSNamhyung Kim while (1) { 905aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 906aca7a94dSNamhyung Kim if (h->ms.unfolded) { 907aca7a94dSNamhyung Kim if (first) { 908aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 909aca7a94dSNamhyung Kim offset += h->row_offset; 910aca7a94dSNamhyung Kim h->row_offset = 0; 911aca7a94dSNamhyung Kim } else { 912aca7a94dSNamhyung Kim h->row_offset += offset; 913aca7a94dSNamhyung Kim offset = 0; 91405e8b080SArnaldo Carvalho de Melo browser->top = nd; 915aca7a94dSNamhyung Kim break; 916aca7a94dSNamhyung Kim } 917aca7a94dSNamhyung Kim } else { 918aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 919aca7a94dSNamhyung Kim offset += h->nr_rows; 920aca7a94dSNamhyung Kim h->row_offset = 0; 921aca7a94dSNamhyung Kim } else { 922aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 923aca7a94dSNamhyung Kim offset = 0; 92405e8b080SArnaldo Carvalho de Melo browser->top = nd; 925aca7a94dSNamhyung Kim break; 926aca7a94dSNamhyung Kim } 927aca7a94dSNamhyung Kim } 928aca7a94dSNamhyung Kim } 929aca7a94dSNamhyung Kim 930064f1981SNamhyung Kim nd = hists__filter_prev_entries(rb_prev(nd), hb->hists, 931064f1981SNamhyung Kim hb->min_pcnt); 932aca7a94dSNamhyung Kim if (nd == NULL) 933aca7a94dSNamhyung Kim break; 934aca7a94dSNamhyung Kim ++offset; 93505e8b080SArnaldo Carvalho de Melo browser->top = nd; 936aca7a94dSNamhyung Kim if (offset == 0) { 937aca7a94dSNamhyung Kim /* 938aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 939aca7a94dSNamhyung Kim * unfolded, if it is then we should have 940aca7a94dSNamhyung Kim * row_offset at its last entry. 941aca7a94dSNamhyung Kim */ 942aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 943aca7a94dSNamhyung Kim if (h->ms.unfolded) 944aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 945aca7a94dSNamhyung Kim break; 946aca7a94dSNamhyung Kim } 947aca7a94dSNamhyung Kim first = false; 948aca7a94dSNamhyung Kim } 949aca7a94dSNamhyung Kim } else { 95005e8b080SArnaldo Carvalho de Melo browser->top = nd; 951aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 952aca7a94dSNamhyung Kim h->row_offset = 0; 953aca7a94dSNamhyung Kim } 954aca7a94dSNamhyung Kim } 955aca7a94dSNamhyung Kim 956aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser, 957aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *chain_node, 958aff3f3f6SArnaldo Carvalho de Melo u64 total, int level, 959aff3f3f6SArnaldo Carvalho de Melo FILE *fp) 960aff3f3f6SArnaldo Carvalho de Melo { 961aff3f3f6SArnaldo Carvalho de Melo struct rb_node *node; 962aff3f3f6SArnaldo Carvalho de Melo int offset = level * LEVEL_OFFSET_STEP; 963aff3f3f6SArnaldo Carvalho de Melo u64 new_total, remaining; 964aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 965aff3f3f6SArnaldo Carvalho de Melo 966aff3f3f6SArnaldo Carvalho de Melo if (callchain_param.mode == CHAIN_GRAPH_REL) 967aff3f3f6SArnaldo Carvalho de Melo new_total = chain_node->children_hit; 968aff3f3f6SArnaldo Carvalho de Melo else 969aff3f3f6SArnaldo Carvalho de Melo new_total = total; 970aff3f3f6SArnaldo Carvalho de Melo 971aff3f3f6SArnaldo Carvalho de Melo remaining = new_total; 972aff3f3f6SArnaldo Carvalho de Melo node = rb_first(&chain_node->rb_root); 973aff3f3f6SArnaldo Carvalho de Melo while (node) { 974aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 975aff3f3f6SArnaldo Carvalho de Melo struct rb_node *next = rb_next(node); 976aff3f3f6SArnaldo Carvalho de Melo u64 cumul = callchain_cumul_hits(child); 977aff3f3f6SArnaldo Carvalho de Melo struct callchain_list *chain; 978aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 979aff3f3f6SArnaldo Carvalho de Melo int first = true; 980aff3f3f6SArnaldo Carvalho de Melo int extra_offset = 0; 981aff3f3f6SArnaldo Carvalho de Melo 982aff3f3f6SArnaldo Carvalho de Melo remaining -= cumul; 983aff3f3f6SArnaldo Carvalho de Melo 984aff3f3f6SArnaldo Carvalho de Melo list_for_each_entry(chain, &child->val, list) { 985a7cb8863SArnaldo Carvalho de Melo char bf[1024], *alloc_str; 986aff3f3f6SArnaldo Carvalho de Melo const char *str; 987aff3f3f6SArnaldo Carvalho de Melo bool was_first = first; 988aff3f3f6SArnaldo Carvalho de Melo 989aff3f3f6SArnaldo Carvalho de Melo if (first) 990aff3f3f6SArnaldo Carvalho de Melo first = false; 991aff3f3f6SArnaldo Carvalho de Melo else 992aff3f3f6SArnaldo Carvalho de Melo extra_offset = LEVEL_OFFSET_STEP; 993aff3f3f6SArnaldo Carvalho de Melo 994aff3f3f6SArnaldo Carvalho de Melo folded_sign = callchain_list__folded(chain); 995aff3f3f6SArnaldo Carvalho de Melo 996aff3f3f6SArnaldo Carvalho de Melo alloc_str = NULL; 997a7cb8863SArnaldo Carvalho de Melo str = callchain_list__sym_name(chain, bf, sizeof(bf), 998a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 999aff3f3f6SArnaldo Carvalho de Melo if (was_first) { 1000aff3f3f6SArnaldo Carvalho de Melo double percent = cumul * 100.0 / new_total; 1001aff3f3f6SArnaldo Carvalho de Melo 1002aff3f3f6SArnaldo Carvalho de Melo if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 1003aff3f3f6SArnaldo Carvalho de Melo str = "Not enough memory!"; 1004aff3f3f6SArnaldo Carvalho de Melo else 1005aff3f3f6SArnaldo Carvalho de Melo str = alloc_str; 1006aff3f3f6SArnaldo Carvalho de Melo } 1007aff3f3f6SArnaldo Carvalho de Melo 1008aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str); 1009aff3f3f6SArnaldo Carvalho de Melo free(alloc_str); 1010aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '+') 1011aff3f3f6SArnaldo Carvalho de Melo break; 1012aff3f3f6SArnaldo Carvalho de Melo } 1013aff3f3f6SArnaldo Carvalho de Melo 1014aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') { 1015aff3f3f6SArnaldo Carvalho de Melo const int new_level = level + (extra_offset ? 2 : 1); 1016aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total, 1017aff3f3f6SArnaldo Carvalho de Melo new_level, fp); 1018aff3f3f6SArnaldo Carvalho de Melo } 1019aff3f3f6SArnaldo Carvalho de Melo 1020aff3f3f6SArnaldo Carvalho de Melo node = next; 1021aff3f3f6SArnaldo Carvalho de Melo } 1022aff3f3f6SArnaldo Carvalho de Melo 1023aff3f3f6SArnaldo Carvalho de Melo return printed; 1024aff3f3f6SArnaldo Carvalho de Melo } 1025aff3f3f6SArnaldo Carvalho de Melo 1026aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain_node(struct hist_browser *browser, 1027aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *node, 1028aff3f3f6SArnaldo Carvalho de Melo int level, FILE *fp) 1029aff3f3f6SArnaldo Carvalho de Melo { 1030aff3f3f6SArnaldo Carvalho de Melo struct callchain_list *chain; 1031aff3f3f6SArnaldo Carvalho de Melo int offset = level * LEVEL_OFFSET_STEP; 1032aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 1033aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1034aff3f3f6SArnaldo Carvalho de Melo 1035aff3f3f6SArnaldo Carvalho de Melo list_for_each_entry(chain, &node->val, list) { 1036a7cb8863SArnaldo Carvalho de Melo char bf[1024], *s; 1037aff3f3f6SArnaldo Carvalho de Melo 1038aff3f3f6SArnaldo Carvalho de Melo folded_sign = callchain_list__folded(chain); 1039a7cb8863SArnaldo Carvalho de Melo s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso); 1040aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s); 1041aff3f3f6SArnaldo Carvalho de Melo } 1042aff3f3f6SArnaldo Carvalho de Melo 1043aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 1044aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node, 1045aff3f3f6SArnaldo Carvalho de Melo browser->hists->stats.total_period, 1046aff3f3f6SArnaldo Carvalho de Melo level + 1, fp); 1047aff3f3f6SArnaldo Carvalho de Melo return printed; 1048aff3f3f6SArnaldo Carvalho de Melo } 1049aff3f3f6SArnaldo Carvalho de Melo 1050aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1051aff3f3f6SArnaldo Carvalho de Melo struct rb_root *chain, int level, FILE *fp) 1052aff3f3f6SArnaldo Carvalho de Melo { 1053aff3f3f6SArnaldo Carvalho de Melo struct rb_node *nd; 1054aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1055aff3f3f6SArnaldo Carvalho de Melo 1056aff3f3f6SArnaldo Carvalho de Melo for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 1057aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 1058aff3f3f6SArnaldo Carvalho de Melo 1059aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain_node(browser, node, level, fp); 1060aff3f3f6SArnaldo Carvalho de Melo } 1061aff3f3f6SArnaldo Carvalho de Melo 1062aff3f3f6SArnaldo Carvalho de Melo return printed; 1063aff3f3f6SArnaldo Carvalho de Melo } 1064aff3f3f6SArnaldo Carvalho de Melo 1065aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 1066aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 1067aff3f3f6SArnaldo Carvalho de Melo { 1068aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 1069aff3f3f6SArnaldo Carvalho de Melo double percent; 1070aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1071aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 1072aff3f3f6SArnaldo Carvalho de Melo 1073aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1074aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 1075aff3f3f6SArnaldo Carvalho de Melo 1076000078bcSNamhyung Kim hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists); 1077b24c28f7SNamhyung Kim percent = (he->stat.period * 100.0) / browser->hists->stats.total_period; 1078aff3f3f6SArnaldo Carvalho de Melo 1079aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1080aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 1081aff3f3f6SArnaldo Carvalho de Melo 1082aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, " %5.2f%%", percent); 1083aff3f3f6SArnaldo Carvalho de Melo 1084aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.show_nr_samples) 1085b24c28f7SNamhyung Kim printed += fprintf(fp, " %11u", he->stat.nr_events); 1086aff3f3f6SArnaldo Carvalho de Melo 1087aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.show_total_period) 1088b24c28f7SNamhyung Kim printed += fprintf(fp, " %12" PRIu64, he->stat.period); 1089aff3f3f6SArnaldo Carvalho de Melo 1090aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", rtrim(s)); 1091aff3f3f6SArnaldo Carvalho de Melo 1092aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 1093aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp); 1094aff3f3f6SArnaldo Carvalho de Melo 1095aff3f3f6SArnaldo Carvalho de Melo return printed; 1096aff3f3f6SArnaldo Carvalho de Melo } 1097aff3f3f6SArnaldo Carvalho de Melo 1098aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1099aff3f3f6SArnaldo Carvalho de Melo { 1100064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1101064f1981SNamhyung Kim browser->hists, 1102064f1981SNamhyung Kim browser->min_pcnt); 1103aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1104aff3f3f6SArnaldo Carvalho de Melo 1105aff3f3f6SArnaldo Carvalho de Melo while (nd) { 1106aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1107aff3f3f6SArnaldo Carvalho de Melo 1108aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 1109064f1981SNamhyung Kim nd = hists__filter_entries(rb_next(nd), browser->hists, 1110064f1981SNamhyung Kim browser->min_pcnt); 1111aff3f3f6SArnaldo Carvalho de Melo } 1112aff3f3f6SArnaldo Carvalho de Melo 1113aff3f3f6SArnaldo Carvalho de Melo return printed; 1114aff3f3f6SArnaldo Carvalho de Melo } 1115aff3f3f6SArnaldo Carvalho de Melo 1116aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 1117aff3f3f6SArnaldo Carvalho de Melo { 1118aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 1119aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 1120aff3f3f6SArnaldo Carvalho de Melo 1121aff3f3f6SArnaldo Carvalho de Melo while (1) { 1122aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 1123aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 1124aff3f3f6SArnaldo Carvalho de Melo break; 1125aff3f3f6SArnaldo Carvalho de Melo /* 1126aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 1127aff3f3f6SArnaldo Carvalho de Melo */ 1128aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 1129aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 1130aff3f3f6SArnaldo Carvalho de Melo return -1; 1131aff3f3f6SArnaldo Carvalho de Melo } 1132aff3f3f6SArnaldo Carvalho de Melo } 1133aff3f3f6SArnaldo Carvalho de Melo 1134aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 1135aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 1136aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 11374cc49d4dSKirill A. Shutemov const char *err = strerror_r(errno, bf, sizeof(bf)); 11384cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 1139aff3f3f6SArnaldo Carvalho de Melo return -1; 1140aff3f3f6SArnaldo Carvalho de Melo } 1141aff3f3f6SArnaldo Carvalho de Melo 1142aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 1143aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 1144aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 1145aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 1146aff3f3f6SArnaldo Carvalho de Melo 1147aff3f3f6SArnaldo Carvalho de Melo return 0; 1148aff3f3f6SArnaldo Carvalho de Melo } 1149aff3f3f6SArnaldo Carvalho de Melo 1150aca7a94dSNamhyung Kim static struct hist_browser *hist_browser__new(struct hists *hists) 1151aca7a94dSNamhyung Kim { 115205e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = zalloc(sizeof(*browser)); 1153aca7a94dSNamhyung Kim 115405e8b080SArnaldo Carvalho de Melo if (browser) { 115505e8b080SArnaldo Carvalho de Melo browser->hists = hists; 115605e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 115705e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 115805e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 1159aca7a94dSNamhyung Kim } 1160aca7a94dSNamhyung Kim 116105e8b080SArnaldo Carvalho de Melo return browser; 1162aca7a94dSNamhyung Kim } 1163aca7a94dSNamhyung Kim 116405e8b080SArnaldo Carvalho de Melo static void hist_browser__delete(struct hist_browser *browser) 1165aca7a94dSNamhyung Kim { 116605e8b080SArnaldo Carvalho de Melo free(browser); 1167aca7a94dSNamhyung Kim } 1168aca7a94dSNamhyung Kim 116905e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 1170aca7a94dSNamhyung Kim { 117105e8b080SArnaldo Carvalho de Melo return browser->he_selection; 1172aca7a94dSNamhyung Kim } 1173aca7a94dSNamhyung Kim 117405e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 1175aca7a94dSNamhyung Kim { 117605e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 1177aca7a94dSNamhyung Kim } 1178aca7a94dSNamhyung Kim 117905e8b080SArnaldo Carvalho de Melo static int hists__browser_title(struct hists *hists, char *bf, size_t size, 1180aca7a94dSNamhyung Kim const char *ev_name) 1181aca7a94dSNamhyung Kim { 1182aca7a94dSNamhyung Kim char unit; 1183aca7a94dSNamhyung Kim int printed; 118405e8b080SArnaldo Carvalho de Melo const struct dso *dso = hists->dso_filter; 118505e8b080SArnaldo Carvalho de Melo const struct thread *thread = hists->thread_filter; 118605e8b080SArnaldo Carvalho de Melo unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 118705e8b080SArnaldo Carvalho de Melo u64 nr_events = hists->stats.total_period; 1188717e263fSNamhyung Kim struct perf_evsel *evsel = hists_to_evsel(hists); 1189717e263fSNamhyung Kim char buf[512]; 1190717e263fSNamhyung Kim size_t buflen = sizeof(buf); 1191717e263fSNamhyung Kim 1192759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1193717e263fSNamhyung Kim struct perf_evsel *pos; 1194717e263fSNamhyung Kim 1195717e263fSNamhyung Kim perf_evsel__group_desc(evsel, buf, buflen); 1196717e263fSNamhyung Kim ev_name = buf; 1197717e263fSNamhyung Kim 1198717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 1199717e263fSNamhyung Kim nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1200717e263fSNamhyung Kim nr_events += pos->hists.stats.total_period; 1201717e263fSNamhyung Kim } 1202717e263fSNamhyung Kim } 1203aca7a94dSNamhyung Kim 1204aca7a94dSNamhyung Kim nr_samples = convert_unit(nr_samples, &unit); 1205aca7a94dSNamhyung Kim printed = scnprintf(bf, size, 1206aca7a94dSNamhyung Kim "Samples: %lu%c of event '%s', Event count (approx.): %lu", 1207aca7a94dSNamhyung Kim nr_samples, unit, ev_name, nr_events); 1208aca7a94dSNamhyung Kim 1209aca7a94dSNamhyung Kim 121005e8b080SArnaldo Carvalho de Melo if (hists->uid_filter_str) 1211aca7a94dSNamhyung Kim printed += snprintf(bf + printed, size - printed, 121205e8b080SArnaldo Carvalho de Melo ", UID: %s", hists->uid_filter_str); 1213aca7a94dSNamhyung Kim if (thread) 1214aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1215aca7a94dSNamhyung Kim ", Thread: %s(%d)", 1216b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 121738051234SAdrian Hunter thread->tid); 1218aca7a94dSNamhyung Kim if (dso) 1219aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1220aca7a94dSNamhyung Kim ", DSO: %s", dso->short_name); 1221aca7a94dSNamhyung Kim return printed; 1222aca7a94dSNamhyung Kim } 1223aca7a94dSNamhyung Kim 1224aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 1225aca7a94dSNamhyung Kim { 1226aca7a94dSNamhyung Kim int i; 1227aca7a94dSNamhyung Kim 122804662523SArnaldo Carvalho de Melo for (i = 0; i < n; ++i) 122904662523SArnaldo Carvalho de Melo zfree(&options[i]); 1230aca7a94dSNamhyung Kim } 1231aca7a94dSNamhyung Kim 1232c77d8d70SFeng Tang /* Check whether the browser is for 'top' or 'report' */ 1233c77d8d70SFeng Tang static inline bool is_report_browser(void *timer) 1234c77d8d70SFeng Tang { 1235c77d8d70SFeng Tang return timer == NULL; 1236c77d8d70SFeng Tang } 1237c77d8d70SFeng Tang 1238341487abSFeng Tang /* 1239341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 1240341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 1241341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 1242341487abSFeng Tang */ 1243341487abSFeng Tang static bool is_input_name_malloced = false; 1244341487abSFeng Tang 1245341487abSFeng Tang static int switch_data_file(void) 1246341487abSFeng Tang { 1247341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 1248341487abSFeng Tang DIR *pwd_dir; 1249341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 1250341487abSFeng Tang struct dirent *dent; 1251341487abSFeng Tang 1252341487abSFeng Tang pwd = getenv("PWD"); 1253341487abSFeng Tang if (!pwd) 1254341487abSFeng Tang return ret; 1255341487abSFeng Tang 1256341487abSFeng Tang pwd_dir = opendir(pwd); 1257341487abSFeng Tang if (!pwd_dir) 1258341487abSFeng Tang return ret; 1259341487abSFeng Tang 1260341487abSFeng Tang memset(options, 0, sizeof(options)); 1261341487abSFeng Tang memset(options, 0, sizeof(abs_path)); 1262341487abSFeng Tang 1263341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 1264341487abSFeng Tang char path[PATH_MAX]; 1265341487abSFeng Tang u64 magic; 1266341487abSFeng Tang char *name = dent->d_name; 1267341487abSFeng Tang FILE *file; 1268341487abSFeng Tang 1269341487abSFeng Tang if (!(dent->d_type == DT_REG)) 1270341487abSFeng Tang continue; 1271341487abSFeng Tang 1272341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 1273341487abSFeng Tang 1274341487abSFeng Tang file = fopen(path, "r"); 1275341487abSFeng Tang if (!file) 1276341487abSFeng Tang continue; 1277341487abSFeng Tang 1278341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 1279341487abSFeng Tang goto close_file_and_continue; 1280341487abSFeng Tang 1281341487abSFeng Tang if (is_perf_magic(magic)) { 1282341487abSFeng Tang options[nr_options] = strdup(name); 1283341487abSFeng Tang if (!options[nr_options]) 1284341487abSFeng Tang goto close_file_and_continue; 1285341487abSFeng Tang 1286341487abSFeng Tang abs_path[nr_options] = strdup(path); 1287341487abSFeng Tang if (!abs_path[nr_options]) { 128874cf249dSArnaldo Carvalho de Melo zfree(&options[nr_options]); 1289341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 1290341487abSFeng Tang fclose(file); 1291341487abSFeng Tang break; 1292341487abSFeng Tang } 1293341487abSFeng Tang 1294341487abSFeng Tang nr_options++; 1295341487abSFeng Tang } 1296341487abSFeng Tang 1297341487abSFeng Tang close_file_and_continue: 1298341487abSFeng Tang fclose(file); 1299341487abSFeng Tang if (nr_options >= 32) { 1300341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 1301341487abSFeng Tang "Only the first 32 files will be listed.\n"); 1302341487abSFeng Tang break; 1303341487abSFeng Tang } 1304341487abSFeng Tang } 1305341487abSFeng Tang closedir(pwd_dir); 1306341487abSFeng Tang 1307341487abSFeng Tang if (nr_options) { 1308341487abSFeng Tang choice = ui__popup_menu(nr_options, options); 1309341487abSFeng Tang if (choice < nr_options && choice >= 0) { 1310341487abSFeng Tang tmp = strdup(abs_path[choice]); 1311341487abSFeng Tang if (tmp) { 1312341487abSFeng Tang if (is_input_name_malloced) 1313341487abSFeng Tang free((void *)input_name); 1314341487abSFeng Tang input_name = tmp; 1315341487abSFeng Tang is_input_name_malloced = true; 1316341487abSFeng Tang ret = 0; 1317341487abSFeng Tang } else 1318341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 1319341487abSFeng Tang } 1320341487abSFeng Tang } 1321341487abSFeng Tang 1322341487abSFeng Tang free_popup_options(options, nr_options); 1323341487abSFeng Tang free_popup_options(abs_path, nr_options); 1324341487abSFeng Tang return ret; 1325341487abSFeng Tang } 1326341487abSFeng Tang 1327064f1981SNamhyung Kim static void hist_browser__update_pcnt_entries(struct hist_browser *hb) 1328064f1981SNamhyung Kim { 1329064f1981SNamhyung Kim u64 nr_entries = 0; 1330064f1981SNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 1331064f1981SNamhyung Kim 1332064f1981SNamhyung Kim while (nd) { 1333064f1981SNamhyung Kim nr_entries++; 1334064f1981SNamhyung Kim nd = hists__filter_entries(rb_next(nd), hb->hists, 1335064f1981SNamhyung Kim hb->min_pcnt); 1336064f1981SNamhyung Kim } 1337064f1981SNamhyung Kim 1338064f1981SNamhyung Kim hb->nr_pcnt_entries = nr_entries; 1339064f1981SNamhyung Kim } 1340341487abSFeng Tang 1341aca7a94dSNamhyung Kim static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1342aca7a94dSNamhyung Kim const char *helpline, const char *ev_name, 1343aca7a94dSNamhyung Kim bool left_exits, 134468d80758SNamhyung Kim struct hist_browser_timer *hbt, 1345064f1981SNamhyung Kim float min_pcnt, 134668d80758SNamhyung Kim struct perf_session_env *env) 1347aca7a94dSNamhyung Kim { 134805e8b080SArnaldo Carvalho de Melo struct hists *hists = &evsel->hists; 134905e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = hist_browser__new(hists); 1350aca7a94dSNamhyung Kim struct branch_info *bi; 1351aca7a94dSNamhyung Kim struct pstack *fstack; 1352aca7a94dSNamhyung Kim char *options[16]; 1353aca7a94dSNamhyung Kim int nr_options = 0; 1354aca7a94dSNamhyung Kim int key = -1; 1355aca7a94dSNamhyung Kim char buf[64]; 1356cdbab7c2SFeng Tang char script_opt[64]; 13579783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 1358aca7a94dSNamhyung Kim 1359e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 1360e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 1361e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 1362e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 1363e8e684a5SNamhyung Kim "q/ESC/CTRL+C Exit browser\n\n" \ 1364e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 1365e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 1366e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 1367e8e684a5SNamhyung Kim "-> Zoom into DSO/Threads & Annotate current symbol\n" \ 1368e8e684a5SNamhyung Kim "<- Zoom out\n" \ 1369e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 1370e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 1371e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 1372e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 1373e8e684a5SNamhyung Kim 1374e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 1375e8e684a5SNamhyung Kim const char report_help[] = HIST_BROWSER_HELP_COMMON 13766dd60135SNamhyung Kim "i Show header information\n" 1377e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 1378e8e684a5SNamhyung Kim "r Run available scripts\n" 1379e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 1380e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 1381e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 1382e8e684a5SNamhyung Kim "/ Filter symbol by name"; 1383e8e684a5SNamhyung Kim const char top_help[] = HIST_BROWSER_HELP_COMMON 1384e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 1385e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 1386e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 1387e8e684a5SNamhyung Kim "/ Filter symbol by name"; 1388e8e684a5SNamhyung Kim 1389aca7a94dSNamhyung Kim if (browser == NULL) 1390aca7a94dSNamhyung Kim return -1; 1391aca7a94dSNamhyung Kim 1392064f1981SNamhyung Kim if (min_pcnt) { 1393064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 1394064f1981SNamhyung Kim hist_browser__update_pcnt_entries(browser); 1395064f1981SNamhyung Kim } 1396064f1981SNamhyung Kim 1397aca7a94dSNamhyung Kim fstack = pstack__new(2); 1398aca7a94dSNamhyung Kim if (fstack == NULL) 1399aca7a94dSNamhyung Kim goto out; 1400aca7a94dSNamhyung Kim 1401aca7a94dSNamhyung Kim ui_helpline__push(helpline); 1402aca7a94dSNamhyung Kim 1403aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 1404aca7a94dSNamhyung Kim 1405aca7a94dSNamhyung Kim while (1) { 1406aca7a94dSNamhyung Kim const struct thread *thread = NULL; 1407aca7a94dSNamhyung Kim const struct dso *dso = NULL; 1408aca7a94dSNamhyung Kim int choice = 0, 1409aca7a94dSNamhyung Kim annotate = -2, zoom_dso = -2, zoom_thread = -2, 1410aca7a94dSNamhyung Kim annotate_f = -2, annotate_t = -2, browse_map = -2; 1411341487abSFeng Tang int scripts_comm = -2, scripts_symbol = -2, 1412341487abSFeng Tang scripts_all = -2, switch_data = -2; 1413aca7a94dSNamhyung Kim 1414aca7a94dSNamhyung Kim nr_options = 0; 1415aca7a94dSNamhyung Kim 14169783adf7SNamhyung Kim key = hist_browser__run(browser, ev_name, hbt); 1417aca7a94dSNamhyung Kim 1418aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 1419aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 1420aca7a94dSNamhyung Kim dso = browser->selection->map ? browser->selection->map->dso : NULL; 1421aca7a94dSNamhyung Kim } 1422aca7a94dSNamhyung Kim switch (key) { 1423aca7a94dSNamhyung Kim case K_TAB: 1424aca7a94dSNamhyung Kim case K_UNTAB: 1425aca7a94dSNamhyung Kim if (nr_events == 1) 1426aca7a94dSNamhyung Kim continue; 1427aca7a94dSNamhyung Kim /* 1428aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 1429aca7a94dSNamhyung Kim * go to the next or previous 1430aca7a94dSNamhyung Kim */ 1431aca7a94dSNamhyung Kim goto out_free_stack; 1432aca7a94dSNamhyung Kim case 'a': 14339c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) { 1434aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 1435aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 1436aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 1437aca7a94dSNamhyung Kim continue; 1438aca7a94dSNamhyung Kim } 1439aca7a94dSNamhyung Kim 1440aca7a94dSNamhyung Kim if (browser->selection == NULL || 1441aca7a94dSNamhyung Kim browser->selection->sym == NULL || 1442aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 1443aca7a94dSNamhyung Kim continue; 1444aca7a94dSNamhyung Kim goto do_annotate; 1445aff3f3f6SArnaldo Carvalho de Melo case 'P': 1446aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 1447aff3f3f6SArnaldo Carvalho de Melo continue; 1448aca7a94dSNamhyung Kim case 'd': 1449aca7a94dSNamhyung Kim goto zoom_dso; 1450a7cb8863SArnaldo Carvalho de Melo case 'V': 1451a7cb8863SArnaldo Carvalho de Melo browser->show_dso = !browser->show_dso; 1452a7cb8863SArnaldo Carvalho de Melo continue; 1453aca7a94dSNamhyung Kim case 't': 1454aca7a94dSNamhyung Kim goto zoom_thread; 14555a5626b1SArnaldo Carvalho de Melo case '/': 1456aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 1457aca7a94dSNamhyung Kim "Please enter the name of symbol you want to see", 1458aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 1459aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 146005e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 146105e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 1462aca7a94dSNamhyung Kim hist_browser__reset(browser); 1463aca7a94dSNamhyung Kim } 1464aca7a94dSNamhyung Kim continue; 1465cdbab7c2SFeng Tang case 'r': 14669783adf7SNamhyung Kim if (is_report_browser(hbt)) 1467cdbab7c2SFeng Tang goto do_scripts; 1468c77d8d70SFeng Tang continue; 1469341487abSFeng Tang case 's': 1470341487abSFeng Tang if (is_report_browser(hbt)) 1471341487abSFeng Tang goto do_data_switch; 1472341487abSFeng Tang continue; 14736dd60135SNamhyung Kim case 'i': 14746dd60135SNamhyung Kim /* env->arch is NULL for live-mode (i.e. perf top) */ 14756dd60135SNamhyung Kim if (env->arch) 14766dd60135SNamhyung Kim tui__header_window(env); 14776dd60135SNamhyung Kim continue; 1478aca7a94dSNamhyung Kim case K_F1: 1479aca7a94dSNamhyung Kim case 'h': 1480aca7a94dSNamhyung Kim case '?': 1481aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 1482e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 1483aca7a94dSNamhyung Kim continue; 1484aca7a94dSNamhyung Kim case K_ENTER: 1485aca7a94dSNamhyung Kim case K_RIGHT: 1486aca7a94dSNamhyung Kim /* menu */ 1487aca7a94dSNamhyung Kim break; 1488aca7a94dSNamhyung Kim case K_LEFT: { 1489aca7a94dSNamhyung Kim const void *top; 1490aca7a94dSNamhyung Kim 1491aca7a94dSNamhyung Kim if (pstack__empty(fstack)) { 1492aca7a94dSNamhyung Kim /* 1493aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 1494aca7a94dSNamhyung Kim */ 1495aca7a94dSNamhyung Kim if (left_exits) 1496aca7a94dSNamhyung Kim goto out_free_stack; 1497aca7a94dSNamhyung Kim continue; 1498aca7a94dSNamhyung Kim } 1499aca7a94dSNamhyung Kim top = pstack__pop(fstack); 1500aca7a94dSNamhyung Kim if (top == &browser->hists->dso_filter) 1501aca7a94dSNamhyung Kim goto zoom_out_dso; 1502aca7a94dSNamhyung Kim if (top == &browser->hists->thread_filter) 1503aca7a94dSNamhyung Kim goto zoom_out_thread; 1504aca7a94dSNamhyung Kim continue; 1505aca7a94dSNamhyung Kim } 1506aca7a94dSNamhyung Kim case K_ESC: 1507aca7a94dSNamhyung Kim if (!left_exits && 1508aca7a94dSNamhyung Kim !ui_browser__dialog_yesno(&browser->b, 1509aca7a94dSNamhyung Kim "Do you really want to exit?")) 1510aca7a94dSNamhyung Kim continue; 1511aca7a94dSNamhyung Kim /* Fall thru */ 1512aca7a94dSNamhyung Kim case 'q': 1513aca7a94dSNamhyung Kim case CTRL('c'): 1514aca7a94dSNamhyung Kim goto out_free_stack; 1515aca7a94dSNamhyung Kim default: 1516aca7a94dSNamhyung Kim continue; 1517aca7a94dSNamhyung Kim } 1518aca7a94dSNamhyung Kim 15199c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) 1520aca7a94dSNamhyung Kim goto add_exit_option; 1521aca7a94dSNamhyung Kim 152255369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 1523aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 1524aca7a94dSNamhyung Kim if (browser->selection != NULL && 1525aca7a94dSNamhyung Kim bi && 1526aca7a94dSNamhyung Kim bi->from.sym != NULL && 1527aca7a94dSNamhyung Kim !bi->from.map->dso->annotate_warned && 1528aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1529aca7a94dSNamhyung Kim bi->from.sym->name) > 0) 1530aca7a94dSNamhyung Kim annotate_f = nr_options++; 1531aca7a94dSNamhyung Kim 1532aca7a94dSNamhyung Kim if (browser->selection != NULL && 1533aca7a94dSNamhyung Kim bi && 1534aca7a94dSNamhyung Kim bi->to.sym != NULL && 1535aca7a94dSNamhyung Kim !bi->to.map->dso->annotate_warned && 1536aca7a94dSNamhyung Kim (bi->to.sym != bi->from.sym || 1537aca7a94dSNamhyung Kim bi->to.map->dso != bi->from.map->dso) && 1538aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1539aca7a94dSNamhyung Kim bi->to.sym->name) > 0) 1540aca7a94dSNamhyung Kim annotate_t = nr_options++; 1541aca7a94dSNamhyung Kim } else { 1542aca7a94dSNamhyung Kim 1543aca7a94dSNamhyung Kim if (browser->selection != NULL && 1544aca7a94dSNamhyung Kim browser->selection->sym != NULL && 1545aca7a94dSNamhyung Kim !browser->selection->map->dso->annotate_warned && 1546aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1547aca7a94dSNamhyung Kim browser->selection->sym->name) > 0) 1548aca7a94dSNamhyung Kim annotate = nr_options++; 1549aca7a94dSNamhyung Kim } 1550aca7a94dSNamhyung Kim 1551aca7a94dSNamhyung Kim if (thread != NULL && 1552aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1553aca7a94dSNamhyung Kim (browser->hists->thread_filter ? "out of" : "into"), 1554b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 155538051234SAdrian Hunter thread->tid) > 0) 1556aca7a94dSNamhyung Kim zoom_thread = nr_options++; 1557aca7a94dSNamhyung Kim 1558aca7a94dSNamhyung Kim if (dso != NULL && 1559aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Zoom %s %s DSO", 1560aca7a94dSNamhyung Kim (browser->hists->dso_filter ? "out of" : "into"), 1561aca7a94dSNamhyung Kim (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 1562aca7a94dSNamhyung Kim zoom_dso = nr_options++; 1563aca7a94dSNamhyung Kim 1564aca7a94dSNamhyung Kim if (browser->selection != NULL && 1565aca7a94dSNamhyung Kim browser->selection->map != NULL && 1566aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Browse map details") > 0) 1567aca7a94dSNamhyung Kim browse_map = nr_options++; 1568cdbab7c2SFeng Tang 1569cdbab7c2SFeng Tang /* perf script support */ 1570cdbab7c2SFeng Tang if (browser->he_selection) { 1571cdbab7c2SFeng Tang struct symbol *sym; 1572cdbab7c2SFeng Tang 1573cdbab7c2SFeng Tang if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", 1574b9c5143aSFrederic Weisbecker thread__comm_str(browser->he_selection->thread)) > 0) 1575cdbab7c2SFeng Tang scripts_comm = nr_options++; 1576cdbab7c2SFeng Tang 1577cdbab7c2SFeng Tang sym = browser->he_selection->ms.sym; 1578cdbab7c2SFeng Tang if (sym && sym->namelen && 1579cdbab7c2SFeng Tang asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]", 1580cdbab7c2SFeng Tang sym->name) > 0) 1581cdbab7c2SFeng Tang scripts_symbol = nr_options++; 1582cdbab7c2SFeng Tang } 1583cdbab7c2SFeng Tang 1584cdbab7c2SFeng Tang if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) 1585cdbab7c2SFeng Tang scripts_all = nr_options++; 1586cdbab7c2SFeng Tang 1587341487abSFeng Tang if (is_report_browser(hbt) && asprintf(&options[nr_options], 1588341487abSFeng Tang "Switch to another data file in PWD") > 0) 1589341487abSFeng Tang switch_data = nr_options++; 1590aca7a94dSNamhyung Kim add_exit_option: 1591aca7a94dSNamhyung Kim options[nr_options++] = (char *)"Exit"; 1592aca7a94dSNamhyung Kim retry_popup_menu: 1593aca7a94dSNamhyung Kim choice = ui__popup_menu(nr_options, options); 1594aca7a94dSNamhyung Kim 1595aca7a94dSNamhyung Kim if (choice == nr_options - 1) 1596aca7a94dSNamhyung Kim break; 1597aca7a94dSNamhyung Kim 1598aca7a94dSNamhyung Kim if (choice == -1) { 1599aca7a94dSNamhyung Kim free_popup_options(options, nr_options - 1); 1600aca7a94dSNamhyung Kim continue; 1601aca7a94dSNamhyung Kim } 1602aca7a94dSNamhyung Kim 1603aca7a94dSNamhyung Kim if (choice == annotate || choice == annotate_t || choice == annotate_f) { 1604aca7a94dSNamhyung Kim struct hist_entry *he; 1605aca7a94dSNamhyung Kim int err; 1606aca7a94dSNamhyung Kim do_annotate: 160768d80758SNamhyung Kim if (!objdump_path && perf_session_env__lookup_objdump(env)) 160868d80758SNamhyung Kim continue; 160968d80758SNamhyung Kim 1610aca7a94dSNamhyung Kim he = hist_browser__selected_entry(browser); 1611aca7a94dSNamhyung Kim if (he == NULL) 1612aca7a94dSNamhyung Kim continue; 1613aca7a94dSNamhyung Kim 1614aca7a94dSNamhyung Kim /* 1615aca7a94dSNamhyung Kim * we stash the branch_info symbol + map into the 1616aca7a94dSNamhyung Kim * the ms so we don't have to rewrite all the annotation 1617aca7a94dSNamhyung Kim * code to use branch_info. 1618aca7a94dSNamhyung Kim * in branch mode, the ms struct is not used 1619aca7a94dSNamhyung Kim */ 1620aca7a94dSNamhyung Kim if (choice == annotate_f) { 1621aca7a94dSNamhyung Kim he->ms.sym = he->branch_info->from.sym; 1622aca7a94dSNamhyung Kim he->ms.map = he->branch_info->from.map; 1623aca7a94dSNamhyung Kim } else if (choice == annotate_t) { 1624aca7a94dSNamhyung Kim he->ms.sym = he->branch_info->to.sym; 1625aca7a94dSNamhyung Kim he->ms.map = he->branch_info->to.map; 1626aca7a94dSNamhyung Kim } 1627aca7a94dSNamhyung Kim 1628aca7a94dSNamhyung Kim /* 1629aca7a94dSNamhyung Kim * Don't let this be freed, say, by hists__decay_entry. 1630aca7a94dSNamhyung Kim */ 1631aca7a94dSNamhyung Kim he->used = true; 1632db8fd07aSNamhyung Kim err = hist_entry__tui_annotate(he, evsel, hbt); 1633aca7a94dSNamhyung Kim he->used = false; 1634aca7a94dSNamhyung Kim /* 1635aca7a94dSNamhyung Kim * offer option to annotate the other branch source or target 1636aca7a94dSNamhyung Kim * (if they exists) when returning from annotate 1637aca7a94dSNamhyung Kim */ 1638aca7a94dSNamhyung Kim if ((err == 'q' || err == CTRL('c')) 1639aca7a94dSNamhyung Kim && annotate_t != -2 && annotate_f != -2) 1640aca7a94dSNamhyung Kim goto retry_popup_menu; 1641aca7a94dSNamhyung Kim 1642aca7a94dSNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1643aca7a94dSNamhyung Kim if (err) 1644aca7a94dSNamhyung Kim ui_browser__handle_resize(&browser->b); 1645aca7a94dSNamhyung Kim 1646aca7a94dSNamhyung Kim } else if (choice == browse_map) 1647aca7a94dSNamhyung Kim map__browse(browser->selection->map); 1648aca7a94dSNamhyung Kim else if (choice == zoom_dso) { 1649aca7a94dSNamhyung Kim zoom_dso: 1650aca7a94dSNamhyung Kim if (browser->hists->dso_filter) { 1651aca7a94dSNamhyung Kim pstack__remove(fstack, &browser->hists->dso_filter); 1652aca7a94dSNamhyung Kim zoom_out_dso: 1653aca7a94dSNamhyung Kim ui_helpline__pop(); 1654aca7a94dSNamhyung Kim browser->hists->dso_filter = NULL; 1655aca7a94dSNamhyung Kim sort_dso.elide = false; 1656aca7a94dSNamhyung Kim } else { 1657aca7a94dSNamhyung Kim if (dso == NULL) 1658aca7a94dSNamhyung Kim continue; 1659aca7a94dSNamhyung Kim ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1660aca7a94dSNamhyung Kim dso->kernel ? "the Kernel" : dso->short_name); 1661aca7a94dSNamhyung Kim browser->hists->dso_filter = dso; 1662aca7a94dSNamhyung Kim sort_dso.elide = true; 1663aca7a94dSNamhyung Kim pstack__push(fstack, &browser->hists->dso_filter); 1664aca7a94dSNamhyung Kim } 166505e8b080SArnaldo Carvalho de Melo hists__filter_by_dso(hists); 1666aca7a94dSNamhyung Kim hist_browser__reset(browser); 1667aca7a94dSNamhyung Kim } else if (choice == zoom_thread) { 1668aca7a94dSNamhyung Kim zoom_thread: 1669aca7a94dSNamhyung Kim if (browser->hists->thread_filter) { 1670aca7a94dSNamhyung Kim pstack__remove(fstack, &browser->hists->thread_filter); 1671aca7a94dSNamhyung Kim zoom_out_thread: 1672aca7a94dSNamhyung Kim ui_helpline__pop(); 1673aca7a94dSNamhyung Kim browser->hists->thread_filter = NULL; 1674aca7a94dSNamhyung Kim sort_thread.elide = false; 1675aca7a94dSNamhyung Kim } else { 1676aca7a94dSNamhyung Kim ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1677b9c5143aSFrederic Weisbecker thread->comm_set ? thread__comm_str(thread) : "", 167838051234SAdrian Hunter thread->tid); 1679aca7a94dSNamhyung Kim browser->hists->thread_filter = thread; 1680aca7a94dSNamhyung Kim sort_thread.elide = true; 1681aca7a94dSNamhyung Kim pstack__push(fstack, &browser->hists->thread_filter); 1682aca7a94dSNamhyung Kim } 168305e8b080SArnaldo Carvalho de Melo hists__filter_by_thread(hists); 1684aca7a94dSNamhyung Kim hist_browser__reset(browser); 1685aca7a94dSNamhyung Kim } 1686cdbab7c2SFeng Tang /* perf scripts support */ 1687cdbab7c2SFeng Tang else if (choice == scripts_all || choice == scripts_comm || 1688cdbab7c2SFeng Tang choice == scripts_symbol) { 1689cdbab7c2SFeng Tang do_scripts: 1690cdbab7c2SFeng Tang memset(script_opt, 0, 64); 1691cdbab7c2SFeng Tang 1692cdbab7c2SFeng Tang if (choice == scripts_comm) 1693b9c5143aSFrederic Weisbecker sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread)); 1694cdbab7c2SFeng Tang 1695cdbab7c2SFeng Tang if (choice == scripts_symbol) 1696cdbab7c2SFeng Tang sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); 1697cdbab7c2SFeng Tang 1698cdbab7c2SFeng Tang script_browse(script_opt); 1699cdbab7c2SFeng Tang } 1700341487abSFeng Tang /* Switch to another data file */ 1701341487abSFeng Tang else if (choice == switch_data) { 1702341487abSFeng Tang do_data_switch: 1703341487abSFeng Tang if (!switch_data_file()) { 1704341487abSFeng Tang key = K_SWITCH_INPUT_DATA; 1705341487abSFeng Tang break; 1706341487abSFeng Tang } else 1707341487abSFeng Tang ui__warning("Won't switch the data files due to\n" 1708341487abSFeng Tang "no valid data file get selected!\n"); 1709341487abSFeng Tang } 1710aca7a94dSNamhyung Kim } 1711aca7a94dSNamhyung Kim out_free_stack: 1712aca7a94dSNamhyung Kim pstack__delete(fstack); 1713aca7a94dSNamhyung Kim out: 1714aca7a94dSNamhyung Kim hist_browser__delete(browser); 1715aca7a94dSNamhyung Kim free_popup_options(options, nr_options - 1); 1716aca7a94dSNamhyung Kim return key; 1717aca7a94dSNamhyung Kim } 1718aca7a94dSNamhyung Kim 1719aca7a94dSNamhyung Kim struct perf_evsel_menu { 1720aca7a94dSNamhyung Kim struct ui_browser b; 1721aca7a94dSNamhyung Kim struct perf_evsel *selection; 1722aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 1723064f1981SNamhyung Kim float min_pcnt; 172468d80758SNamhyung Kim struct perf_session_env *env; 1725aca7a94dSNamhyung Kim }; 1726aca7a94dSNamhyung Kim 1727aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 1728aca7a94dSNamhyung Kim void *entry, int row) 1729aca7a94dSNamhyung Kim { 1730aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 1731aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 1732aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1733aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 1734aca7a94dSNamhyung Kim unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 17357289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 1736aca7a94dSNamhyung Kim char bf[256], unit; 1737aca7a94dSNamhyung Kim const char *warn = " "; 1738aca7a94dSNamhyung Kim size_t printed; 1739aca7a94dSNamhyung Kim 1740aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1741aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 1742aca7a94dSNamhyung Kim 1743759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1744717e263fSNamhyung Kim struct perf_evsel *pos; 1745717e263fSNamhyung Kim 1746717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 1747717e263fSNamhyung Kim 1748717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 1749717e263fSNamhyung Kim nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1750717e263fSNamhyung Kim } 1751717e263fSNamhyung Kim } 1752717e263fSNamhyung Kim 1753aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 1754aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1755aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 1756aca7a94dSNamhyung Kim slsmg_printf("%s", bf); 1757aca7a94dSNamhyung Kim 1758aca7a94dSNamhyung Kim nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 1759aca7a94dSNamhyung Kim if (nr_events != 0) { 1760aca7a94dSNamhyung Kim menu->lost_events = true; 1761aca7a94dSNamhyung Kim if (!current_entry) 1762aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 1763aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 1764aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 1765aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 1766aca7a94dSNamhyung Kim warn = bf; 1767aca7a94dSNamhyung Kim } 1768aca7a94dSNamhyung Kim 1769aca7a94dSNamhyung Kim slsmg_write_nstring(warn, browser->width - printed); 1770aca7a94dSNamhyung Kim 1771aca7a94dSNamhyung Kim if (current_entry) 1772aca7a94dSNamhyung Kim menu->selection = evsel; 1773aca7a94dSNamhyung Kim } 1774aca7a94dSNamhyung Kim 1775aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 1776aca7a94dSNamhyung Kim int nr_events, const char *help, 17779783adf7SNamhyung Kim struct hist_browser_timer *hbt) 1778aca7a94dSNamhyung Kim { 1779aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 1780aca7a94dSNamhyung Kim struct perf_evsel *pos; 1781aca7a94dSNamhyung Kim const char *ev_name, *title = "Available samples"; 17829783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 1783aca7a94dSNamhyung Kim int key; 1784aca7a94dSNamhyung Kim 1785aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 1786aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 1787aca7a94dSNamhyung Kim return -1; 1788aca7a94dSNamhyung Kim 1789aca7a94dSNamhyung Kim while (1) { 1790aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 1791aca7a94dSNamhyung Kim 1792aca7a94dSNamhyung Kim switch (key) { 1793aca7a94dSNamhyung Kim case K_TIMER: 17949783adf7SNamhyung Kim hbt->timer(hbt->arg); 1795aca7a94dSNamhyung Kim 1796aca7a94dSNamhyung Kim if (!menu->lost_events_warned && menu->lost_events) { 1797aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 1798aca7a94dSNamhyung Kim menu->lost_events_warned = true; 1799aca7a94dSNamhyung Kim } 1800aca7a94dSNamhyung Kim continue; 1801aca7a94dSNamhyung Kim case K_RIGHT: 1802aca7a94dSNamhyung Kim case K_ENTER: 1803aca7a94dSNamhyung Kim if (!menu->selection) 1804aca7a94dSNamhyung Kim continue; 1805aca7a94dSNamhyung Kim pos = menu->selection; 1806aca7a94dSNamhyung Kim browse_hists: 1807aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 1808aca7a94dSNamhyung Kim /* 1809aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 1810aca7a94dSNamhyung Kim * default evsel resorted hists tree. 1811aca7a94dSNamhyung Kim */ 18129783adf7SNamhyung Kim if (hbt) 18139783adf7SNamhyung Kim hbt->timer(hbt->arg); 18147289f83cSArnaldo Carvalho de Melo ev_name = perf_evsel__name(pos); 1815aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 181668d80758SNamhyung Kim ev_name, true, hbt, 1817064f1981SNamhyung Kim menu->min_pcnt, 181868d80758SNamhyung Kim menu->env); 1819aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 1820aca7a94dSNamhyung Kim switch (key) { 1821aca7a94dSNamhyung Kim case K_TAB: 1822aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 18239a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__first(evlist); 1824aca7a94dSNamhyung Kim else 18259a354cdcSArnaldo Carvalho de Melo pos = perf_evsel__next(pos); 1826aca7a94dSNamhyung Kim goto browse_hists; 1827aca7a94dSNamhyung Kim case K_UNTAB: 1828aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 18299a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__last(evlist); 1830aca7a94dSNamhyung Kim else 1831d87fcb4aSArnaldo Carvalho de Melo pos = perf_evsel__prev(pos); 1832aca7a94dSNamhyung Kim goto browse_hists; 1833aca7a94dSNamhyung Kim case K_ESC: 1834aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 1835aca7a94dSNamhyung Kim "Do you really want to exit?")) 1836aca7a94dSNamhyung Kim continue; 1837aca7a94dSNamhyung Kim /* Fall thru */ 1838341487abSFeng Tang case K_SWITCH_INPUT_DATA: 1839aca7a94dSNamhyung Kim case 'q': 1840aca7a94dSNamhyung Kim case CTRL('c'): 1841aca7a94dSNamhyung Kim goto out; 1842aca7a94dSNamhyung Kim default: 1843aca7a94dSNamhyung Kim continue; 1844aca7a94dSNamhyung Kim } 1845aca7a94dSNamhyung Kim case K_LEFT: 1846aca7a94dSNamhyung Kim continue; 1847aca7a94dSNamhyung Kim case K_ESC: 1848aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 1849aca7a94dSNamhyung Kim "Do you really want to exit?")) 1850aca7a94dSNamhyung Kim continue; 1851aca7a94dSNamhyung Kim /* Fall thru */ 1852aca7a94dSNamhyung Kim case 'q': 1853aca7a94dSNamhyung Kim case CTRL('c'): 1854aca7a94dSNamhyung Kim goto out; 1855aca7a94dSNamhyung Kim default: 1856aca7a94dSNamhyung Kim continue; 1857aca7a94dSNamhyung Kim } 1858aca7a94dSNamhyung Kim } 1859aca7a94dSNamhyung Kim 1860aca7a94dSNamhyung Kim out: 1861aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 1862aca7a94dSNamhyung Kim return key; 1863aca7a94dSNamhyung Kim } 1864aca7a94dSNamhyung Kim 1865316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 1866fc24d7c2SNamhyung Kim void *entry) 1867fc24d7c2SNamhyung Kim { 1868fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1869fc24d7c2SNamhyung Kim 1870fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 1871fc24d7c2SNamhyung Kim return true; 1872fc24d7c2SNamhyung Kim 1873fc24d7c2SNamhyung Kim return false; 1874fc24d7c2SNamhyung Kim } 1875fc24d7c2SNamhyung Kim 1876aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1877fc24d7c2SNamhyung Kim int nr_entries, const char *help, 187868d80758SNamhyung Kim struct hist_browser_timer *hbt, 1879064f1981SNamhyung Kim float min_pcnt, 188068d80758SNamhyung Kim struct perf_session_env *env) 1881aca7a94dSNamhyung Kim { 1882aca7a94dSNamhyung Kim struct perf_evsel *pos; 1883aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 1884aca7a94dSNamhyung Kim .b = { 1885aca7a94dSNamhyung Kim .entries = &evlist->entries, 1886aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 1887aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 1888aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 1889fc24d7c2SNamhyung Kim .filter = filter_group_entries, 1890fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 1891aca7a94dSNamhyung Kim .priv = evlist, 1892aca7a94dSNamhyung Kim }, 1893064f1981SNamhyung Kim .min_pcnt = min_pcnt, 189468d80758SNamhyung Kim .env = env, 1895aca7a94dSNamhyung Kim }; 1896aca7a94dSNamhyung Kim 1897aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 1898aca7a94dSNamhyung Kim 18990050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 19007289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 1901aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 1902aca7a94dSNamhyung Kim 1903aca7a94dSNamhyung Kim if (menu.b.width < line_len) 1904aca7a94dSNamhyung Kim menu.b.width = line_len; 1905aca7a94dSNamhyung Kim } 1906aca7a94dSNamhyung Kim 1907fc24d7c2SNamhyung Kim return perf_evsel_menu__run(&menu, nr_entries, help, hbt); 1908aca7a94dSNamhyung Kim } 1909aca7a94dSNamhyung Kim 1910aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 191168d80758SNamhyung Kim struct hist_browser_timer *hbt, 1912064f1981SNamhyung Kim float min_pcnt, 191368d80758SNamhyung Kim struct perf_session_env *env) 1914aca7a94dSNamhyung Kim { 1915fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 1916fc24d7c2SNamhyung Kim 1917fc24d7c2SNamhyung Kim single_entry: 1918fc24d7c2SNamhyung Kim if (nr_entries == 1) { 19199a354cdcSArnaldo Carvalho de Melo struct perf_evsel *first = perf_evlist__first(evlist); 19207289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(first); 1921fc24d7c2SNamhyung Kim 1922fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 1923064f1981SNamhyung Kim ev_name, false, hbt, min_pcnt, 1924064f1981SNamhyung Kim env); 1925aca7a94dSNamhyung Kim } 1926aca7a94dSNamhyung Kim 1927fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 1928fc24d7c2SNamhyung Kim struct perf_evsel *pos; 1929fc24d7c2SNamhyung Kim 1930fc24d7c2SNamhyung Kim nr_entries = 0; 19310050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 1932fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 1933fc24d7c2SNamhyung Kim nr_entries++; 19340050f7aaSArnaldo Carvalho de Melo } 1935fc24d7c2SNamhyung Kim 1936fc24d7c2SNamhyung Kim if (nr_entries == 1) 1937fc24d7c2SNamhyung Kim goto single_entry; 1938fc24d7c2SNamhyung Kim } 1939fc24d7c2SNamhyung Kim 1940fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 1941064f1981SNamhyung Kim hbt, min_pcnt, env); 1942aca7a94dSNamhyung Kim } 1943