1aca7a94dSNamhyung Kim #include <stdio.h> 2aca7a94dSNamhyung Kim #include <stdlib.h> 3aca7a94dSNamhyung Kim #include <string.h> 4aca7a94dSNamhyung Kim #include <linux/rbtree.h> 5aca7a94dSNamhyung Kim 6aca7a94dSNamhyung Kim #include "../../util/evsel.h" 7aca7a94dSNamhyung Kim #include "../../util/evlist.h" 8aca7a94dSNamhyung Kim #include "../../util/hist.h" 9aca7a94dSNamhyung Kim #include "../../util/pstack.h" 10aca7a94dSNamhyung Kim #include "../../util/sort.h" 11aca7a94dSNamhyung Kim #include "../../util/util.h" 1242337a22SNamhyung Kim #include "../../util/top.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" 20d755330cSJiri Olsa #include "annotate.h" 21aca7a94dSNamhyung Kim 22aca7a94dSNamhyung Kim struct hist_browser { 23aca7a94dSNamhyung Kim struct ui_browser b; 24aca7a94dSNamhyung Kim struct hists *hists; 25aca7a94dSNamhyung Kim struct hist_entry *he_selection; 26aca7a94dSNamhyung Kim struct map_symbol *selection; 27c2a51ab8SNamhyung Kim struct hist_browser_timer *hbt; 2801f00a1cSNamhyung Kim struct pstack *pstack; 29ce80d3beSKan Liang struct perf_env *env; 30aff3f3f6SArnaldo Carvalho de Melo int print_seq; 31a7cb8863SArnaldo Carvalho de Melo bool show_dso; 32025bf7eaSArnaldo Carvalho de Melo bool show_headers; 33064f1981SNamhyung Kim float min_pcnt; 34112f761fSNamhyung Kim u64 nr_non_filtered_entries; 35c3b78952SNamhyung Kim u64 nr_callchain_rows; 36aca7a94dSNamhyung Kim }; 37aca7a94dSNamhyung Kim 38f5951d56SNamhyung Kim extern void hist_browser__init_hpp(void); 39f5951d56SNamhyung Kim 401e378ebdSTaeung Song static int hists__browser_title(struct hists *hists, 411e378ebdSTaeung Song struct hist_browser_timer *hbt, 421e378ebdSTaeung Song char *bf, size_t size); 43112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb); 44aca7a94dSNamhyung Kim 45c3b78952SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 46c3b78952SNamhyung Kim float min_pcnt); 47c3b78952SNamhyung Kim 48268397cbSNamhyung Kim static bool hist_browser__has_filter(struct hist_browser *hb) 49268397cbSNamhyung Kim { 509c0fa8ddSArnaldo Carvalho de Melo return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter; 51268397cbSNamhyung Kim } 52268397cbSNamhyung Kim 534fabf3d1SHe Kuang static int hist_browser__get_folding(struct hist_browser *browser) 544fabf3d1SHe Kuang { 554fabf3d1SHe Kuang struct rb_node *nd; 564fabf3d1SHe Kuang struct hists *hists = browser->hists; 574fabf3d1SHe Kuang int unfolded_rows = 0; 584fabf3d1SHe Kuang 594fabf3d1SHe Kuang for (nd = rb_first(&hists->entries); 604fabf3d1SHe Kuang (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 614fabf3d1SHe Kuang nd = rb_next(nd)) { 624fabf3d1SHe Kuang struct hist_entry *he = 634fabf3d1SHe Kuang rb_entry(nd, struct hist_entry, rb_node); 644fabf3d1SHe Kuang 653698dab1SNamhyung Kim if (he->unfolded) 664fabf3d1SHe Kuang unfolded_rows += he->nr_rows; 674fabf3d1SHe Kuang } 684fabf3d1SHe Kuang return unfolded_rows; 694fabf3d1SHe Kuang } 704fabf3d1SHe Kuang 71c3b78952SNamhyung Kim static u32 hist_browser__nr_entries(struct hist_browser *hb) 72c3b78952SNamhyung Kim { 73c3b78952SNamhyung Kim u32 nr_entries; 74c3b78952SNamhyung Kim 75c3b78952SNamhyung Kim if (hist_browser__has_filter(hb)) 76c3b78952SNamhyung Kim nr_entries = hb->nr_non_filtered_entries; 77c3b78952SNamhyung Kim else 78c3b78952SNamhyung Kim nr_entries = hb->hists->nr_entries; 79c3b78952SNamhyung Kim 804fabf3d1SHe Kuang hb->nr_callchain_rows = hist_browser__get_folding(hb); 81c3b78952SNamhyung Kim return nr_entries + hb->nr_callchain_rows; 82c3b78952SNamhyung Kim } 83c3b78952SNamhyung Kim 84025bf7eaSArnaldo Carvalho de Melo static void hist_browser__update_rows(struct hist_browser *hb) 85025bf7eaSArnaldo Carvalho de Melo { 86025bf7eaSArnaldo Carvalho de Melo struct ui_browser *browser = &hb->b; 87025bf7eaSArnaldo Carvalho de Melo u16 header_offset = hb->show_headers ? 1 : 0, index_row; 88025bf7eaSArnaldo Carvalho de Melo 89025bf7eaSArnaldo Carvalho de Melo browser->rows = browser->height - header_offset; 90025bf7eaSArnaldo Carvalho de Melo /* 91025bf7eaSArnaldo Carvalho de Melo * Verify if we were at the last line and that line isn't 92025bf7eaSArnaldo Carvalho de Melo * visibe because we now show the header line(s). 93025bf7eaSArnaldo Carvalho de Melo */ 94025bf7eaSArnaldo Carvalho de Melo index_row = browser->index - browser->top_idx; 95025bf7eaSArnaldo Carvalho de Melo if (index_row >= browser->rows) 96025bf7eaSArnaldo Carvalho de Melo browser->index -= index_row - browser->rows + 1; 97025bf7eaSArnaldo Carvalho de Melo } 98025bf7eaSArnaldo Carvalho de Melo 99357cfff1SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct ui_browser *browser) 100aca7a94dSNamhyung Kim { 101357cfff1SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 102357cfff1SArnaldo Carvalho de Melo 103aca7a94dSNamhyung Kim /* 3 == +/- toggle symbol before actual hist_entry rendering */ 104357cfff1SArnaldo Carvalho de Melo browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]")); 105357cfff1SArnaldo Carvalho de Melo /* 106357cfff1SArnaldo Carvalho de Melo * FIXME: Just keeping existing behaviour, but this really should be 107357cfff1SArnaldo Carvalho de Melo * before updating browser->width, as it will invalidate the 108357cfff1SArnaldo Carvalho de Melo * calculation above. Fix this and the fallout in another 109357cfff1SArnaldo Carvalho de Melo * changeset. 110357cfff1SArnaldo Carvalho de Melo */ 111357cfff1SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(browser); 112025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(hb); 113aca7a94dSNamhyung Kim } 114aca7a94dSNamhyung Kim 115ca3ff33bSArnaldo Carvalho de Melo static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) 116ca3ff33bSArnaldo Carvalho de Melo { 117025bf7eaSArnaldo Carvalho de Melo u16 header_offset = browser->show_headers ? 1 : 0; 118025bf7eaSArnaldo Carvalho de Melo 119025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row + header_offset, column); 120ca3ff33bSArnaldo Carvalho de Melo } 121ca3ff33bSArnaldo Carvalho de Melo 12205e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser) 123aca7a94dSNamhyung Kim { 124c3b78952SNamhyung Kim /* 125c3b78952SNamhyung Kim * The hists__remove_entry_filter() already folds non-filtered 126c3b78952SNamhyung Kim * entries so we can assume it has 0 callchain rows. 127c3b78952SNamhyung Kim */ 128c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 129c3b78952SNamhyung Kim 130268397cbSNamhyung Kim hist_browser__update_nr_entries(browser); 131c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 132357cfff1SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(&browser->b); 13305e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 134aca7a94dSNamhyung Kim } 135aca7a94dSNamhyung Kim 136aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded) 137aca7a94dSNamhyung Kim { 138aca7a94dSNamhyung Kim return unfolded ? '-' : '+'; 139aca7a94dSNamhyung Kim } 140aca7a94dSNamhyung Kim 14105e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he) 142aca7a94dSNamhyung Kim { 1433698dab1SNamhyung Kim return he->has_children ? tree__folded_sign(he->unfolded) : ' '; 144aca7a94dSNamhyung Kim } 145aca7a94dSNamhyung Kim 14605e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl) 147aca7a94dSNamhyung Kim { 1483698dab1SNamhyung Kim return cl->has_children ? tree__folded_sign(cl->unfolded) : ' '; 149aca7a94dSNamhyung Kim } 150aca7a94dSNamhyung Kim 1513698dab1SNamhyung Kim static void callchain_list__set_folding(struct callchain_list *cl, bool unfold) 152aca7a94dSNamhyung Kim { 1533698dab1SNamhyung Kim cl->unfolded = unfold ? cl->has_children : false; 154aca7a94dSNamhyung Kim } 155aca7a94dSNamhyung Kim 15605e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 157aca7a94dSNamhyung Kim { 158aca7a94dSNamhyung Kim int n = 0; 159aca7a94dSNamhyung Kim struct rb_node *nd; 160aca7a94dSNamhyung Kim 16105e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 162aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 163aca7a94dSNamhyung Kim struct callchain_list *chain; 164aca7a94dSNamhyung Kim char folded_sign = ' '; /* No children */ 165aca7a94dSNamhyung Kim 166aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 167aca7a94dSNamhyung Kim ++n; 168aca7a94dSNamhyung Kim /* We need this because we may not have children */ 169aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 170aca7a94dSNamhyung Kim if (folded_sign == '+') 171aca7a94dSNamhyung Kim break; 172aca7a94dSNamhyung Kim } 173aca7a94dSNamhyung Kim 174aca7a94dSNamhyung Kim if (folded_sign == '-') /* Have children and they're unfolded */ 175aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(child); 176aca7a94dSNamhyung Kim } 177aca7a94dSNamhyung Kim 178aca7a94dSNamhyung Kim return n; 179aca7a94dSNamhyung Kim } 180aca7a94dSNamhyung Kim 181aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 182aca7a94dSNamhyung Kim { 183aca7a94dSNamhyung Kim struct callchain_list *chain; 184aca7a94dSNamhyung Kim bool unfolded = false; 185aca7a94dSNamhyung Kim int n = 0; 186aca7a94dSNamhyung Kim 187aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 188aca7a94dSNamhyung Kim ++n; 1893698dab1SNamhyung Kim unfolded = chain->unfolded; 190aca7a94dSNamhyung Kim } 191aca7a94dSNamhyung Kim 192aca7a94dSNamhyung Kim if (unfolded) 193aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 194aca7a94dSNamhyung Kim 195aca7a94dSNamhyung Kim return n; 196aca7a94dSNamhyung Kim } 197aca7a94dSNamhyung Kim 198aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 199aca7a94dSNamhyung Kim { 200aca7a94dSNamhyung Kim struct rb_node *nd; 201aca7a94dSNamhyung Kim int n = 0; 202aca7a94dSNamhyung Kim 203aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 204aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 205aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 206aca7a94dSNamhyung Kim } 207aca7a94dSNamhyung Kim 208aca7a94dSNamhyung Kim return n; 209aca7a94dSNamhyung Kim } 210aca7a94dSNamhyung Kim 2113698dab1SNamhyung Kim static bool hist_entry__toggle_fold(struct hist_entry *he) 212aca7a94dSNamhyung Kim { 2133698dab1SNamhyung Kim if (!he) 214aca7a94dSNamhyung Kim return false; 215aca7a94dSNamhyung Kim 2163698dab1SNamhyung Kim if (!he->has_children) 217aca7a94dSNamhyung Kim return false; 218aca7a94dSNamhyung Kim 2193698dab1SNamhyung Kim he->unfolded = !he->unfolded; 2203698dab1SNamhyung Kim return true; 2213698dab1SNamhyung Kim } 2223698dab1SNamhyung Kim 2233698dab1SNamhyung Kim static bool callchain_list__toggle_fold(struct callchain_list *cl) 2243698dab1SNamhyung Kim { 2253698dab1SNamhyung Kim if (!cl) 2263698dab1SNamhyung Kim return false; 2273698dab1SNamhyung Kim 2283698dab1SNamhyung Kim if (!cl->has_children) 2293698dab1SNamhyung Kim return false; 2303698dab1SNamhyung Kim 2313698dab1SNamhyung Kim cl->unfolded = !cl->unfolded; 232aca7a94dSNamhyung Kim return true; 233aca7a94dSNamhyung Kim } 234aca7a94dSNamhyung Kim 23505e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 236aca7a94dSNamhyung Kim { 23705e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 238aca7a94dSNamhyung Kim 23905e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 240aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 241aca7a94dSNamhyung Kim struct callchain_list *chain; 242aca7a94dSNamhyung Kim bool first = true; 243aca7a94dSNamhyung Kim 244aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 245aca7a94dSNamhyung Kim if (first) { 246aca7a94dSNamhyung Kim first = false; 2473698dab1SNamhyung Kim chain->has_children = chain->list.next != &child->val || 248aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 249aca7a94dSNamhyung Kim } else 2503698dab1SNamhyung Kim chain->has_children = chain->list.next == &child->val && 251aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 252aca7a94dSNamhyung Kim } 253aca7a94dSNamhyung Kim 254aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 255aca7a94dSNamhyung Kim } 256aca7a94dSNamhyung Kim } 257aca7a94dSNamhyung Kim 258a7444af6SNamhyung Kim static void callchain_node__init_have_children(struct callchain_node *node, 259a7444af6SNamhyung Kim bool has_sibling) 260aca7a94dSNamhyung Kim { 261aca7a94dSNamhyung Kim struct callchain_list *chain; 262aca7a94dSNamhyung Kim 263a7444af6SNamhyung Kim chain = list_entry(node->val.next, struct callchain_list, list); 2643698dab1SNamhyung Kim chain->has_children = has_sibling; 265a7444af6SNamhyung Kim 26682162b5aSNamhyung Kim if (!list_empty(&node->val)) { 26782162b5aSNamhyung Kim chain = list_entry(node->val.prev, struct callchain_list, list); 2683698dab1SNamhyung Kim chain->has_children = !RB_EMPTY_ROOT(&node->rb_root); 26982162b5aSNamhyung Kim } 270aca7a94dSNamhyung Kim 27105e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 272aca7a94dSNamhyung Kim } 273aca7a94dSNamhyung Kim 27405e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 275aca7a94dSNamhyung Kim { 276a7444af6SNamhyung Kim struct rb_node *nd = rb_first(root); 277a7444af6SNamhyung Kim bool has_sibling = nd && rb_next(nd); 278aca7a94dSNamhyung Kim 27905e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 280aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 281a7444af6SNamhyung Kim callchain_node__init_have_children(node, has_sibling); 282aca7a94dSNamhyung Kim } 283aca7a94dSNamhyung Kim } 284aca7a94dSNamhyung Kim 28505e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 286aca7a94dSNamhyung Kim { 28705e8b080SArnaldo Carvalho de Melo if (!he->init_have_children) { 2883698dab1SNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 28905e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 29005e8b080SArnaldo Carvalho de Melo he->init_have_children = true; 291aca7a94dSNamhyung Kim } 292aca7a94dSNamhyung Kim } 293aca7a94dSNamhyung Kim 29405e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 295aca7a94dSNamhyung Kim { 29605e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 2973698dab1SNamhyung Kim struct map_symbol *ms = browser->selection; 2983698dab1SNamhyung Kim struct callchain_list *cl = container_of(ms, struct callchain_list, ms); 2993698dab1SNamhyung Kim bool has_children; 300aca7a94dSNamhyung Kim 3013698dab1SNamhyung Kim if (ms == &he->ms) 3023698dab1SNamhyung Kim has_children = hist_entry__toggle_fold(he); 3033698dab1SNamhyung Kim else 3043698dab1SNamhyung Kim has_children = callchain_list__toggle_fold(cl); 3053698dab1SNamhyung Kim 3063698dab1SNamhyung Kim if (has_children) { 307aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 308c3b78952SNamhyung Kim browser->b.nr_entries -= he->nr_rows; 309c3b78952SNamhyung Kim browser->nr_callchain_rows -= he->nr_rows; 310aca7a94dSNamhyung Kim 3113698dab1SNamhyung Kim if (he->unfolded) 312aca7a94dSNamhyung Kim he->nr_rows = callchain__count_rows(&he->sorted_chain); 313aca7a94dSNamhyung Kim else 314aca7a94dSNamhyung Kim he->nr_rows = 0; 315c3b78952SNamhyung Kim 316c3b78952SNamhyung Kim browser->b.nr_entries += he->nr_rows; 317c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 318aca7a94dSNamhyung Kim 319aca7a94dSNamhyung Kim return true; 320aca7a94dSNamhyung Kim } 321aca7a94dSNamhyung Kim 322aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 323aca7a94dSNamhyung Kim return false; 324aca7a94dSNamhyung Kim } 325aca7a94dSNamhyung Kim 32605e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 327aca7a94dSNamhyung Kim { 328aca7a94dSNamhyung Kim int n = 0; 329aca7a94dSNamhyung Kim struct rb_node *nd; 330aca7a94dSNamhyung Kim 33105e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 332aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 333aca7a94dSNamhyung Kim struct callchain_list *chain; 334aca7a94dSNamhyung Kim bool has_children = false; 335aca7a94dSNamhyung Kim 336aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 337aca7a94dSNamhyung Kim ++n; 3383698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 3393698dab1SNamhyung Kim has_children = chain->has_children; 340aca7a94dSNamhyung Kim } 341aca7a94dSNamhyung Kim 342aca7a94dSNamhyung Kim if (has_children) 343aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 344aca7a94dSNamhyung Kim } 345aca7a94dSNamhyung Kim 346aca7a94dSNamhyung Kim return n; 347aca7a94dSNamhyung Kim } 348aca7a94dSNamhyung Kim 349aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 350aca7a94dSNamhyung Kim { 351aca7a94dSNamhyung Kim struct callchain_list *chain; 352aca7a94dSNamhyung Kim bool has_children = false; 353aca7a94dSNamhyung Kim int n = 0; 354aca7a94dSNamhyung Kim 355aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 356aca7a94dSNamhyung Kim ++n; 3573698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 3583698dab1SNamhyung Kim has_children = chain->has_children; 359aca7a94dSNamhyung Kim } 360aca7a94dSNamhyung Kim 361aca7a94dSNamhyung Kim if (has_children) 362aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 363aca7a94dSNamhyung Kim 364aca7a94dSNamhyung Kim return n; 365aca7a94dSNamhyung Kim } 366aca7a94dSNamhyung Kim 367aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 368aca7a94dSNamhyung Kim { 369aca7a94dSNamhyung Kim struct rb_node *nd; 370aca7a94dSNamhyung Kim int n = 0; 371aca7a94dSNamhyung Kim 372aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 373aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 374aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 375aca7a94dSNamhyung Kim } 376aca7a94dSNamhyung Kim 377aca7a94dSNamhyung Kim return n; 378aca7a94dSNamhyung Kim } 379aca7a94dSNamhyung Kim 38005e8b080SArnaldo Carvalho de Melo static void hist_entry__set_folding(struct hist_entry *he, bool unfold) 381aca7a94dSNamhyung Kim { 38205e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 3833698dab1SNamhyung Kim he->unfolded = unfold ? he->has_children : false; 384aca7a94dSNamhyung Kim 3853698dab1SNamhyung Kim if (he->has_children) { 38605e8b080SArnaldo Carvalho de Melo int n = callchain__set_folding(&he->sorted_chain, unfold); 38705e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 388aca7a94dSNamhyung Kim } else 38905e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 390aca7a94dSNamhyung Kim } 391aca7a94dSNamhyung Kim 392c3b78952SNamhyung Kim static void 393c3b78952SNamhyung Kim __hist_browser__set_folding(struct hist_browser *browser, bool unfold) 394aca7a94dSNamhyung Kim { 395aca7a94dSNamhyung Kim struct rb_node *nd; 396c3b78952SNamhyung Kim struct hists *hists = browser->hists; 397aca7a94dSNamhyung Kim 398c3b78952SNamhyung Kim for (nd = rb_first(&hists->entries); 39914135663SNamhyung Kim (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 400c3b78952SNamhyung Kim nd = rb_next(nd)) { 401aca7a94dSNamhyung Kim struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 402aca7a94dSNamhyung Kim hist_entry__set_folding(he, unfold); 403c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 404aca7a94dSNamhyung Kim } 405aca7a94dSNamhyung Kim } 406aca7a94dSNamhyung Kim 40705e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 408aca7a94dSNamhyung Kim { 409c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 410c3b78952SNamhyung Kim __hist_browser__set_folding(browser, unfold); 411c3b78952SNamhyung Kim 412c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 413aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 41405e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 415aca7a94dSNamhyung Kim } 416aca7a94dSNamhyung Kim 417aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 418aca7a94dSNamhyung Kim { 419aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 420aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 421aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 422aca7a94dSNamhyung Kim " perf top -r 80\n\n" 423aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 424aca7a94dSNamhyung Kim } 425aca7a94dSNamhyung Kim 4265f00b0f4SArnaldo Carvalho de Melo static int hist_browser__run(struct hist_browser *browser, const char *help) 427aca7a94dSNamhyung Kim { 428aca7a94dSNamhyung Kim int key; 429aca7a94dSNamhyung Kim char title[160]; 430c2a51ab8SNamhyung Kim struct hist_browser_timer *hbt = browser->hbt; 4319783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 432aca7a94dSNamhyung Kim 43305e8b080SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 434c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 435aca7a94dSNamhyung Kim 4361e378ebdSTaeung Song hists__browser_title(browser->hists, hbt, title, sizeof(title)); 437aca7a94dSNamhyung Kim 4385f00b0f4SArnaldo Carvalho de Melo if (ui_browser__show(&browser->b, title, help) < 0) 439aca7a94dSNamhyung Kim return -1; 440aca7a94dSNamhyung Kim 441aca7a94dSNamhyung Kim while (1) { 44205e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 443aca7a94dSNamhyung Kim 444aca7a94dSNamhyung Kim switch (key) { 445fa5df943SNamhyung Kim case K_TIMER: { 446fa5df943SNamhyung Kim u64 nr_entries; 4479783adf7SNamhyung Kim hbt->timer(hbt->arg); 448fa5df943SNamhyung Kim 449c3b78952SNamhyung Kim if (hist_browser__has_filter(browser)) 450112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 451fa5df943SNamhyung Kim 452c3b78952SNamhyung Kim nr_entries = hist_browser__nr_entries(browser); 453fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 454aca7a94dSNamhyung Kim 45505e8b080SArnaldo Carvalho de Melo if (browser->hists->stats.nr_lost_warned != 45605e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]) { 45705e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 45805e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 45905e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 460aca7a94dSNamhyung Kim } 461aca7a94dSNamhyung Kim 4621e378ebdSTaeung Song hists__browser_title(browser->hists, 4631e378ebdSTaeung Song hbt, title, sizeof(title)); 46405e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 465aca7a94dSNamhyung Kim continue; 466fa5df943SNamhyung Kim } 467aca7a94dSNamhyung Kim case 'D': { /* Debug */ 468aca7a94dSNamhyung Kim static int seq; 46905e8b080SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, 470aca7a94dSNamhyung Kim struct hist_entry, rb_node); 471aca7a94dSNamhyung Kim ui_helpline__pop(); 47262c95ae3SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 47305e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 47405e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries, 47562c95ae3SArnaldo Carvalho de Melo browser->b.rows, 47605e8b080SArnaldo Carvalho de Melo browser->b.index, 47705e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 478aca7a94dSNamhyung Kim h->row_offset, h->nr_rows); 479aca7a94dSNamhyung Kim } 480aca7a94dSNamhyung Kim break; 481aca7a94dSNamhyung Kim case 'C': 482aca7a94dSNamhyung Kim /* Collapse the whole world. */ 48305e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 484aca7a94dSNamhyung Kim break; 485aca7a94dSNamhyung Kim case 'E': 486aca7a94dSNamhyung Kim /* Expand the whole world. */ 48705e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 488aca7a94dSNamhyung Kim break; 489025bf7eaSArnaldo Carvalho de Melo case 'H': 490025bf7eaSArnaldo Carvalho de Melo browser->show_headers = !browser->show_headers; 491025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(browser); 492025bf7eaSArnaldo Carvalho de Melo break; 493aca7a94dSNamhyung Kim case K_ENTER: 49405e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 495aca7a94dSNamhyung Kim break; 496aca7a94dSNamhyung Kim /* fall thru */ 497aca7a94dSNamhyung Kim default: 498aca7a94dSNamhyung Kim goto out; 499aca7a94dSNamhyung Kim } 500aca7a94dSNamhyung Kim } 501aca7a94dSNamhyung Kim out: 50205e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 503aca7a94dSNamhyung Kim return key; 504aca7a94dSNamhyung Kim } 505aca7a94dSNamhyung Kim 50639ee533fSNamhyung Kim struct callchain_print_arg { 50739ee533fSNamhyung Kim /* for hists browser */ 50839ee533fSNamhyung Kim off_t row_offset; 50939ee533fSNamhyung Kim bool is_current_entry; 51039ee533fSNamhyung Kim 51139ee533fSNamhyung Kim /* for file dump */ 51239ee533fSNamhyung Kim FILE *fp; 51339ee533fSNamhyung Kim int printed; 51439ee533fSNamhyung Kim }; 51539ee533fSNamhyung Kim 51639ee533fSNamhyung Kim typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, 51739ee533fSNamhyung Kim struct callchain_list *chain, 51839ee533fSNamhyung Kim const char *str, int offset, 51939ee533fSNamhyung Kim unsigned short row, 52039ee533fSNamhyung Kim struct callchain_print_arg *arg); 52139ee533fSNamhyung Kim 522f4536dddSNamhyung Kim static void hist_browser__show_callchain_entry(struct hist_browser *browser, 523f4536dddSNamhyung Kim struct callchain_list *chain, 52439ee533fSNamhyung Kim const char *str, int offset, 52539ee533fSNamhyung Kim unsigned short row, 52639ee533fSNamhyung Kim struct callchain_print_arg *arg) 527f4536dddSNamhyung Kim { 528f4536dddSNamhyung Kim int color, width; 52939ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 53070e97278SArnaldo Carvalho de Melo bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src; 531f4536dddSNamhyung Kim 532f4536dddSNamhyung Kim color = HE_COLORSET_NORMAL; 533f4536dddSNamhyung Kim width = browser->b.width - (offset + 2); 534f4536dddSNamhyung Kim if (ui_browser__is_current_entry(&browser->b, row)) { 535f4536dddSNamhyung Kim browser->selection = &chain->ms; 536f4536dddSNamhyung Kim color = HE_COLORSET_SELECTED; 53739ee533fSNamhyung Kim arg->is_current_entry = true; 538f4536dddSNamhyung Kim } 539f4536dddSNamhyung Kim 540f4536dddSNamhyung Kim ui_browser__set_color(&browser->b, color); 541f4536dddSNamhyung Kim hist_browser__gotorc(browser, row, 0); 54226270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, " ", offset); 543517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c", folded_sign); 54470e97278SArnaldo Carvalho de Melo ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); 54526270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, str, width); 546f4536dddSNamhyung Kim } 547f4536dddSNamhyung Kim 54839ee533fSNamhyung Kim static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, 54939ee533fSNamhyung Kim struct callchain_list *chain, 55039ee533fSNamhyung Kim const char *str, int offset, 55139ee533fSNamhyung Kim unsigned short row __maybe_unused, 55239ee533fSNamhyung Kim struct callchain_print_arg *arg) 55339ee533fSNamhyung Kim { 55439ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 55539ee533fSNamhyung Kim 55639ee533fSNamhyung Kim arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", 55739ee533fSNamhyung Kim folded_sign, str); 55839ee533fSNamhyung Kim } 55939ee533fSNamhyung Kim 56039ee533fSNamhyung Kim typedef bool (*check_output_full_fn)(struct hist_browser *browser, 56139ee533fSNamhyung Kim unsigned short row); 56239ee533fSNamhyung Kim 56339ee533fSNamhyung Kim static bool hist_browser__check_output_full(struct hist_browser *browser, 56439ee533fSNamhyung Kim unsigned short row) 56539ee533fSNamhyung Kim { 56639ee533fSNamhyung Kim return browser->b.rows == row; 56739ee533fSNamhyung Kim } 56839ee533fSNamhyung Kim 56939ee533fSNamhyung Kim static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, 57039ee533fSNamhyung Kim unsigned short row __maybe_unused) 57139ee533fSNamhyung Kim { 57239ee533fSNamhyung Kim return false; 57339ee533fSNamhyung Kim } 57439ee533fSNamhyung Kim 575aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 576aca7a94dSNamhyung Kim 577c09a7e75SNamhyung Kim static int hist_browser__show_callchain(struct hist_browser *browser, 578c09a7e75SNamhyung Kim struct rb_root *root, int level, 57939ee533fSNamhyung Kim unsigned short row, u64 total, 58039ee533fSNamhyung Kim print_callchain_entry_fn print, 58139ee533fSNamhyung Kim struct callchain_print_arg *arg, 58239ee533fSNamhyung Kim check_output_full_fn is_output_full) 583aca7a94dSNamhyung Kim { 584aca7a94dSNamhyung Kim struct rb_node *node; 585f4536dddSNamhyung Kim int first_row = row, offset = level * LEVEL_OFFSET_STEP; 58636e15dd4SNamhyung Kim u64 new_total; 5874087d11cSNamhyung Kim bool need_percent; 588aca7a94dSNamhyung Kim 589c09a7e75SNamhyung Kim node = rb_first(root); 590c09e31ccSNamhyung Kim need_percent = node && rb_next(node); 5914087d11cSNamhyung Kim 592aca7a94dSNamhyung Kim while (node) { 593aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 594aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 595aca7a94dSNamhyung Kim u64 cumul = callchain_cumul_hits(child); 596aca7a94dSNamhyung Kim struct callchain_list *chain; 597aca7a94dSNamhyung Kim char folded_sign = ' '; 598aca7a94dSNamhyung Kim int first = true; 599aca7a94dSNamhyung Kim int extra_offset = 0; 600aca7a94dSNamhyung Kim 601aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 602a7cb8863SArnaldo Carvalho de Melo char bf[1024], *alloc_str; 603aca7a94dSNamhyung Kim const char *str; 604aca7a94dSNamhyung Kim bool was_first = first; 605aca7a94dSNamhyung Kim 606aca7a94dSNamhyung Kim if (first) 607aca7a94dSNamhyung Kim first = false; 6084087d11cSNamhyung Kim else if (need_percent) 609aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 610aca7a94dSNamhyung Kim 611aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 61239ee533fSNamhyung Kim if (arg->row_offset != 0) { 61339ee533fSNamhyung Kim arg->row_offset--; 614aca7a94dSNamhyung Kim goto do_next; 615aca7a94dSNamhyung Kim } 616aca7a94dSNamhyung Kim 617aca7a94dSNamhyung Kim alloc_str = NULL; 618a7cb8863SArnaldo Carvalho de Melo str = callchain_list__sym_name(chain, bf, sizeof(bf), 619a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 620c09a7e75SNamhyung Kim 6214087d11cSNamhyung Kim if (was_first && need_percent) { 622c09a7e75SNamhyung Kim double percent = cumul * 100.0 / total; 623aca7a94dSNamhyung Kim 624aca7a94dSNamhyung Kim if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 625aca7a94dSNamhyung Kim str = "Not enough memory!"; 626aca7a94dSNamhyung Kim else 627aca7a94dSNamhyung Kim str = alloc_str; 628aca7a94dSNamhyung Kim } 629aca7a94dSNamhyung Kim 63039ee533fSNamhyung Kim print(browser, chain, str, offset + extra_offset, row, arg); 63139ee533fSNamhyung Kim 632aca7a94dSNamhyung Kim free(alloc_str); 633aca7a94dSNamhyung Kim 63439ee533fSNamhyung Kim if (is_output_full(browser, ++row)) 635aca7a94dSNamhyung Kim goto out; 636aca7a94dSNamhyung Kim do_next: 637aca7a94dSNamhyung Kim if (folded_sign == '+') 638aca7a94dSNamhyung Kim break; 639aca7a94dSNamhyung Kim } 640aca7a94dSNamhyung Kim 641aca7a94dSNamhyung Kim if (folded_sign == '-') { 642aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 643c09a7e75SNamhyung Kim 644c09a7e75SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 645c09a7e75SNamhyung Kim new_total = child->children_hit; 646c09a7e75SNamhyung Kim else 647c09a7e75SNamhyung Kim new_total = total; 648c09a7e75SNamhyung Kim 649c09a7e75SNamhyung Kim row += hist_browser__show_callchain(browser, &child->rb_root, 65039ee533fSNamhyung Kim new_level, row, new_total, 65139ee533fSNamhyung Kim print, arg, is_output_full); 652aca7a94dSNamhyung Kim } 65339ee533fSNamhyung Kim if (is_output_full(browser, row)) 654c09a7e75SNamhyung Kim break; 655aca7a94dSNamhyung Kim node = next; 656aca7a94dSNamhyung Kim } 657aca7a94dSNamhyung Kim out: 658aca7a94dSNamhyung Kim return row - first_row; 659aca7a94dSNamhyung Kim } 660aca7a94dSNamhyung Kim 66189701460SNamhyung Kim struct hpp_arg { 66289701460SNamhyung Kim struct ui_browser *b; 66389701460SNamhyung Kim char folded_sign; 66489701460SNamhyung Kim bool current_entry; 66589701460SNamhyung Kim }; 66689701460SNamhyung Kim 6672f6d9009SNamhyung Kim static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 6682f6d9009SNamhyung Kim { 6692f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 670d675107cSNamhyung Kim int ret, len; 6712f6d9009SNamhyung Kim va_list args; 6722f6d9009SNamhyung Kim double percent; 6732f6d9009SNamhyung Kim 6742f6d9009SNamhyung Kim va_start(args, fmt); 675d675107cSNamhyung Kim len = va_arg(args, int); 6762f6d9009SNamhyung Kim percent = va_arg(args, double); 6772f6d9009SNamhyung Kim va_end(args); 6785aed9d24SNamhyung Kim 67989701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 6805aed9d24SNamhyung Kim 681d675107cSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); 682517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); 68389701460SNamhyung Kim 6842f6d9009SNamhyung Kim advance_hpp(hpp, ret); 6855aed9d24SNamhyung Kim return ret; 686f5951d56SNamhyung Kim } 687f5951d56SNamhyung Kim 688fb821c9eSNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field) \ 6895aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 6905aed9d24SNamhyung Kim { \ 6915aed9d24SNamhyung Kim return he->stat._field; \ 6925aed9d24SNamhyung Kim } \ 6935aed9d24SNamhyung Kim \ 6942c5d4b4aSJiri Olsa static int \ 6955b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 6962c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 6975aed9d24SNamhyung Kim struct hist_entry *he) \ 6985aed9d24SNamhyung Kim { \ 6995b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \ 7002f6d9009SNamhyung Kim __hpp__slsmg_color_printf, true); \ 7015aed9d24SNamhyung Kim } 702f5951d56SNamhyung Kim 7030434ddd2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 7040434ddd2SNamhyung Kim static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ 7050434ddd2SNamhyung Kim { \ 7060434ddd2SNamhyung Kim return he->stat_acc->_field; \ 7070434ddd2SNamhyung Kim } \ 7080434ddd2SNamhyung Kim \ 7090434ddd2SNamhyung Kim static int \ 7105b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 7110434ddd2SNamhyung Kim struct perf_hpp *hpp, \ 7120434ddd2SNamhyung Kim struct hist_entry *he) \ 7130434ddd2SNamhyung Kim { \ 7140434ddd2SNamhyung Kim if (!symbol_conf.cumulate_callchain) { \ 715517dfdb3SArnaldo Carvalho de Melo struct hpp_arg *arg = hpp->ptr; \ 7165b591669SNamhyung Kim int len = fmt->user_len ?: fmt->len; \ 717d675107cSNamhyung Kim int ret = scnprintf(hpp->buf, hpp->size, \ 7185b591669SNamhyung Kim "%*s", len, "N/A"); \ 719517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); \ 7200434ddd2SNamhyung Kim \ 7210434ddd2SNamhyung Kim return ret; \ 7220434ddd2SNamhyung Kim } \ 7235b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \ 7245b591669SNamhyung Kim " %*.2f%%", __hpp__slsmg_color_printf, true); \ 7250434ddd2SNamhyung Kim } 7260434ddd2SNamhyung Kim 727fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period) 728fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 729fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us) 730fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 731fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 7320434ddd2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period) 7335aed9d24SNamhyung Kim 7345aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 7350434ddd2SNamhyung Kim #undef __HPP_COLOR_ACC_PERCENT_FN 736f5951d56SNamhyung Kim 737f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 738f5951d56SNamhyung Kim { 739f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 740f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 741f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 742f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 743f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 744f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 745f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 746f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 747f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 748f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 7490434ddd2SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = 7500434ddd2SNamhyung Kim hist_browser__hpp_color_overhead_acc; 751f5951d56SNamhyung Kim } 752f5951d56SNamhyung Kim 75305e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 754aca7a94dSNamhyung Kim struct hist_entry *entry, 755aca7a94dSNamhyung Kim unsigned short row) 756aca7a94dSNamhyung Kim { 757aca7a94dSNamhyung Kim char s[256]; 7581240005eSJiri Olsa int printed = 0; 75967d25916SNamhyung Kim int width = browser->b.width; 760aca7a94dSNamhyung Kim char folded_sign = ' '; 76105e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 762aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 76363a1a3d8SNamhyung Kim bool first = true; 7641240005eSJiri Olsa struct perf_hpp_fmt *fmt; 765aca7a94dSNamhyung Kim 766aca7a94dSNamhyung Kim if (current_entry) { 76705e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 76805e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 769aca7a94dSNamhyung Kim } 770aca7a94dSNamhyung Kim 771aca7a94dSNamhyung Kim if (symbol_conf.use_callchain) { 772aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 773aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 774aca7a94dSNamhyung Kim } 775aca7a94dSNamhyung Kim 776aca7a94dSNamhyung Kim if (row_offset == 0) { 77789701460SNamhyung Kim struct hpp_arg arg = { 77889701460SNamhyung Kim .b = &browser->b, 77989701460SNamhyung Kim .folded_sign = folded_sign, 78089701460SNamhyung Kim .current_entry = current_entry, 78189701460SNamhyung Kim }; 782f5951d56SNamhyung Kim struct perf_hpp hpp = { 783f5951d56SNamhyung Kim .buf = s, 784f5951d56SNamhyung Kim .size = sizeof(s), 78589701460SNamhyung Kim .ptr = &arg, 786f5951d56SNamhyung Kim }; 787c6c3c02dSArnaldo Carvalho de Melo int column = 0; 788f5951d56SNamhyung Kim 789ca3ff33bSArnaldo Carvalho de Melo hist_browser__gotorc(browser, row, 0); 790f5951d56SNamhyung Kim 7911240005eSJiri Olsa perf_hpp__for_each_format(fmt) { 792c6c3c02dSArnaldo Carvalho de Melo if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) 793e67d49a7SNamhyung Kim continue; 794e67d49a7SNamhyung Kim 795fb821c9eSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 796fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 797fb821c9eSNamhyung Kim HE_COLORSET_SELECTED); 798fb821c9eSNamhyung Kim } else { 799fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 800fb821c9eSNamhyung Kim HE_COLORSET_NORMAL); 801fb821c9eSNamhyung Kim } 802fb821c9eSNamhyung Kim 803fb821c9eSNamhyung Kim if (first) { 804fb821c9eSNamhyung Kim if (symbol_conf.use_callchain) { 805517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c ", folded_sign); 806f5951d56SNamhyung Kim width -= 2; 807f5951d56SNamhyung Kim } 80863a1a3d8SNamhyung Kim first = false; 809fb821c9eSNamhyung Kim } else { 810517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, " "); 811fb821c9eSNamhyung Kim width -= 2; 812fb821c9eSNamhyung Kim } 813f5951d56SNamhyung Kim 8141240005eSJiri Olsa if (fmt->color) { 8152c5d4b4aSJiri Olsa width -= fmt->color(fmt, &hpp, entry); 816f5951d56SNamhyung Kim } else { 8172c5d4b4aSJiri Olsa width -= fmt->entry(fmt, &hpp, entry); 818517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s); 819f5951d56SNamhyung Kim } 820f5951d56SNamhyung Kim } 821aca7a94dSNamhyung Kim 822aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 82305e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 824aca7a94dSNamhyung Kim width += 1; 825aca7a94dSNamhyung Kim 82626270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, "", width); 82726d8b338SNamhyung Kim 828aca7a94dSNamhyung Kim ++row; 829aca7a94dSNamhyung Kim ++printed; 830aca7a94dSNamhyung Kim } else 831aca7a94dSNamhyung Kim --row_offset; 832aca7a94dSNamhyung Kim 83362c95ae3SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.rows) { 834c09a7e75SNamhyung Kim u64 total = hists__total_period(entry->hists); 83539ee533fSNamhyung Kim struct callchain_print_arg arg = { 83639ee533fSNamhyung Kim .row_offset = row_offset, 83739ee533fSNamhyung Kim .is_current_entry = current_entry, 83839ee533fSNamhyung Kim }; 839c09a7e75SNamhyung Kim 8404087d11cSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) { 8414087d11cSNamhyung Kim if (symbol_conf.cumulate_callchain) 8424087d11cSNamhyung Kim total = entry->stat_acc->period; 8434087d11cSNamhyung Kim else 8444087d11cSNamhyung Kim total = entry->stat.period; 8454087d11cSNamhyung Kim } 8464087d11cSNamhyung Kim 847c09a7e75SNamhyung Kim printed += hist_browser__show_callchain(browser, 84839ee533fSNamhyung Kim &entry->sorted_chain, 1, row, total, 84939ee533fSNamhyung Kim hist_browser__show_callchain_entry, &arg, 85039ee533fSNamhyung Kim hist_browser__check_output_full); 851c09a7e75SNamhyung Kim 85239ee533fSNamhyung Kim if (arg.is_current_entry) 85305e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 854aca7a94dSNamhyung Kim } 855aca7a94dSNamhyung Kim 856aca7a94dSNamhyung Kim return printed; 857aca7a94dSNamhyung Kim } 858aca7a94dSNamhyung Kim 85981a888feSJiri Olsa static int advance_hpp_check(struct perf_hpp *hpp, int inc) 86081a888feSJiri Olsa { 86181a888feSJiri Olsa advance_hpp(hpp, inc); 86281a888feSJiri Olsa return hpp->size <= 0; 86381a888feSJiri Olsa } 86481a888feSJiri Olsa 865c6c3c02dSArnaldo Carvalho de Melo static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size) 86681a888feSJiri Olsa { 867c6c3c02dSArnaldo Carvalho de Melo struct hists *hists = browser->hists; 86881a888feSJiri Olsa struct perf_hpp dummy_hpp = { 86981a888feSJiri Olsa .buf = buf, 87081a888feSJiri Olsa .size = size, 87181a888feSJiri Olsa }; 87281a888feSJiri Olsa struct perf_hpp_fmt *fmt; 87381a888feSJiri Olsa size_t ret = 0; 874c6c3c02dSArnaldo Carvalho de Melo int column = 0; 87581a888feSJiri Olsa 87681a888feSJiri Olsa if (symbol_conf.use_callchain) { 87781a888feSJiri Olsa ret = scnprintf(buf, size, " "); 87881a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 87981a888feSJiri Olsa return ret; 88081a888feSJiri Olsa } 88181a888feSJiri Olsa 88281a888feSJiri Olsa perf_hpp__for_each_format(fmt) { 883c6c3c02dSArnaldo Carvalho de Melo if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) 88481a888feSJiri Olsa continue; 88581a888feSJiri Olsa 88681a888feSJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); 88781a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 88881a888feSJiri Olsa break; 88981a888feSJiri Olsa 89081a888feSJiri Olsa ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 89181a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 89281a888feSJiri Olsa break; 89381a888feSJiri Olsa } 89481a888feSJiri Olsa 89581a888feSJiri Olsa return ret; 89681a888feSJiri Olsa } 89781a888feSJiri Olsa 898025bf7eaSArnaldo Carvalho de Melo static void hist_browser__show_headers(struct hist_browser *browser) 899025bf7eaSArnaldo Carvalho de Melo { 90081a888feSJiri Olsa char headers[1024]; 90181a888feSJiri Olsa 902c6c3c02dSArnaldo Carvalho de Melo hists_browser__scnprintf_headers(browser, headers, sizeof(headers)); 903025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, 0, 0); 904025bf7eaSArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 90526270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 906025bf7eaSArnaldo Carvalho de Melo } 907025bf7eaSArnaldo Carvalho de Melo 908aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 909aca7a94dSNamhyung Kim { 910aca7a94dSNamhyung Kim if (browser->top == NULL) { 911aca7a94dSNamhyung Kim struct hist_browser *hb; 912aca7a94dSNamhyung Kim 913aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 914aca7a94dSNamhyung Kim browser->top = rb_first(&hb->hists->entries); 915aca7a94dSNamhyung Kim } 916aca7a94dSNamhyung Kim } 917aca7a94dSNamhyung Kim 91805e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 919aca7a94dSNamhyung Kim { 920aca7a94dSNamhyung Kim unsigned row = 0; 921025bf7eaSArnaldo Carvalho de Melo u16 header_offset = 0; 922aca7a94dSNamhyung Kim struct rb_node *nd; 92305e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 924aca7a94dSNamhyung Kim 925025bf7eaSArnaldo Carvalho de Melo if (hb->show_headers) { 926025bf7eaSArnaldo Carvalho de Melo hist_browser__show_headers(hb); 927025bf7eaSArnaldo Carvalho de Melo header_offset = 1; 928025bf7eaSArnaldo Carvalho de Melo } 929025bf7eaSArnaldo Carvalho de Melo 93005e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 931*979d2cacSWang Nan hb->he_selection = NULL; 932*979d2cacSWang Nan hb->selection = NULL; 933aca7a94dSNamhyung Kim 93405e8b080SArnaldo Carvalho de Melo for (nd = browser->top; nd; nd = rb_next(nd)) { 935aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 93614135663SNamhyung Kim float percent; 937aca7a94dSNamhyung Kim 938aca7a94dSNamhyung Kim if (h->filtered) 939aca7a94dSNamhyung Kim continue; 940aca7a94dSNamhyung Kim 94114135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 942064f1981SNamhyung Kim if (percent < hb->min_pcnt) 943064f1981SNamhyung Kim continue; 944064f1981SNamhyung Kim 945aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 94662c95ae3SArnaldo Carvalho de Melo if (row == browser->rows) 947aca7a94dSNamhyung Kim break; 948aca7a94dSNamhyung Kim } 949aca7a94dSNamhyung Kim 950025bf7eaSArnaldo Carvalho de Melo return row + header_offset; 951aca7a94dSNamhyung Kim } 952aca7a94dSNamhyung Kim 953064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 954064f1981SNamhyung Kim float min_pcnt) 955aca7a94dSNamhyung Kim { 956aca7a94dSNamhyung Kim while (nd != NULL) { 957aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 95814135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 959064f1981SNamhyung Kim 960c0f1527bSNamhyung Kim if (!h->filtered && percent >= min_pcnt) 961aca7a94dSNamhyung Kim return nd; 962aca7a94dSNamhyung Kim 963aca7a94dSNamhyung Kim nd = rb_next(nd); 964aca7a94dSNamhyung Kim } 965aca7a94dSNamhyung Kim 966aca7a94dSNamhyung Kim return NULL; 967aca7a94dSNamhyung Kim } 968aca7a94dSNamhyung Kim 969064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 970064f1981SNamhyung Kim float min_pcnt) 971aca7a94dSNamhyung Kim { 972aca7a94dSNamhyung Kim while (nd != NULL) { 973aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 97414135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 975064f1981SNamhyung Kim 976064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 977aca7a94dSNamhyung Kim return nd; 978aca7a94dSNamhyung Kim 979aca7a94dSNamhyung Kim nd = rb_prev(nd); 980aca7a94dSNamhyung Kim } 981aca7a94dSNamhyung Kim 982aca7a94dSNamhyung Kim return NULL; 983aca7a94dSNamhyung Kim } 984aca7a94dSNamhyung Kim 98505e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 986aca7a94dSNamhyung Kim off_t offset, int whence) 987aca7a94dSNamhyung Kim { 988aca7a94dSNamhyung Kim struct hist_entry *h; 989aca7a94dSNamhyung Kim struct rb_node *nd; 990aca7a94dSNamhyung Kim bool first = true; 991064f1981SNamhyung Kim struct hist_browser *hb; 992064f1981SNamhyung Kim 993064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 994aca7a94dSNamhyung Kim 99505e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 996aca7a94dSNamhyung Kim return; 997aca7a94dSNamhyung Kim 99805e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 999aca7a94dSNamhyung Kim 1000aca7a94dSNamhyung Kim switch (whence) { 1001aca7a94dSNamhyung Kim case SEEK_SET: 1002064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 100314135663SNamhyung Kim hb->min_pcnt); 1004aca7a94dSNamhyung Kim break; 1005aca7a94dSNamhyung Kim case SEEK_CUR: 100605e8b080SArnaldo Carvalho de Melo nd = browser->top; 1007aca7a94dSNamhyung Kim goto do_offset; 1008aca7a94dSNamhyung Kim case SEEK_END: 1009064f1981SNamhyung Kim nd = hists__filter_prev_entries(rb_last(browser->entries), 101014135663SNamhyung Kim hb->min_pcnt); 1011aca7a94dSNamhyung Kim first = false; 1012aca7a94dSNamhyung Kim break; 1013aca7a94dSNamhyung Kim default: 1014aca7a94dSNamhyung Kim return; 1015aca7a94dSNamhyung Kim } 1016aca7a94dSNamhyung Kim 1017aca7a94dSNamhyung Kim /* 1018aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 1019aca7a94dSNamhyung Kim * row_offset: 1020aca7a94dSNamhyung Kim */ 102105e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 1022aca7a94dSNamhyung Kim h->row_offset = 0; 1023aca7a94dSNamhyung Kim 1024aca7a94dSNamhyung Kim /* 1025aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 1026aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 1027aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 1028aca7a94dSNamhyung Kim * 1029aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 1030aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 1031aca7a94dSNamhyung Kim * 1032aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 1033aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 1034aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 1035aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 1036aca7a94dSNamhyung Kim */ 1037aca7a94dSNamhyung Kim do_offset: 1038837eeb75SWang Nan if (!nd) 1039837eeb75SWang Nan return; 1040837eeb75SWang Nan 1041aca7a94dSNamhyung Kim if (offset > 0) { 1042aca7a94dSNamhyung Kim do { 1043aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 10443698dab1SNamhyung Kim if (h->unfolded) { 1045aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 1046aca7a94dSNamhyung Kim if (offset > remaining) { 1047aca7a94dSNamhyung Kim offset -= remaining; 1048aca7a94dSNamhyung Kim h->row_offset = 0; 1049aca7a94dSNamhyung Kim } else { 1050aca7a94dSNamhyung Kim h->row_offset += offset; 1051aca7a94dSNamhyung Kim offset = 0; 105205e8b080SArnaldo Carvalho de Melo browser->top = nd; 1053aca7a94dSNamhyung Kim break; 1054aca7a94dSNamhyung Kim } 1055aca7a94dSNamhyung Kim } 105614135663SNamhyung Kim nd = hists__filter_entries(rb_next(nd), hb->min_pcnt); 1057aca7a94dSNamhyung Kim if (nd == NULL) 1058aca7a94dSNamhyung Kim break; 1059aca7a94dSNamhyung Kim --offset; 106005e8b080SArnaldo Carvalho de Melo browser->top = nd; 1061aca7a94dSNamhyung Kim } while (offset != 0); 1062aca7a94dSNamhyung Kim } else if (offset < 0) { 1063aca7a94dSNamhyung Kim while (1) { 1064aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 10653698dab1SNamhyung Kim if (h->unfolded) { 1066aca7a94dSNamhyung Kim if (first) { 1067aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 1068aca7a94dSNamhyung Kim offset += h->row_offset; 1069aca7a94dSNamhyung Kim h->row_offset = 0; 1070aca7a94dSNamhyung Kim } else { 1071aca7a94dSNamhyung Kim h->row_offset += offset; 1072aca7a94dSNamhyung Kim offset = 0; 107305e8b080SArnaldo Carvalho de Melo browser->top = nd; 1074aca7a94dSNamhyung Kim break; 1075aca7a94dSNamhyung Kim } 1076aca7a94dSNamhyung Kim } else { 1077aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 1078aca7a94dSNamhyung Kim offset += h->nr_rows; 1079aca7a94dSNamhyung Kim h->row_offset = 0; 1080aca7a94dSNamhyung Kim } else { 1081aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 1082aca7a94dSNamhyung Kim offset = 0; 108305e8b080SArnaldo Carvalho de Melo browser->top = nd; 1084aca7a94dSNamhyung Kim break; 1085aca7a94dSNamhyung Kim } 1086aca7a94dSNamhyung Kim } 1087aca7a94dSNamhyung Kim } 1088aca7a94dSNamhyung Kim 108914135663SNamhyung Kim nd = hists__filter_prev_entries(rb_prev(nd), 1090064f1981SNamhyung Kim hb->min_pcnt); 1091aca7a94dSNamhyung Kim if (nd == NULL) 1092aca7a94dSNamhyung Kim break; 1093aca7a94dSNamhyung Kim ++offset; 109405e8b080SArnaldo Carvalho de Melo browser->top = nd; 1095aca7a94dSNamhyung Kim if (offset == 0) { 1096aca7a94dSNamhyung Kim /* 1097aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 1098aca7a94dSNamhyung Kim * unfolded, if it is then we should have 1099aca7a94dSNamhyung Kim * row_offset at its last entry. 1100aca7a94dSNamhyung Kim */ 1101aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 11023698dab1SNamhyung Kim if (h->unfolded) 1103aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 1104aca7a94dSNamhyung Kim break; 1105aca7a94dSNamhyung Kim } 1106aca7a94dSNamhyung Kim first = false; 1107aca7a94dSNamhyung Kim } 1108aca7a94dSNamhyung Kim } else { 110905e8b080SArnaldo Carvalho de Melo browser->top = nd; 1110aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1111aca7a94dSNamhyung Kim h->row_offset = 0; 1112aca7a94dSNamhyung Kim } 1113aca7a94dSNamhyung Kim } 1114aca7a94dSNamhyung Kim 1115aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 111639ee533fSNamhyung Kim struct hist_entry *he, FILE *fp) 1117aff3f3f6SArnaldo Carvalho de Melo { 111839ee533fSNamhyung Kim u64 total = hists__total_period(he->hists); 111939ee533fSNamhyung Kim struct callchain_print_arg arg = { 112039ee533fSNamhyung Kim .fp = fp, 112139ee533fSNamhyung Kim }; 1122aff3f3f6SArnaldo Carvalho de Melo 112339ee533fSNamhyung Kim if (symbol_conf.cumulate_callchain) 112439ee533fSNamhyung Kim total = he->stat_acc->period; 1125aff3f3f6SArnaldo Carvalho de Melo 112639ee533fSNamhyung Kim hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total, 112739ee533fSNamhyung Kim hist_browser__fprintf_callchain_entry, &arg, 112839ee533fSNamhyung Kim hist_browser__check_dump_full); 112939ee533fSNamhyung Kim return arg.printed; 1130aff3f3f6SArnaldo Carvalho de Melo } 1131aff3f3f6SArnaldo Carvalho de Melo 1132aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 1133aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 1134aff3f3f6SArnaldo Carvalho de Melo { 1135aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 1136aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1137aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 113826d8b338SNamhyung Kim struct perf_hpp hpp = { 113926d8b338SNamhyung Kim .buf = s, 114026d8b338SNamhyung Kim .size = sizeof(s), 114126d8b338SNamhyung Kim }; 114226d8b338SNamhyung Kim struct perf_hpp_fmt *fmt; 114326d8b338SNamhyung Kim bool first = true; 114426d8b338SNamhyung Kim int ret; 1145aff3f3f6SArnaldo Carvalho de Melo 1146aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1147aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 1148aff3f3f6SArnaldo Carvalho de Melo 1149aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1150aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 1151aff3f3f6SArnaldo Carvalho de Melo 115226d8b338SNamhyung Kim perf_hpp__for_each_format(fmt) { 1153e67d49a7SNamhyung Kim if (perf_hpp__should_skip(fmt)) 1154e67d49a7SNamhyung Kim continue; 1155e67d49a7SNamhyung Kim 115626d8b338SNamhyung Kim if (!first) { 115726d8b338SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 115826d8b338SNamhyung Kim advance_hpp(&hpp, ret); 115926d8b338SNamhyung Kim } else 116026d8b338SNamhyung Kim first = false; 1161aff3f3f6SArnaldo Carvalho de Melo 116226d8b338SNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 116326d8b338SNamhyung Kim advance_hpp(&hpp, ret); 116426d8b338SNamhyung Kim } 1165aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", rtrim(s)); 1166aff3f3f6SArnaldo Carvalho de Melo 1167aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 116839ee533fSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp); 1169aff3f3f6SArnaldo Carvalho de Melo 1170aff3f3f6SArnaldo Carvalho de Melo return printed; 1171aff3f3f6SArnaldo Carvalho de Melo } 1172aff3f3f6SArnaldo Carvalho de Melo 1173aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1174aff3f3f6SArnaldo Carvalho de Melo { 1175064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1176064f1981SNamhyung Kim browser->min_pcnt); 1177aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1178aff3f3f6SArnaldo Carvalho de Melo 1179aff3f3f6SArnaldo Carvalho de Melo while (nd) { 1180aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1181aff3f3f6SArnaldo Carvalho de Melo 1182aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 118314135663SNamhyung Kim nd = hists__filter_entries(rb_next(nd), browser->min_pcnt); 1184aff3f3f6SArnaldo Carvalho de Melo } 1185aff3f3f6SArnaldo Carvalho de Melo 1186aff3f3f6SArnaldo Carvalho de Melo return printed; 1187aff3f3f6SArnaldo Carvalho de Melo } 1188aff3f3f6SArnaldo Carvalho de Melo 1189aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 1190aff3f3f6SArnaldo Carvalho de Melo { 1191aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 1192aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 1193aff3f3f6SArnaldo Carvalho de Melo 1194aff3f3f6SArnaldo Carvalho de Melo while (1) { 1195aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 1196aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 1197aff3f3f6SArnaldo Carvalho de Melo break; 1198aff3f3f6SArnaldo Carvalho de Melo /* 1199aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 1200aff3f3f6SArnaldo Carvalho de Melo */ 1201aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 1202aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 1203aff3f3f6SArnaldo Carvalho de Melo return -1; 1204aff3f3f6SArnaldo Carvalho de Melo } 1205aff3f3f6SArnaldo Carvalho de Melo } 1206aff3f3f6SArnaldo Carvalho de Melo 1207aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 1208aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 1209aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 12104cc49d4dSKirill A. Shutemov const char *err = strerror_r(errno, bf, sizeof(bf)); 12114cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 1212aff3f3f6SArnaldo Carvalho de Melo return -1; 1213aff3f3f6SArnaldo Carvalho de Melo } 1214aff3f3f6SArnaldo Carvalho de Melo 1215aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 1216aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 1217aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 1218aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 1219aff3f3f6SArnaldo Carvalho de Melo 1220aff3f3f6SArnaldo Carvalho de Melo return 0; 1221aff3f3f6SArnaldo Carvalho de Melo } 1222aff3f3f6SArnaldo Carvalho de Melo 1223c2a51ab8SNamhyung Kim static struct hist_browser *hist_browser__new(struct hists *hists, 1224b1a9ceefSNamhyung Kim struct hist_browser_timer *hbt, 1225ce80d3beSKan Liang struct perf_env *env) 1226aca7a94dSNamhyung Kim { 122705e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = zalloc(sizeof(*browser)); 1228aca7a94dSNamhyung Kim 122905e8b080SArnaldo Carvalho de Melo if (browser) { 123005e8b080SArnaldo Carvalho de Melo browser->hists = hists; 123105e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 1232357cfff1SArnaldo Carvalho de Melo browser->b.refresh_dimensions = hist_browser__refresh_dimensions; 123305e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 123405e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 1235c8302367SJiri Olsa browser->show_headers = symbol_conf.show_hist_headers; 1236c2a51ab8SNamhyung Kim browser->hbt = hbt; 1237b1a9ceefSNamhyung Kim browser->env = env; 1238aca7a94dSNamhyung Kim } 1239aca7a94dSNamhyung Kim 124005e8b080SArnaldo Carvalho de Melo return browser; 1241aca7a94dSNamhyung Kim } 1242aca7a94dSNamhyung Kim 124305e8b080SArnaldo Carvalho de Melo static void hist_browser__delete(struct hist_browser *browser) 1244aca7a94dSNamhyung Kim { 124505e8b080SArnaldo Carvalho de Melo free(browser); 1246aca7a94dSNamhyung Kim } 1247aca7a94dSNamhyung Kim 124805e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 1249aca7a94dSNamhyung Kim { 125005e8b080SArnaldo Carvalho de Melo return browser->he_selection; 1251aca7a94dSNamhyung Kim } 1252aca7a94dSNamhyung Kim 125305e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 1254aca7a94dSNamhyung Kim { 125505e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 1256aca7a94dSNamhyung Kim } 1257aca7a94dSNamhyung Kim 12581e378ebdSTaeung Song /* Check whether the browser is for 'top' or 'report' */ 12591e378ebdSTaeung Song static inline bool is_report_browser(void *timer) 12601e378ebdSTaeung Song { 12611e378ebdSTaeung Song return timer == NULL; 12621e378ebdSTaeung Song } 12631e378ebdSTaeung Song 12641e378ebdSTaeung Song static int hists__browser_title(struct hists *hists, 12651e378ebdSTaeung Song struct hist_browser_timer *hbt, 12661e378ebdSTaeung Song char *bf, size_t size) 1267aca7a94dSNamhyung Kim { 1268aca7a94dSNamhyung Kim char unit; 1269aca7a94dSNamhyung Kim int printed; 127005e8b080SArnaldo Carvalho de Melo const struct dso *dso = hists->dso_filter; 127105e8b080SArnaldo Carvalho de Melo const struct thread *thread = hists->thread_filter; 127284734b06SKan Liang int socket_id = hists->socket_filter; 127305e8b080SArnaldo Carvalho de Melo unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 127405e8b080SArnaldo Carvalho de Melo u64 nr_events = hists->stats.total_period; 1275717e263fSNamhyung Kim struct perf_evsel *evsel = hists_to_evsel(hists); 1276dd00d486SJiri Olsa const char *ev_name = perf_evsel__name(evsel); 1277717e263fSNamhyung Kim char buf[512]; 1278717e263fSNamhyung Kim size_t buflen = sizeof(buf); 12799e207ddfSKan Liang char ref[30] = " show reference callgraph, "; 12809e207ddfSKan Liang bool enable_ref = false; 1281717e263fSNamhyung Kim 1282f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 1283f2148330SNamhyung Kim nr_samples = hists->stats.nr_non_filtered_samples; 1284f2148330SNamhyung Kim nr_events = hists->stats.total_non_filtered_period; 1285f2148330SNamhyung Kim } 1286f2148330SNamhyung Kim 1287759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1288717e263fSNamhyung Kim struct perf_evsel *pos; 1289717e263fSNamhyung Kim 1290717e263fSNamhyung Kim perf_evsel__group_desc(evsel, buf, buflen); 1291717e263fSNamhyung Kim ev_name = buf; 1292717e263fSNamhyung Kim 1293717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 12944ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 12954ea062edSArnaldo Carvalho de Melo 1296f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 12974ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_non_filtered_samples; 12984ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_non_filtered_period; 1299f2148330SNamhyung Kim } else { 13004ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 13014ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_period; 1302717e263fSNamhyung Kim } 1303717e263fSNamhyung Kim } 1304f2148330SNamhyung Kim } 1305aca7a94dSNamhyung Kim 13069e207ddfSKan Liang if (symbol_conf.show_ref_callgraph && 13079e207ddfSKan Liang strstr(ev_name, "call-graph=no")) 13089e207ddfSKan Liang enable_ref = true; 1309aca7a94dSNamhyung Kim nr_samples = convert_unit(nr_samples, &unit); 1310aca7a94dSNamhyung Kim printed = scnprintf(bf, size, 13119e207ddfSKan Liang "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64, 13129e207ddfSKan Liang nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events); 1313aca7a94dSNamhyung Kim 1314aca7a94dSNamhyung Kim 131505e8b080SArnaldo Carvalho de Melo if (hists->uid_filter_str) 1316aca7a94dSNamhyung Kim printed += snprintf(bf + printed, size - printed, 131705e8b080SArnaldo Carvalho de Melo ", UID: %s", hists->uid_filter_str); 1318aca7a94dSNamhyung Kim if (thread) 1319aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1320aca7a94dSNamhyung Kim ", Thread: %s(%d)", 1321b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 132238051234SAdrian Hunter thread->tid); 1323aca7a94dSNamhyung Kim if (dso) 1324aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1325aca7a94dSNamhyung Kim ", DSO: %s", dso->short_name); 132684734b06SKan Liang if (socket_id > -1) 132721394d94SKan Liang printed += scnprintf(bf + printed, size - printed, 132884734b06SKan Liang ", Processor Socket: %d", socket_id); 13291e378ebdSTaeung Song if (!is_report_browser(hbt)) { 13301e378ebdSTaeung Song struct perf_top *top = hbt->arg; 13311e378ebdSTaeung Song 13321e378ebdSTaeung Song if (top->zero) 13331e378ebdSTaeung Song printed += scnprintf(bf + printed, size - printed, " [z]"); 13341e378ebdSTaeung Song } 13351e378ebdSTaeung Song 1336aca7a94dSNamhyung Kim return printed; 1337aca7a94dSNamhyung Kim } 1338aca7a94dSNamhyung Kim 1339aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 1340aca7a94dSNamhyung Kim { 1341aca7a94dSNamhyung Kim int i; 1342aca7a94dSNamhyung Kim 134304662523SArnaldo Carvalho de Melo for (i = 0; i < n; ++i) 134404662523SArnaldo Carvalho de Melo zfree(&options[i]); 1345aca7a94dSNamhyung Kim } 1346aca7a94dSNamhyung Kim 1347341487abSFeng Tang /* 1348341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 1349341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 1350341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 1351341487abSFeng Tang */ 1352341487abSFeng Tang static bool is_input_name_malloced = false; 1353341487abSFeng Tang 1354341487abSFeng Tang static int switch_data_file(void) 1355341487abSFeng Tang { 1356341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 1357341487abSFeng Tang DIR *pwd_dir; 1358341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 1359341487abSFeng Tang struct dirent *dent; 1360341487abSFeng Tang 1361341487abSFeng Tang pwd = getenv("PWD"); 1362341487abSFeng Tang if (!pwd) 1363341487abSFeng Tang return ret; 1364341487abSFeng Tang 1365341487abSFeng Tang pwd_dir = opendir(pwd); 1366341487abSFeng Tang if (!pwd_dir) 1367341487abSFeng Tang return ret; 1368341487abSFeng Tang 1369341487abSFeng Tang memset(options, 0, sizeof(options)); 1370341487abSFeng Tang memset(options, 0, sizeof(abs_path)); 1371341487abSFeng Tang 1372341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 1373341487abSFeng Tang char path[PATH_MAX]; 1374341487abSFeng Tang u64 magic; 1375341487abSFeng Tang char *name = dent->d_name; 1376341487abSFeng Tang FILE *file; 1377341487abSFeng Tang 1378341487abSFeng Tang if (!(dent->d_type == DT_REG)) 1379341487abSFeng Tang continue; 1380341487abSFeng Tang 1381341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 1382341487abSFeng Tang 1383341487abSFeng Tang file = fopen(path, "r"); 1384341487abSFeng Tang if (!file) 1385341487abSFeng Tang continue; 1386341487abSFeng Tang 1387341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 1388341487abSFeng Tang goto close_file_and_continue; 1389341487abSFeng Tang 1390341487abSFeng Tang if (is_perf_magic(magic)) { 1391341487abSFeng Tang options[nr_options] = strdup(name); 1392341487abSFeng Tang if (!options[nr_options]) 1393341487abSFeng Tang goto close_file_and_continue; 1394341487abSFeng Tang 1395341487abSFeng Tang abs_path[nr_options] = strdup(path); 1396341487abSFeng Tang if (!abs_path[nr_options]) { 139774cf249dSArnaldo Carvalho de Melo zfree(&options[nr_options]); 1398341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 1399341487abSFeng Tang fclose(file); 1400341487abSFeng Tang break; 1401341487abSFeng Tang } 1402341487abSFeng Tang 1403341487abSFeng Tang nr_options++; 1404341487abSFeng Tang } 1405341487abSFeng Tang 1406341487abSFeng Tang close_file_and_continue: 1407341487abSFeng Tang fclose(file); 1408341487abSFeng Tang if (nr_options >= 32) { 1409341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 1410341487abSFeng Tang "Only the first 32 files will be listed.\n"); 1411341487abSFeng Tang break; 1412341487abSFeng Tang } 1413341487abSFeng Tang } 1414341487abSFeng Tang closedir(pwd_dir); 1415341487abSFeng Tang 1416341487abSFeng Tang if (nr_options) { 1417341487abSFeng Tang choice = ui__popup_menu(nr_options, options); 1418341487abSFeng Tang if (choice < nr_options && choice >= 0) { 1419341487abSFeng Tang tmp = strdup(abs_path[choice]); 1420341487abSFeng Tang if (tmp) { 1421341487abSFeng Tang if (is_input_name_malloced) 1422341487abSFeng Tang free((void *)input_name); 1423341487abSFeng Tang input_name = tmp; 1424341487abSFeng Tang is_input_name_malloced = true; 1425341487abSFeng Tang ret = 0; 1426341487abSFeng Tang } else 1427341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 1428341487abSFeng Tang } 1429341487abSFeng Tang } 1430341487abSFeng Tang 1431341487abSFeng Tang free_popup_options(options, nr_options); 1432341487abSFeng Tang free_popup_options(abs_path, nr_options); 1433341487abSFeng Tang return ret; 1434341487abSFeng Tang } 1435341487abSFeng Tang 1436ea7cd592SNamhyung Kim struct popup_action { 1437ea7cd592SNamhyung Kim struct thread *thread; 1438ea7cd592SNamhyung Kim struct map_symbol ms; 143984734b06SKan Liang int socket; 1440ea7cd592SNamhyung Kim 1441ea7cd592SNamhyung Kim int (*fn)(struct hist_browser *browser, struct popup_action *act); 1442ea7cd592SNamhyung Kim }; 1443ea7cd592SNamhyung Kim 1444bc7cad42SNamhyung Kim static int 1445ea7cd592SNamhyung Kim do_annotate(struct hist_browser *browser, struct popup_action *act) 1446bc7cad42SNamhyung Kim { 1447bc7cad42SNamhyung Kim struct perf_evsel *evsel; 1448bc7cad42SNamhyung Kim struct annotation *notes; 1449bc7cad42SNamhyung Kim struct hist_entry *he; 1450bc7cad42SNamhyung Kim int err; 1451bc7cad42SNamhyung Kim 1452eebd0bfcSArnaldo Carvalho de Melo if (!objdump_path && perf_env__lookup_objdump(browser->env)) 1453bc7cad42SNamhyung Kim return 0; 1454bc7cad42SNamhyung Kim 1455ea7cd592SNamhyung Kim notes = symbol__annotation(act->ms.sym); 1456bc7cad42SNamhyung Kim if (!notes->src) 1457bc7cad42SNamhyung Kim return 0; 1458bc7cad42SNamhyung Kim 1459bc7cad42SNamhyung Kim evsel = hists_to_evsel(browser->hists); 1460ea7cd592SNamhyung Kim err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); 1461bc7cad42SNamhyung Kim he = hist_browser__selected_entry(browser); 1462bc7cad42SNamhyung Kim /* 1463bc7cad42SNamhyung Kim * offer option to annotate the other branch source or target 1464bc7cad42SNamhyung Kim * (if they exists) when returning from annotate 1465bc7cad42SNamhyung Kim */ 1466bc7cad42SNamhyung Kim if ((err == 'q' || err == CTRL('c')) && he->branch_info) 1467bc7cad42SNamhyung Kim return 1; 1468bc7cad42SNamhyung Kim 1469bc7cad42SNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1470bc7cad42SNamhyung Kim if (err) 1471bc7cad42SNamhyung Kim ui_browser__handle_resize(&browser->b); 1472bc7cad42SNamhyung Kim return 0; 1473bc7cad42SNamhyung Kim } 1474bc7cad42SNamhyung Kim 1475bc7cad42SNamhyung Kim static int 1476ea7cd592SNamhyung Kim add_annotate_opt(struct hist_browser *browser __maybe_unused, 1477ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 1478ea7cd592SNamhyung Kim struct map *map, struct symbol *sym) 1479bc7cad42SNamhyung Kim { 1480ea7cd592SNamhyung Kim if (sym == NULL || map->dso->annotate_warned) 1481ea7cd592SNamhyung Kim return 0; 1482ea7cd592SNamhyung Kim 1483ea7cd592SNamhyung Kim if (asprintf(optstr, "Annotate %s", sym->name) < 0) 1484ea7cd592SNamhyung Kim return 0; 1485ea7cd592SNamhyung Kim 1486ea7cd592SNamhyung Kim act->ms.map = map; 1487ea7cd592SNamhyung Kim act->ms.sym = sym; 1488ea7cd592SNamhyung Kim act->fn = do_annotate; 1489ea7cd592SNamhyung Kim return 1; 1490ea7cd592SNamhyung Kim } 1491ea7cd592SNamhyung Kim 1492ea7cd592SNamhyung Kim static int 1493ea7cd592SNamhyung Kim do_zoom_thread(struct hist_browser *browser, struct popup_action *act) 1494ea7cd592SNamhyung Kim { 1495ea7cd592SNamhyung Kim struct thread *thread = act->thread; 1496ea7cd592SNamhyung Kim 1497bc7cad42SNamhyung Kim if (browser->hists->thread_filter) { 1498bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->thread_filter); 1499bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 1500bc7cad42SNamhyung Kim thread__zput(browser->hists->thread_filter); 1501bc7cad42SNamhyung Kim ui_helpline__pop(); 1502bc7cad42SNamhyung Kim } else { 15037727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 1504bc7cad42SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 1505bc7cad42SNamhyung Kim thread->tid); 1506bc7cad42SNamhyung Kim browser->hists->thread_filter = thread__get(thread); 1507bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 1508bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->thread_filter); 1509bc7cad42SNamhyung Kim } 1510bc7cad42SNamhyung Kim 1511bc7cad42SNamhyung Kim hists__filter_by_thread(browser->hists); 1512bc7cad42SNamhyung Kim hist_browser__reset(browser); 1513bc7cad42SNamhyung Kim return 0; 1514bc7cad42SNamhyung Kim } 1515bc7cad42SNamhyung Kim 1516bc7cad42SNamhyung Kim static int 1517ea7cd592SNamhyung Kim add_thread_opt(struct hist_browser *browser, struct popup_action *act, 1518ea7cd592SNamhyung Kim char **optstr, struct thread *thread) 1519bc7cad42SNamhyung Kim { 1520ea7cd592SNamhyung Kim if (thread == NULL) 1521ea7cd592SNamhyung Kim return 0; 1522ea7cd592SNamhyung Kim 1523ea7cd592SNamhyung Kim if (asprintf(optstr, "Zoom %s %s(%d) thread", 1524ea7cd592SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 1525ea7cd592SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 1526ea7cd592SNamhyung Kim thread->tid) < 0) 1527ea7cd592SNamhyung Kim return 0; 1528ea7cd592SNamhyung Kim 1529ea7cd592SNamhyung Kim act->thread = thread; 1530ea7cd592SNamhyung Kim act->fn = do_zoom_thread; 1531ea7cd592SNamhyung Kim return 1; 1532ea7cd592SNamhyung Kim } 1533ea7cd592SNamhyung Kim 1534ea7cd592SNamhyung Kim static int 1535ea7cd592SNamhyung Kim do_zoom_dso(struct hist_browser *browser, struct popup_action *act) 1536ea7cd592SNamhyung Kim { 1537045b80ddSArnaldo Carvalho de Melo struct map *map = act->ms.map; 1538ea7cd592SNamhyung Kim 1539bc7cad42SNamhyung Kim if (browser->hists->dso_filter) { 1540bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->dso_filter); 1541bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, false); 1542bc7cad42SNamhyung Kim browser->hists->dso_filter = NULL; 1543bc7cad42SNamhyung Kim ui_helpline__pop(); 1544bc7cad42SNamhyung Kim } else { 1545045b80ddSArnaldo Carvalho de Melo if (map == NULL) 1546bc7cad42SNamhyung Kim return 0; 15477727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", 1548045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); 1549045b80ddSArnaldo Carvalho de Melo browser->hists->dso_filter = map->dso; 1550bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, true); 1551bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->dso_filter); 1552bc7cad42SNamhyung Kim } 1553bc7cad42SNamhyung Kim 1554bc7cad42SNamhyung Kim hists__filter_by_dso(browser->hists); 1555bc7cad42SNamhyung Kim hist_browser__reset(browser); 1556bc7cad42SNamhyung Kim return 0; 1557bc7cad42SNamhyung Kim } 1558bc7cad42SNamhyung Kim 1559bc7cad42SNamhyung Kim static int 1560ea7cd592SNamhyung Kim add_dso_opt(struct hist_browser *browser, struct popup_action *act, 1561045b80ddSArnaldo Carvalho de Melo char **optstr, struct map *map) 1562bc7cad42SNamhyung Kim { 1563045b80ddSArnaldo Carvalho de Melo if (map == NULL) 1564ea7cd592SNamhyung Kim return 0; 1565ea7cd592SNamhyung Kim 1566ea7cd592SNamhyung Kim if (asprintf(optstr, "Zoom %s %s DSO", 1567ea7cd592SNamhyung Kim browser->hists->dso_filter ? "out of" : "into", 1568045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) 1569ea7cd592SNamhyung Kim return 0; 1570ea7cd592SNamhyung Kim 1571045b80ddSArnaldo Carvalho de Melo act->ms.map = map; 1572ea7cd592SNamhyung Kim act->fn = do_zoom_dso; 1573ea7cd592SNamhyung Kim return 1; 1574ea7cd592SNamhyung Kim } 1575ea7cd592SNamhyung Kim 1576ea7cd592SNamhyung Kim static int 1577ea7cd592SNamhyung Kim do_browse_map(struct hist_browser *browser __maybe_unused, 1578ea7cd592SNamhyung Kim struct popup_action *act) 1579ea7cd592SNamhyung Kim { 1580ea7cd592SNamhyung Kim map__browse(act->ms.map); 1581bc7cad42SNamhyung Kim return 0; 1582bc7cad42SNamhyung Kim } 1583bc7cad42SNamhyung Kim 1584bc7cad42SNamhyung Kim static int 1585ea7cd592SNamhyung Kim add_map_opt(struct hist_browser *browser __maybe_unused, 1586ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, struct map *map) 1587ea7cd592SNamhyung Kim { 1588ea7cd592SNamhyung Kim if (map == NULL) 1589ea7cd592SNamhyung Kim return 0; 1590ea7cd592SNamhyung Kim 1591ea7cd592SNamhyung Kim if (asprintf(optstr, "Browse map details") < 0) 1592ea7cd592SNamhyung Kim return 0; 1593ea7cd592SNamhyung Kim 1594ea7cd592SNamhyung Kim act->ms.map = map; 1595ea7cd592SNamhyung Kim act->fn = do_browse_map; 1596ea7cd592SNamhyung Kim return 1; 1597ea7cd592SNamhyung Kim } 1598ea7cd592SNamhyung Kim 1599ea7cd592SNamhyung Kim static int 1600bc7cad42SNamhyung Kim do_run_script(struct hist_browser *browser __maybe_unused, 1601ea7cd592SNamhyung Kim struct popup_action *act) 1602bc7cad42SNamhyung Kim { 1603bc7cad42SNamhyung Kim char script_opt[64]; 1604bc7cad42SNamhyung Kim memset(script_opt, 0, sizeof(script_opt)); 1605bc7cad42SNamhyung Kim 1606ea7cd592SNamhyung Kim if (act->thread) { 1607bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -c %s ", 1608ea7cd592SNamhyung Kim thread__comm_str(act->thread)); 1609ea7cd592SNamhyung Kim } else if (act->ms.sym) { 1610bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -S %s ", 1611ea7cd592SNamhyung Kim act->ms.sym->name); 1612bc7cad42SNamhyung Kim } 1613bc7cad42SNamhyung Kim 1614bc7cad42SNamhyung Kim script_browse(script_opt); 1615bc7cad42SNamhyung Kim return 0; 1616bc7cad42SNamhyung Kim } 1617bc7cad42SNamhyung Kim 1618bc7cad42SNamhyung Kim static int 1619ea7cd592SNamhyung Kim add_script_opt(struct hist_browser *browser __maybe_unused, 1620ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 1621ea7cd592SNamhyung Kim struct thread *thread, struct symbol *sym) 1622ea7cd592SNamhyung Kim { 1623ea7cd592SNamhyung Kim if (thread) { 1624ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of thread [%s]", 1625ea7cd592SNamhyung Kim thread__comm_str(thread)) < 0) 1626ea7cd592SNamhyung Kim return 0; 1627ea7cd592SNamhyung Kim } else if (sym) { 1628ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of symbol [%s]", 1629ea7cd592SNamhyung Kim sym->name) < 0) 1630ea7cd592SNamhyung Kim return 0; 1631ea7cd592SNamhyung Kim } else { 1632ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for all samples") < 0) 1633ea7cd592SNamhyung Kim return 0; 1634ea7cd592SNamhyung Kim } 1635ea7cd592SNamhyung Kim 1636ea7cd592SNamhyung Kim act->thread = thread; 1637ea7cd592SNamhyung Kim act->ms.sym = sym; 1638ea7cd592SNamhyung Kim act->fn = do_run_script; 1639ea7cd592SNamhyung Kim return 1; 1640ea7cd592SNamhyung Kim } 1641ea7cd592SNamhyung Kim 1642ea7cd592SNamhyung Kim static int 1643ea7cd592SNamhyung Kim do_switch_data(struct hist_browser *browser __maybe_unused, 1644ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 1645bc7cad42SNamhyung Kim { 1646bc7cad42SNamhyung Kim if (switch_data_file()) { 1647bc7cad42SNamhyung Kim ui__warning("Won't switch the data files due to\n" 1648bc7cad42SNamhyung Kim "no valid data file get selected!\n"); 1649ea7cd592SNamhyung Kim return 0; 1650bc7cad42SNamhyung Kim } 1651bc7cad42SNamhyung Kim 1652bc7cad42SNamhyung Kim return K_SWITCH_INPUT_DATA; 1653bc7cad42SNamhyung Kim } 1654bc7cad42SNamhyung Kim 1655ea7cd592SNamhyung Kim static int 1656ea7cd592SNamhyung Kim add_switch_opt(struct hist_browser *browser, 1657ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 1658ea7cd592SNamhyung Kim { 1659ea7cd592SNamhyung Kim if (!is_report_browser(browser->hbt)) 1660ea7cd592SNamhyung Kim return 0; 1661ea7cd592SNamhyung Kim 1662ea7cd592SNamhyung Kim if (asprintf(optstr, "Switch to another data file in PWD") < 0) 1663ea7cd592SNamhyung Kim return 0; 1664ea7cd592SNamhyung Kim 1665ea7cd592SNamhyung Kim act->fn = do_switch_data; 1666ea7cd592SNamhyung Kim return 1; 1667ea7cd592SNamhyung Kim } 1668ea7cd592SNamhyung Kim 1669ea7cd592SNamhyung Kim static int 1670ea7cd592SNamhyung Kim do_exit_browser(struct hist_browser *browser __maybe_unused, 1671ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 1672ea7cd592SNamhyung Kim { 1673ea7cd592SNamhyung Kim return 0; 1674ea7cd592SNamhyung Kim } 1675ea7cd592SNamhyung Kim 1676ea7cd592SNamhyung Kim static int 1677ea7cd592SNamhyung Kim add_exit_opt(struct hist_browser *browser __maybe_unused, 1678ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 1679ea7cd592SNamhyung Kim { 1680ea7cd592SNamhyung Kim if (asprintf(optstr, "Exit") < 0) 1681ea7cd592SNamhyung Kim return 0; 1682ea7cd592SNamhyung Kim 1683ea7cd592SNamhyung Kim act->fn = do_exit_browser; 1684ea7cd592SNamhyung Kim return 1; 1685ea7cd592SNamhyung Kim } 1686ea7cd592SNamhyung Kim 168784734b06SKan Liang static int 168884734b06SKan Liang do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 168984734b06SKan Liang { 169084734b06SKan Liang if (browser->hists->socket_filter > -1) { 169184734b06SKan Liang pstack__remove(browser->pstack, &browser->hists->socket_filter); 169284734b06SKan Liang browser->hists->socket_filter = -1; 169384734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, false); 169484734b06SKan Liang } else { 169584734b06SKan Liang browser->hists->socket_filter = act->socket; 169684734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, true); 169784734b06SKan Liang pstack__push(browser->pstack, &browser->hists->socket_filter); 169884734b06SKan Liang } 169984734b06SKan Liang 170084734b06SKan Liang hists__filter_by_socket(browser->hists); 170184734b06SKan Liang hist_browser__reset(browser); 170284734b06SKan Liang return 0; 170384734b06SKan Liang } 170484734b06SKan Liang 170584734b06SKan Liang static int 170684734b06SKan Liang add_socket_opt(struct hist_browser *browser, struct popup_action *act, 170784734b06SKan Liang char **optstr, int socket_id) 170884734b06SKan Liang { 170984734b06SKan Liang if (socket_id < 0) 171084734b06SKan Liang return 0; 171184734b06SKan Liang 171284734b06SKan Liang if (asprintf(optstr, "Zoom %s Processor Socket %d", 171384734b06SKan Liang (browser->hists->socket_filter > -1) ? "out of" : "into", 171484734b06SKan Liang socket_id) < 0) 171584734b06SKan Liang return 0; 171684734b06SKan Liang 171784734b06SKan Liang act->socket = socket_id; 171884734b06SKan Liang act->fn = do_zoom_socket; 171984734b06SKan Liang return 1; 172084734b06SKan Liang } 172184734b06SKan Liang 1722112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb) 1723064f1981SNamhyung Kim { 1724064f1981SNamhyung Kim u64 nr_entries = 0; 1725064f1981SNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 1726064f1981SNamhyung Kim 1727268397cbSNamhyung Kim if (hb->min_pcnt == 0) { 1728268397cbSNamhyung Kim hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 1729268397cbSNamhyung Kim return; 1730268397cbSNamhyung Kim } 1731268397cbSNamhyung Kim 173214135663SNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 1733064f1981SNamhyung Kim nr_entries++; 1734c481f930SNamhyung Kim nd = rb_next(nd); 1735064f1981SNamhyung Kim } 1736064f1981SNamhyung Kim 1737112f761fSNamhyung Kim hb->nr_non_filtered_entries = nr_entries; 1738064f1981SNamhyung Kim } 1739341487abSFeng Tang 1740aca7a94dSNamhyung Kim static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1741dd00d486SJiri Olsa const char *helpline, 1742aca7a94dSNamhyung Kim bool left_exits, 174368d80758SNamhyung Kim struct hist_browser_timer *hbt, 1744064f1981SNamhyung Kim float min_pcnt, 1745ce80d3beSKan Liang struct perf_env *env) 1746aca7a94dSNamhyung Kim { 17474ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 1748b1a9ceefSNamhyung Kim struct hist_browser *browser = hist_browser__new(hists, hbt, env); 1749aca7a94dSNamhyung Kim struct branch_info *bi; 1750f2b487dbSNamhyung Kim #define MAX_OPTIONS 16 1751f2b487dbSNamhyung Kim char *options[MAX_OPTIONS]; 1752ea7cd592SNamhyung Kim struct popup_action actions[MAX_OPTIONS]; 1753aca7a94dSNamhyung Kim int nr_options = 0; 1754aca7a94dSNamhyung Kim int key = -1; 1755aca7a94dSNamhyung Kim char buf[64]; 17569783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 175759dc9f25SNamhyung Kim struct perf_hpp_fmt *fmt; 1758aca7a94dSNamhyung Kim 1759e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 1760e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 1761e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 1762e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 1763e8e684a5SNamhyung Kim "q/ESC/CTRL+C Exit browser\n\n" \ 1764e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 1765e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 1766e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 17677727a925SArnaldo Carvalho de Melo "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \ 17687727a925SArnaldo Carvalho de Melo "ESC Zoom out\n" \ 1769e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 1770e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 1771e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 1772e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 1773105eb30fSNamhyung Kim "F Toggle percentage of filtered entries\n" \ 1774025bf7eaSArnaldo Carvalho de Melo "H Display column headers\n" \ 177531eb4360SNamhyung Kim "m Display context menu\n" \ 177684734b06SKan Liang "S Zoom into current Processor Socket\n" \ 1777e8e684a5SNamhyung Kim 1778e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 1779e8e684a5SNamhyung Kim const char report_help[] = HIST_BROWSER_HELP_COMMON 17806dd60135SNamhyung Kim "i Show header information\n" 1781e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 1782e8e684a5SNamhyung Kim "r Run available scripts\n" 1783e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 1784e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 1785e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 1786e8e684a5SNamhyung Kim "/ Filter symbol by name"; 1787e8e684a5SNamhyung Kim const char top_help[] = HIST_BROWSER_HELP_COMMON 1788e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 1789e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 1790e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 179142337a22SNamhyung Kim "z Toggle zeroing of samples\n" 1792fbb7997eSArnaldo Carvalho de Melo "f Enable/Disable events\n" 1793e8e684a5SNamhyung Kim "/ Filter symbol by name"; 1794e8e684a5SNamhyung Kim 1795aca7a94dSNamhyung Kim if (browser == NULL) 1796aca7a94dSNamhyung Kim return -1; 1797aca7a94dSNamhyung Kim 1798ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 1799ed426915SNamhyung Kim SLang_reset_tty(); 1800ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 1801ed426915SNamhyung Kim 1802064f1981SNamhyung Kim if (min_pcnt) { 1803064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 1804112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 1805064f1981SNamhyung Kim } 1806064f1981SNamhyung Kim 180784734b06SKan Liang browser->pstack = pstack__new(3); 180801f00a1cSNamhyung Kim if (browser->pstack == NULL) 1809aca7a94dSNamhyung Kim goto out; 1810aca7a94dSNamhyung Kim 1811aca7a94dSNamhyung Kim ui_helpline__push(helpline); 1812aca7a94dSNamhyung Kim 1813aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 1814ea7cd592SNamhyung Kim memset(actions, 0, sizeof(actions)); 1815aca7a94dSNamhyung Kim 1816c6c3c02dSArnaldo Carvalho de Melo perf_hpp__for_each_format(fmt) { 181759dc9f25SNamhyung Kim perf_hpp__reset_width(fmt, hists); 1818c6c3c02dSArnaldo Carvalho de Melo /* 1819c6c3c02dSArnaldo Carvalho de Melo * This is done just once, and activates the horizontal scrolling 1820c6c3c02dSArnaldo Carvalho de Melo * code in the ui_browser code, it would be better to have a the 1821c6c3c02dSArnaldo Carvalho de Melo * counter in the perf_hpp code, but I couldn't find doing it here 1822c6c3c02dSArnaldo Carvalho de Melo * works, FIXME by setting this in hist_browser__new, for now, be 1823c6c3c02dSArnaldo Carvalho de Melo * clever 8-) 1824c6c3c02dSArnaldo Carvalho de Melo */ 1825c6c3c02dSArnaldo Carvalho de Melo ++browser->b.columns; 1826c6c3c02dSArnaldo Carvalho de Melo } 182759dc9f25SNamhyung Kim 18285b591669SNamhyung Kim if (symbol_conf.col_width_list_str) 18295b591669SNamhyung Kim perf_hpp__set_user_width(symbol_conf.col_width_list_str); 18305b591669SNamhyung Kim 1831aca7a94dSNamhyung Kim while (1) { 1832f3b623b8SArnaldo Carvalho de Melo struct thread *thread = NULL; 1833045b80ddSArnaldo Carvalho de Melo struct map *map = NULL; 1834ea7cd592SNamhyung Kim int choice = 0; 183584734b06SKan Liang int socked_id = -1; 1836aca7a94dSNamhyung Kim 1837aca7a94dSNamhyung Kim nr_options = 0; 1838aca7a94dSNamhyung Kim 18395f00b0f4SArnaldo Carvalho de Melo key = hist_browser__run(browser, helpline); 1840aca7a94dSNamhyung Kim 1841aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 1842aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 1843045b80ddSArnaldo Carvalho de Melo map = browser->selection->map; 184484734b06SKan Liang socked_id = browser->he_selection->socket; 1845aca7a94dSNamhyung Kim } 1846aca7a94dSNamhyung Kim switch (key) { 1847aca7a94dSNamhyung Kim case K_TAB: 1848aca7a94dSNamhyung Kim case K_UNTAB: 1849aca7a94dSNamhyung Kim if (nr_events == 1) 1850aca7a94dSNamhyung Kim continue; 1851aca7a94dSNamhyung Kim /* 1852aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 1853aca7a94dSNamhyung Kim * go to the next or previous 1854aca7a94dSNamhyung Kim */ 1855aca7a94dSNamhyung Kim goto out_free_stack; 1856aca7a94dSNamhyung Kim case 'a': 18579c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) { 1858aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 1859aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 1860aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 1861aca7a94dSNamhyung Kim continue; 1862aca7a94dSNamhyung Kim } 1863aca7a94dSNamhyung Kim 1864aca7a94dSNamhyung Kim if (browser->selection == NULL || 1865aca7a94dSNamhyung Kim browser->selection->sym == NULL || 1866aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 1867aca7a94dSNamhyung Kim continue; 1868bc7cad42SNamhyung Kim 1869ea7cd592SNamhyung Kim actions->ms.map = browser->selection->map; 1870ea7cd592SNamhyung Kim actions->ms.sym = browser->selection->sym; 1871ea7cd592SNamhyung Kim do_annotate(browser, actions); 1872bc7cad42SNamhyung Kim continue; 1873aff3f3f6SArnaldo Carvalho de Melo case 'P': 1874aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 1875aff3f3f6SArnaldo Carvalho de Melo continue; 1876aca7a94dSNamhyung Kim case 'd': 1877fae00650SArnaldo Carvalho de Melo actions->ms.map = map; 1878ea7cd592SNamhyung Kim do_zoom_dso(browser, actions); 1879bc7cad42SNamhyung Kim continue; 1880a7cb8863SArnaldo Carvalho de Melo case 'V': 1881a7cb8863SArnaldo Carvalho de Melo browser->show_dso = !browser->show_dso; 1882a7cb8863SArnaldo Carvalho de Melo continue; 1883aca7a94dSNamhyung Kim case 't': 1884ea7cd592SNamhyung Kim actions->thread = thread; 1885ea7cd592SNamhyung Kim do_zoom_thread(browser, actions); 1886bc7cad42SNamhyung Kim continue; 188784734b06SKan Liang case 'S': 188884734b06SKan Liang actions->socket = socked_id; 188984734b06SKan Liang do_zoom_socket(browser, actions); 189084734b06SKan Liang continue; 18915a5626b1SArnaldo Carvalho de Melo case '/': 1892aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 18934aa8e454SArnaldo Carvalho de Melo "Please enter the name of symbol you want to see.\n" 18944aa8e454SArnaldo Carvalho de Melo "To remove the filter later, press / + ENTER.", 1895aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 1896aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 189705e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 189805e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 1899aca7a94dSNamhyung Kim hist_browser__reset(browser); 1900aca7a94dSNamhyung Kim } 1901aca7a94dSNamhyung Kim continue; 1902cdbab7c2SFeng Tang case 'r': 1903ea7cd592SNamhyung Kim if (is_report_browser(hbt)) { 1904ea7cd592SNamhyung Kim actions->thread = NULL; 1905ea7cd592SNamhyung Kim actions->ms.sym = NULL; 1906ea7cd592SNamhyung Kim do_run_script(browser, actions); 1907ea7cd592SNamhyung Kim } 1908c77d8d70SFeng Tang continue; 1909341487abSFeng Tang case 's': 1910bc7cad42SNamhyung Kim if (is_report_browser(hbt)) { 1911ea7cd592SNamhyung Kim key = do_switch_data(browser, actions); 1912bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 1913bc7cad42SNamhyung Kim goto out_free_stack; 1914bc7cad42SNamhyung Kim } 1915341487abSFeng Tang continue; 19166dd60135SNamhyung Kim case 'i': 19176dd60135SNamhyung Kim /* env->arch is NULL for live-mode (i.e. perf top) */ 19186dd60135SNamhyung Kim if (env->arch) 19196dd60135SNamhyung Kim tui__header_window(env); 19206dd60135SNamhyung Kim continue; 1921105eb30fSNamhyung Kim case 'F': 1922105eb30fSNamhyung Kim symbol_conf.filter_relative ^= 1; 1923105eb30fSNamhyung Kim continue; 192442337a22SNamhyung Kim case 'z': 192542337a22SNamhyung Kim if (!is_report_browser(hbt)) { 192642337a22SNamhyung Kim struct perf_top *top = hbt->arg; 192742337a22SNamhyung Kim 192842337a22SNamhyung Kim top->zero = !top->zero; 192942337a22SNamhyung Kim } 193042337a22SNamhyung Kim continue; 1931aca7a94dSNamhyung Kim case K_F1: 1932aca7a94dSNamhyung Kim case 'h': 1933aca7a94dSNamhyung Kim case '?': 1934aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 1935e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 1936aca7a94dSNamhyung Kim continue; 1937aca7a94dSNamhyung Kim case K_ENTER: 1938aca7a94dSNamhyung Kim case K_RIGHT: 193931eb4360SNamhyung Kim case 'm': 1940aca7a94dSNamhyung Kim /* menu */ 1941aca7a94dSNamhyung Kim break; 194263ab1749SArnaldo Carvalho de Melo case K_ESC: 1943aca7a94dSNamhyung Kim case K_LEFT: { 1944aca7a94dSNamhyung Kim const void *top; 1945aca7a94dSNamhyung Kim 194601f00a1cSNamhyung Kim if (pstack__empty(browser->pstack)) { 1947aca7a94dSNamhyung Kim /* 1948aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 1949aca7a94dSNamhyung Kim */ 1950aca7a94dSNamhyung Kim if (left_exits) 1951aca7a94dSNamhyung Kim goto out_free_stack; 195263ab1749SArnaldo Carvalho de Melo 195363ab1749SArnaldo Carvalho de Melo if (key == K_ESC && 195463ab1749SArnaldo Carvalho de Melo ui_browser__dialog_yesno(&browser->b, 195563ab1749SArnaldo Carvalho de Melo "Do you really want to exit?")) 195663ab1749SArnaldo Carvalho de Melo goto out_free_stack; 195763ab1749SArnaldo Carvalho de Melo 1958aca7a94dSNamhyung Kim continue; 1959aca7a94dSNamhyung Kim } 19606422184bSNamhyung Kim top = pstack__peek(browser->pstack); 1961bc7cad42SNamhyung Kim if (top == &browser->hists->dso_filter) { 19626422184bSNamhyung Kim /* 19636422184bSNamhyung Kim * No need to set actions->dso here since 19646422184bSNamhyung Kim * it's just to remove the current filter. 19656422184bSNamhyung Kim * Ditto for thread below. 19666422184bSNamhyung Kim */ 19676422184bSNamhyung Kim do_zoom_dso(browser, actions); 196884734b06SKan Liang } else if (top == &browser->hists->thread_filter) { 19696422184bSNamhyung Kim do_zoom_thread(browser, actions); 197084734b06SKan Liang } else if (top == &browser->hists->socket_filter) { 197184734b06SKan Liang do_zoom_socket(browser, actions); 197284734b06SKan Liang } 1973aca7a94dSNamhyung Kim continue; 1974aca7a94dSNamhyung Kim } 1975aca7a94dSNamhyung Kim case 'q': 1976aca7a94dSNamhyung Kim case CTRL('c'): 1977516e5368SArnaldo Carvalho de Melo goto out_free_stack; 1978fbb7997eSArnaldo Carvalho de Melo case 'f': 197913d1e536SNamhyung Kim if (!is_report_browser(hbt)) { 198013d1e536SNamhyung Kim struct perf_top *top = hbt->arg; 198113d1e536SNamhyung Kim 198213d1e536SNamhyung Kim perf_evlist__toggle_enable(top->evlist); 198313d1e536SNamhyung Kim /* 198413d1e536SNamhyung Kim * No need to refresh, resort/decay histogram 198513d1e536SNamhyung Kim * entries if we are not collecting samples: 198613d1e536SNamhyung Kim */ 198713d1e536SNamhyung Kim if (top->evlist->enabled) { 198813d1e536SNamhyung Kim helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; 198913d1e536SNamhyung Kim hbt->refresh = delay_secs; 199013d1e536SNamhyung Kim } else { 199113d1e536SNamhyung Kim helpline = "Press 'f' again to re-enable the events"; 199213d1e536SNamhyung Kim hbt->refresh = 0; 199313d1e536SNamhyung Kim } 199413d1e536SNamhyung Kim continue; 199513d1e536SNamhyung Kim } 19963e323dc0SArnaldo Carvalho de Melo /* Fall thru */ 1997aca7a94dSNamhyung Kim default: 19983e323dc0SArnaldo Carvalho de Melo helpline = "Press '?' for help on key bindings"; 1999aca7a94dSNamhyung Kim continue; 2000aca7a94dSNamhyung Kim } 2001aca7a94dSNamhyung Kim 20029c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) 2003aca7a94dSNamhyung Kim goto add_exit_option; 2004aca7a94dSNamhyung Kim 20050ba332f7SArnaldo Carvalho de Melo if (browser->selection == NULL) 20060ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 20070ba332f7SArnaldo Carvalho de Melo 200855369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 2009aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 20100ba332f7SArnaldo Carvalho de Melo 20110ba332f7SArnaldo Carvalho de Melo if (bi == NULL) 20120ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 20130ba332f7SArnaldo Carvalho de Melo 2014ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2015ea7cd592SNamhyung Kim &actions[nr_options], 2016ea7cd592SNamhyung Kim &options[nr_options], 2017ea7cd592SNamhyung Kim bi->from.map, 2018ea7cd592SNamhyung Kim bi->from.sym); 2019ea7cd592SNamhyung Kim if (bi->to.sym != bi->from.sym) 2020ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2021ea7cd592SNamhyung Kim &actions[nr_options], 2022ea7cd592SNamhyung Kim &options[nr_options], 2023ea7cd592SNamhyung Kim bi->to.map, 2024ea7cd592SNamhyung Kim bi->to.sym); 2025aca7a94dSNamhyung Kim } else { 2026ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2027ea7cd592SNamhyung Kim &actions[nr_options], 2028ea7cd592SNamhyung Kim &options[nr_options], 2029ea7cd592SNamhyung Kim browser->selection->map, 2030ea7cd592SNamhyung Kim browser->selection->sym); 2031446fb96cSArnaldo Carvalho de Melo } 20320ba332f7SArnaldo Carvalho de Melo skip_annotation: 2033ea7cd592SNamhyung Kim nr_options += add_thread_opt(browser, &actions[nr_options], 2034ea7cd592SNamhyung Kim &options[nr_options], thread); 2035ea7cd592SNamhyung Kim nr_options += add_dso_opt(browser, &actions[nr_options], 2036045b80ddSArnaldo Carvalho de Melo &options[nr_options], map); 2037ea7cd592SNamhyung Kim nr_options += add_map_opt(browser, &actions[nr_options], 2038ea7cd592SNamhyung Kim &options[nr_options], 2039bd315aabSWang Nan browser->selection ? 2040bd315aabSWang Nan browser->selection->map : NULL); 204184734b06SKan Liang nr_options += add_socket_opt(browser, &actions[nr_options], 204284734b06SKan Liang &options[nr_options], 204384734b06SKan Liang socked_id); 2044cdbab7c2SFeng Tang /* perf script support */ 2045cdbab7c2SFeng Tang if (browser->he_selection) { 2046ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 2047ea7cd592SNamhyung Kim &actions[nr_options], 2048ea7cd592SNamhyung Kim &options[nr_options], 2049ea7cd592SNamhyung Kim thread, NULL); 2050bd315aabSWang Nan /* 2051bd315aabSWang Nan * Note that browser->selection != NULL 2052bd315aabSWang Nan * when browser->he_selection is not NULL, 2053bd315aabSWang Nan * so we don't need to check browser->selection 2054bd315aabSWang Nan * before fetching browser->selection->sym like what 2055bd315aabSWang Nan * we do before fetching browser->selection->map. 2056bd315aabSWang Nan * 2057bd315aabSWang Nan * See hist_browser__show_entry. 2058bd315aabSWang Nan */ 2059ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 2060ea7cd592SNamhyung Kim &actions[nr_options], 2061ea7cd592SNamhyung Kim &options[nr_options], 2062ea7cd592SNamhyung Kim NULL, browser->selection->sym); 2063cdbab7c2SFeng Tang } 2064ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, &actions[nr_options], 2065ea7cd592SNamhyung Kim &options[nr_options], NULL, NULL); 2066ea7cd592SNamhyung Kim nr_options += add_switch_opt(browser, &actions[nr_options], 2067ea7cd592SNamhyung Kim &options[nr_options]); 2068aca7a94dSNamhyung Kim add_exit_option: 2069ea7cd592SNamhyung Kim nr_options += add_exit_opt(browser, &actions[nr_options], 2070ea7cd592SNamhyung Kim &options[nr_options]); 2071aca7a94dSNamhyung Kim 2072ea7cd592SNamhyung Kim do { 2073ea7cd592SNamhyung Kim struct popup_action *act; 2074ea7cd592SNamhyung Kim 2075ea7cd592SNamhyung Kim choice = ui__popup_menu(nr_options, options); 2076ea7cd592SNamhyung Kim if (choice == -1 || choice >= nr_options) 2077aca7a94dSNamhyung Kim break; 2078aca7a94dSNamhyung Kim 2079ea7cd592SNamhyung Kim act = &actions[choice]; 2080ea7cd592SNamhyung Kim key = act->fn(browser, act); 2081ea7cd592SNamhyung Kim } while (key == 1); 2082aca7a94dSNamhyung Kim 2083bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 2084341487abSFeng Tang break; 2085341487abSFeng Tang } 2086aca7a94dSNamhyung Kim out_free_stack: 208701f00a1cSNamhyung Kim pstack__delete(browser->pstack); 2088aca7a94dSNamhyung Kim out: 2089aca7a94dSNamhyung Kim hist_browser__delete(browser); 2090f2b487dbSNamhyung Kim free_popup_options(options, MAX_OPTIONS); 2091aca7a94dSNamhyung Kim return key; 2092aca7a94dSNamhyung Kim } 2093aca7a94dSNamhyung Kim 2094aca7a94dSNamhyung Kim struct perf_evsel_menu { 2095aca7a94dSNamhyung Kim struct ui_browser b; 2096aca7a94dSNamhyung Kim struct perf_evsel *selection; 2097aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 2098064f1981SNamhyung Kim float min_pcnt; 2099ce80d3beSKan Liang struct perf_env *env; 2100aca7a94dSNamhyung Kim }; 2101aca7a94dSNamhyung Kim 2102aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 2103aca7a94dSNamhyung Kim void *entry, int row) 2104aca7a94dSNamhyung Kim { 2105aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 2106aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 2107aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 21084ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 2109aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 21104ea062edSArnaldo Carvalho de Melo unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 21117289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 2112aca7a94dSNamhyung Kim char bf[256], unit; 2113aca7a94dSNamhyung Kim const char *warn = " "; 2114aca7a94dSNamhyung Kim size_t printed; 2115aca7a94dSNamhyung Kim 2116aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 2117aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 2118aca7a94dSNamhyung Kim 2119759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 2120717e263fSNamhyung Kim struct perf_evsel *pos; 2121717e263fSNamhyung Kim 2122717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 2123717e263fSNamhyung Kim 2124717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 21254ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 21264ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 2127717e263fSNamhyung Kim } 2128717e263fSNamhyung Kim } 2129717e263fSNamhyung Kim 2130aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 2131aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 2132aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 2133517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%s", bf); 2134aca7a94dSNamhyung Kim 21354ea062edSArnaldo Carvalho de Melo nr_events = hists->stats.nr_events[PERF_RECORD_LOST]; 2136aca7a94dSNamhyung Kim if (nr_events != 0) { 2137aca7a94dSNamhyung Kim menu->lost_events = true; 2138aca7a94dSNamhyung Kim if (!current_entry) 2139aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 2140aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 2141aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 2142aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 2143aca7a94dSNamhyung Kim warn = bf; 2144aca7a94dSNamhyung Kim } 2145aca7a94dSNamhyung Kim 214626270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, warn, browser->width - printed); 2147aca7a94dSNamhyung Kim 2148aca7a94dSNamhyung Kim if (current_entry) 2149aca7a94dSNamhyung Kim menu->selection = evsel; 2150aca7a94dSNamhyung Kim } 2151aca7a94dSNamhyung Kim 2152aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 2153aca7a94dSNamhyung Kim int nr_events, const char *help, 21549783adf7SNamhyung Kim struct hist_browser_timer *hbt) 2155aca7a94dSNamhyung Kim { 2156aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 2157aca7a94dSNamhyung Kim struct perf_evsel *pos; 2158dd00d486SJiri Olsa const char *title = "Available samples"; 21599783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 2160aca7a94dSNamhyung Kim int key; 2161aca7a94dSNamhyung Kim 2162aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 2163aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 2164aca7a94dSNamhyung Kim return -1; 2165aca7a94dSNamhyung Kim 2166aca7a94dSNamhyung Kim while (1) { 2167aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 2168aca7a94dSNamhyung Kim 2169aca7a94dSNamhyung Kim switch (key) { 2170aca7a94dSNamhyung Kim case K_TIMER: 21719783adf7SNamhyung Kim hbt->timer(hbt->arg); 2172aca7a94dSNamhyung Kim 2173aca7a94dSNamhyung Kim if (!menu->lost_events_warned && menu->lost_events) { 2174aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 2175aca7a94dSNamhyung Kim menu->lost_events_warned = true; 2176aca7a94dSNamhyung Kim } 2177aca7a94dSNamhyung Kim continue; 2178aca7a94dSNamhyung Kim case K_RIGHT: 2179aca7a94dSNamhyung Kim case K_ENTER: 2180aca7a94dSNamhyung Kim if (!menu->selection) 2181aca7a94dSNamhyung Kim continue; 2182aca7a94dSNamhyung Kim pos = menu->selection; 2183aca7a94dSNamhyung Kim browse_hists: 2184aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 2185aca7a94dSNamhyung Kim /* 2186aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 2187aca7a94dSNamhyung Kim * default evsel resorted hists tree. 2188aca7a94dSNamhyung Kim */ 21899783adf7SNamhyung Kim if (hbt) 21909783adf7SNamhyung Kim hbt->timer(hbt->arg); 2191aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 2192dd00d486SJiri Olsa true, hbt, 2193064f1981SNamhyung Kim menu->min_pcnt, 219468d80758SNamhyung Kim menu->env); 2195aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 2196aca7a94dSNamhyung Kim switch (key) { 2197aca7a94dSNamhyung Kim case K_TAB: 2198aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 21999a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__first(evlist); 2200aca7a94dSNamhyung Kim else 22019a354cdcSArnaldo Carvalho de Melo pos = perf_evsel__next(pos); 2202aca7a94dSNamhyung Kim goto browse_hists; 2203aca7a94dSNamhyung Kim case K_UNTAB: 2204aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 22059a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__last(evlist); 2206aca7a94dSNamhyung Kim else 2207d87fcb4aSArnaldo Carvalho de Melo pos = perf_evsel__prev(pos); 2208aca7a94dSNamhyung Kim goto browse_hists; 2209341487abSFeng Tang case K_SWITCH_INPUT_DATA: 2210aca7a94dSNamhyung Kim case 'q': 2211aca7a94dSNamhyung Kim case CTRL('c'): 2212aca7a94dSNamhyung Kim goto out; 221363ab1749SArnaldo Carvalho de Melo case K_ESC: 2214aca7a94dSNamhyung Kim default: 2215aca7a94dSNamhyung Kim continue; 2216aca7a94dSNamhyung Kim } 2217aca7a94dSNamhyung Kim case K_LEFT: 2218aca7a94dSNamhyung Kim continue; 2219aca7a94dSNamhyung Kim case K_ESC: 2220aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 2221aca7a94dSNamhyung Kim "Do you really want to exit?")) 2222aca7a94dSNamhyung Kim continue; 2223aca7a94dSNamhyung Kim /* Fall thru */ 2224aca7a94dSNamhyung Kim case 'q': 2225aca7a94dSNamhyung Kim case CTRL('c'): 2226aca7a94dSNamhyung Kim goto out; 2227aca7a94dSNamhyung Kim default: 2228aca7a94dSNamhyung Kim continue; 2229aca7a94dSNamhyung Kim } 2230aca7a94dSNamhyung Kim } 2231aca7a94dSNamhyung Kim 2232aca7a94dSNamhyung Kim out: 2233aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 2234aca7a94dSNamhyung Kim return key; 2235aca7a94dSNamhyung Kim } 2236aca7a94dSNamhyung Kim 2237316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 2238fc24d7c2SNamhyung Kim void *entry) 2239fc24d7c2SNamhyung Kim { 2240fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 2241fc24d7c2SNamhyung Kim 2242fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 2243fc24d7c2SNamhyung Kim return true; 2244fc24d7c2SNamhyung Kim 2245fc24d7c2SNamhyung Kim return false; 2246fc24d7c2SNamhyung Kim } 2247fc24d7c2SNamhyung Kim 2248aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 2249fc24d7c2SNamhyung Kim int nr_entries, const char *help, 225068d80758SNamhyung Kim struct hist_browser_timer *hbt, 2251064f1981SNamhyung Kim float min_pcnt, 2252ce80d3beSKan Liang struct perf_env *env) 2253aca7a94dSNamhyung Kim { 2254aca7a94dSNamhyung Kim struct perf_evsel *pos; 2255aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 2256aca7a94dSNamhyung Kim .b = { 2257aca7a94dSNamhyung Kim .entries = &evlist->entries, 2258aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 2259aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 2260aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 2261fc24d7c2SNamhyung Kim .filter = filter_group_entries, 2262fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 2263aca7a94dSNamhyung Kim .priv = evlist, 2264aca7a94dSNamhyung Kim }, 2265064f1981SNamhyung Kim .min_pcnt = min_pcnt, 226668d80758SNamhyung Kim .env = env, 2267aca7a94dSNamhyung Kim }; 2268aca7a94dSNamhyung Kim 2269aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 2270aca7a94dSNamhyung Kim 22710050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 22727289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 2273aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 2274aca7a94dSNamhyung Kim 2275aca7a94dSNamhyung Kim if (menu.b.width < line_len) 2276aca7a94dSNamhyung Kim menu.b.width = line_len; 2277aca7a94dSNamhyung Kim } 2278aca7a94dSNamhyung Kim 2279fc24d7c2SNamhyung Kim return perf_evsel_menu__run(&menu, nr_entries, help, hbt); 2280aca7a94dSNamhyung Kim } 2281aca7a94dSNamhyung Kim 2282aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 228368d80758SNamhyung Kim struct hist_browser_timer *hbt, 2284064f1981SNamhyung Kim float min_pcnt, 2285ce80d3beSKan Liang struct perf_env *env) 2286aca7a94dSNamhyung Kim { 2287fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 2288fc24d7c2SNamhyung Kim 2289fc24d7c2SNamhyung Kim single_entry: 2290fc24d7c2SNamhyung Kim if (nr_entries == 1) { 22919a354cdcSArnaldo Carvalho de Melo struct perf_evsel *first = perf_evlist__first(evlist); 2292fc24d7c2SNamhyung Kim 2293fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 2294dd00d486SJiri Olsa false, hbt, min_pcnt, 2295064f1981SNamhyung Kim env); 2296aca7a94dSNamhyung Kim } 2297aca7a94dSNamhyung Kim 2298fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 2299fc24d7c2SNamhyung Kim struct perf_evsel *pos; 2300fc24d7c2SNamhyung Kim 2301fc24d7c2SNamhyung Kim nr_entries = 0; 23020050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 2303fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 2304fc24d7c2SNamhyung Kim nr_entries++; 23050050f7aaSArnaldo Carvalho de Melo } 2306fc24d7c2SNamhyung Kim 2307fc24d7c2SNamhyung Kim if (nr_entries == 1) 2308fc24d7c2SNamhyung Kim goto single_entry; 2309fc24d7c2SNamhyung Kim } 2310fc24d7c2SNamhyung Kim 2311fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 2312064f1981SNamhyung Kim hbt, min_pcnt, env); 2313aca7a94dSNamhyung Kim } 2314