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 1814b3a3212SNamhyung Kim static int callchain_node__count_flat_rows(struct callchain_node *node) 1824b3a3212SNamhyung Kim { 1834b3a3212SNamhyung Kim struct callchain_list *chain; 1844b3a3212SNamhyung Kim char folded_sign = 0; 1854b3a3212SNamhyung Kim int n = 0; 1864b3a3212SNamhyung Kim 1874b3a3212SNamhyung Kim list_for_each_entry(chain, &node->parent_val, list) { 1884b3a3212SNamhyung Kim if (!folded_sign) { 1894b3a3212SNamhyung Kim /* only check first chain list entry */ 1904b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 1914b3a3212SNamhyung Kim if (folded_sign == '+') 1924b3a3212SNamhyung Kim return 1; 1934b3a3212SNamhyung Kim } 1944b3a3212SNamhyung Kim n++; 1954b3a3212SNamhyung Kim } 1964b3a3212SNamhyung Kim 1974b3a3212SNamhyung Kim list_for_each_entry(chain, &node->val, list) { 1984b3a3212SNamhyung Kim if (!folded_sign) { 1994b3a3212SNamhyung Kim /* node->parent_val list might be empty */ 2004b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 2014b3a3212SNamhyung Kim if (folded_sign == '+') 2024b3a3212SNamhyung Kim return 1; 2034b3a3212SNamhyung Kim } 2044b3a3212SNamhyung Kim n++; 2054b3a3212SNamhyung Kim } 2064b3a3212SNamhyung Kim 2074b3a3212SNamhyung Kim return n; 2084b3a3212SNamhyung Kim } 2094b3a3212SNamhyung Kim 2108c430a34SNamhyung Kim static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused) 2118c430a34SNamhyung Kim { 2128c430a34SNamhyung Kim return 1; 2138c430a34SNamhyung Kim } 2148c430a34SNamhyung Kim 215aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 216aca7a94dSNamhyung Kim { 217aca7a94dSNamhyung Kim struct callchain_list *chain; 218aca7a94dSNamhyung Kim bool unfolded = false; 219aca7a94dSNamhyung Kim int n = 0; 220aca7a94dSNamhyung Kim 2214b3a3212SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) 2224b3a3212SNamhyung Kim return callchain_node__count_flat_rows(node); 2238c430a34SNamhyung Kim else if (callchain_param.mode == CHAIN_FOLDED) 2248c430a34SNamhyung Kim return callchain_node__count_folded_rows(node); 2254b3a3212SNamhyung Kim 226aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 227aca7a94dSNamhyung Kim ++n; 2283698dab1SNamhyung Kim unfolded = chain->unfolded; 229aca7a94dSNamhyung Kim } 230aca7a94dSNamhyung Kim 231aca7a94dSNamhyung Kim if (unfolded) 232aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 233aca7a94dSNamhyung Kim 234aca7a94dSNamhyung Kim return n; 235aca7a94dSNamhyung Kim } 236aca7a94dSNamhyung Kim 237aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 238aca7a94dSNamhyung Kim { 239aca7a94dSNamhyung Kim struct rb_node *nd; 240aca7a94dSNamhyung Kim int n = 0; 241aca7a94dSNamhyung Kim 242aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 243aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 244aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 245aca7a94dSNamhyung Kim } 246aca7a94dSNamhyung Kim 247aca7a94dSNamhyung Kim return n; 248aca7a94dSNamhyung Kim } 249aca7a94dSNamhyung Kim 2503698dab1SNamhyung Kim static bool hist_entry__toggle_fold(struct hist_entry *he) 251aca7a94dSNamhyung Kim { 2523698dab1SNamhyung Kim if (!he) 253aca7a94dSNamhyung Kim return false; 254aca7a94dSNamhyung Kim 2553698dab1SNamhyung Kim if (!he->has_children) 256aca7a94dSNamhyung Kim return false; 257aca7a94dSNamhyung Kim 2583698dab1SNamhyung Kim he->unfolded = !he->unfolded; 2593698dab1SNamhyung Kim return true; 2603698dab1SNamhyung Kim } 2613698dab1SNamhyung Kim 2623698dab1SNamhyung Kim static bool callchain_list__toggle_fold(struct callchain_list *cl) 2633698dab1SNamhyung Kim { 2643698dab1SNamhyung Kim if (!cl) 2653698dab1SNamhyung Kim return false; 2663698dab1SNamhyung Kim 2673698dab1SNamhyung Kim if (!cl->has_children) 2683698dab1SNamhyung Kim return false; 2693698dab1SNamhyung Kim 2703698dab1SNamhyung Kim cl->unfolded = !cl->unfolded; 271aca7a94dSNamhyung Kim return true; 272aca7a94dSNamhyung Kim } 273aca7a94dSNamhyung Kim 27405e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 275aca7a94dSNamhyung Kim { 27605e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 277aca7a94dSNamhyung Kim 27805e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 279aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 280aca7a94dSNamhyung Kim struct callchain_list *chain; 281aca7a94dSNamhyung Kim bool first = true; 282aca7a94dSNamhyung Kim 283aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 284aca7a94dSNamhyung Kim if (first) { 285aca7a94dSNamhyung Kim first = false; 2863698dab1SNamhyung Kim chain->has_children = chain->list.next != &child->val || 287aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 288aca7a94dSNamhyung Kim } else 2893698dab1SNamhyung Kim chain->has_children = chain->list.next == &child->val && 290aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 291aca7a94dSNamhyung Kim } 292aca7a94dSNamhyung Kim 293aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 294aca7a94dSNamhyung Kim } 295aca7a94dSNamhyung Kim } 296aca7a94dSNamhyung Kim 297a7444af6SNamhyung Kim static void callchain_node__init_have_children(struct callchain_node *node, 298a7444af6SNamhyung Kim bool has_sibling) 299aca7a94dSNamhyung Kim { 300aca7a94dSNamhyung Kim struct callchain_list *chain; 301aca7a94dSNamhyung Kim 302a7444af6SNamhyung Kim chain = list_entry(node->val.next, struct callchain_list, list); 3033698dab1SNamhyung Kim chain->has_children = has_sibling; 304a7444af6SNamhyung Kim 3054b3a3212SNamhyung Kim if (node->val.next != node->val.prev) { 30682162b5aSNamhyung Kim chain = list_entry(node->val.prev, struct callchain_list, list); 3073698dab1SNamhyung Kim chain->has_children = !RB_EMPTY_ROOT(&node->rb_root); 30882162b5aSNamhyung Kim } 309aca7a94dSNamhyung Kim 31005e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 311aca7a94dSNamhyung Kim } 312aca7a94dSNamhyung Kim 31305e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 314aca7a94dSNamhyung Kim { 315a7444af6SNamhyung Kim struct rb_node *nd = rb_first(root); 316a7444af6SNamhyung Kim bool has_sibling = nd && rb_next(nd); 317aca7a94dSNamhyung Kim 31805e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 319aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 320a7444af6SNamhyung Kim callchain_node__init_have_children(node, has_sibling); 3218c430a34SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT || 3228c430a34SNamhyung Kim callchain_param.mode == CHAIN_FOLDED) 3234b3a3212SNamhyung Kim callchain_node__make_parent_list(node); 324aca7a94dSNamhyung Kim } 325aca7a94dSNamhyung Kim } 326aca7a94dSNamhyung Kim 32705e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 328aca7a94dSNamhyung Kim { 32905e8b080SArnaldo Carvalho de Melo if (!he->init_have_children) { 3303698dab1SNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 33105e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 33205e8b080SArnaldo Carvalho de Melo he->init_have_children = true; 333aca7a94dSNamhyung Kim } 334aca7a94dSNamhyung Kim } 335aca7a94dSNamhyung Kim 33605e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 337aca7a94dSNamhyung Kim { 33805e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 3393698dab1SNamhyung Kim struct map_symbol *ms = browser->selection; 3403698dab1SNamhyung Kim struct callchain_list *cl = container_of(ms, struct callchain_list, ms); 3413698dab1SNamhyung Kim bool has_children; 342aca7a94dSNamhyung Kim 3434938cf0cSWang Nan if (!he || !ms) 3444938cf0cSWang Nan return false; 3454938cf0cSWang Nan 3463698dab1SNamhyung Kim if (ms == &he->ms) 3473698dab1SNamhyung Kim has_children = hist_entry__toggle_fold(he); 3483698dab1SNamhyung Kim else 3493698dab1SNamhyung Kim has_children = callchain_list__toggle_fold(cl); 3503698dab1SNamhyung Kim 3513698dab1SNamhyung Kim if (has_children) { 352aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 353c3b78952SNamhyung Kim browser->b.nr_entries -= he->nr_rows; 354c3b78952SNamhyung Kim browser->nr_callchain_rows -= he->nr_rows; 355aca7a94dSNamhyung Kim 3563698dab1SNamhyung Kim if (he->unfolded) 357aca7a94dSNamhyung Kim he->nr_rows = callchain__count_rows(&he->sorted_chain); 358aca7a94dSNamhyung Kim else 359aca7a94dSNamhyung Kim he->nr_rows = 0; 360c3b78952SNamhyung Kim 361c3b78952SNamhyung Kim browser->b.nr_entries += he->nr_rows; 362c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 363aca7a94dSNamhyung Kim 364aca7a94dSNamhyung Kim return true; 365aca7a94dSNamhyung Kim } 366aca7a94dSNamhyung Kim 367aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 368aca7a94dSNamhyung Kim return false; 369aca7a94dSNamhyung Kim } 370aca7a94dSNamhyung Kim 37105e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 372aca7a94dSNamhyung Kim { 373aca7a94dSNamhyung Kim int n = 0; 374aca7a94dSNamhyung Kim struct rb_node *nd; 375aca7a94dSNamhyung Kim 37605e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 377aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 378aca7a94dSNamhyung Kim struct callchain_list *chain; 379aca7a94dSNamhyung Kim bool has_children = false; 380aca7a94dSNamhyung Kim 381aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 382aca7a94dSNamhyung Kim ++n; 3833698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 3843698dab1SNamhyung Kim has_children = chain->has_children; 385aca7a94dSNamhyung Kim } 386aca7a94dSNamhyung Kim 387aca7a94dSNamhyung Kim if (has_children) 388aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 389aca7a94dSNamhyung Kim } 390aca7a94dSNamhyung Kim 391aca7a94dSNamhyung Kim return n; 392aca7a94dSNamhyung Kim } 393aca7a94dSNamhyung Kim 394aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 395aca7a94dSNamhyung Kim { 396aca7a94dSNamhyung Kim struct callchain_list *chain; 397aca7a94dSNamhyung Kim bool has_children = false; 398aca7a94dSNamhyung Kim int n = 0; 399aca7a94dSNamhyung Kim 400aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 401aca7a94dSNamhyung Kim ++n; 4023698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 4033698dab1SNamhyung Kim has_children = chain->has_children; 404aca7a94dSNamhyung Kim } 405aca7a94dSNamhyung Kim 406aca7a94dSNamhyung Kim if (has_children) 407aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 408aca7a94dSNamhyung Kim 409aca7a94dSNamhyung Kim return n; 410aca7a94dSNamhyung Kim } 411aca7a94dSNamhyung Kim 412aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 413aca7a94dSNamhyung Kim { 414aca7a94dSNamhyung Kim struct rb_node *nd; 415aca7a94dSNamhyung Kim int n = 0; 416aca7a94dSNamhyung Kim 417aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 418aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 419aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 420aca7a94dSNamhyung Kim } 421aca7a94dSNamhyung Kim 422aca7a94dSNamhyung Kim return n; 423aca7a94dSNamhyung Kim } 424aca7a94dSNamhyung Kim 42505e8b080SArnaldo Carvalho de Melo static void hist_entry__set_folding(struct hist_entry *he, bool unfold) 426aca7a94dSNamhyung Kim { 42705e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 4283698dab1SNamhyung Kim he->unfolded = unfold ? he->has_children : false; 429aca7a94dSNamhyung Kim 4303698dab1SNamhyung Kim if (he->has_children) { 43105e8b080SArnaldo Carvalho de Melo int n = callchain__set_folding(&he->sorted_chain, unfold); 43205e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 433aca7a94dSNamhyung Kim } else 43405e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 435aca7a94dSNamhyung Kim } 436aca7a94dSNamhyung Kim 437c3b78952SNamhyung Kim static void 438c3b78952SNamhyung Kim __hist_browser__set_folding(struct hist_browser *browser, bool unfold) 439aca7a94dSNamhyung Kim { 440aca7a94dSNamhyung Kim struct rb_node *nd; 441c3b78952SNamhyung Kim struct hists *hists = browser->hists; 442aca7a94dSNamhyung Kim 443c3b78952SNamhyung Kim for (nd = rb_first(&hists->entries); 44414135663SNamhyung Kim (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 445c3b78952SNamhyung Kim nd = rb_next(nd)) { 446aca7a94dSNamhyung Kim struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 447aca7a94dSNamhyung Kim hist_entry__set_folding(he, unfold); 448c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 449aca7a94dSNamhyung Kim } 450aca7a94dSNamhyung Kim } 451aca7a94dSNamhyung Kim 45205e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 453aca7a94dSNamhyung Kim { 454c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 455c3b78952SNamhyung Kim __hist_browser__set_folding(browser, unfold); 456c3b78952SNamhyung Kim 457c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 458aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 45905e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 460aca7a94dSNamhyung Kim } 461aca7a94dSNamhyung Kim 462aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 463aca7a94dSNamhyung Kim { 464aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 465aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 466aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 467aca7a94dSNamhyung Kim " perf top -r 80\n\n" 468aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 469aca7a94dSNamhyung Kim } 470aca7a94dSNamhyung Kim 4715f00b0f4SArnaldo Carvalho de Melo static int hist_browser__run(struct hist_browser *browser, const char *help) 472aca7a94dSNamhyung Kim { 473aca7a94dSNamhyung Kim int key; 474aca7a94dSNamhyung Kim char title[160]; 475c2a51ab8SNamhyung Kim struct hist_browser_timer *hbt = browser->hbt; 4769783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 477aca7a94dSNamhyung Kim 47805e8b080SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 479c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 480aca7a94dSNamhyung Kim 4811e378ebdSTaeung Song hists__browser_title(browser->hists, hbt, title, sizeof(title)); 482aca7a94dSNamhyung Kim 4835f00b0f4SArnaldo Carvalho de Melo if (ui_browser__show(&browser->b, title, help) < 0) 484aca7a94dSNamhyung Kim return -1; 485aca7a94dSNamhyung Kim 486aca7a94dSNamhyung Kim while (1) { 48705e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 488aca7a94dSNamhyung Kim 489aca7a94dSNamhyung Kim switch (key) { 490fa5df943SNamhyung Kim case K_TIMER: { 491fa5df943SNamhyung Kim u64 nr_entries; 4929783adf7SNamhyung Kim hbt->timer(hbt->arg); 493fa5df943SNamhyung Kim 494c3b78952SNamhyung Kim if (hist_browser__has_filter(browser)) 495112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 496fa5df943SNamhyung Kim 497c3b78952SNamhyung Kim nr_entries = hist_browser__nr_entries(browser); 498fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 499aca7a94dSNamhyung Kim 50005e8b080SArnaldo Carvalho de Melo if (browser->hists->stats.nr_lost_warned != 50105e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]) { 50205e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 50305e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 50405e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 505aca7a94dSNamhyung Kim } 506aca7a94dSNamhyung Kim 5071e378ebdSTaeung Song hists__browser_title(browser->hists, 5081e378ebdSTaeung Song hbt, title, sizeof(title)); 50905e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 510aca7a94dSNamhyung Kim continue; 511fa5df943SNamhyung Kim } 512aca7a94dSNamhyung Kim case 'D': { /* Debug */ 513aca7a94dSNamhyung Kim static int seq; 51405e8b080SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, 515aca7a94dSNamhyung Kim struct hist_entry, rb_node); 516aca7a94dSNamhyung Kim ui_helpline__pop(); 51762c95ae3SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 51805e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 51905e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries, 52062c95ae3SArnaldo Carvalho de Melo browser->b.rows, 52105e8b080SArnaldo Carvalho de Melo browser->b.index, 52205e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 523aca7a94dSNamhyung Kim h->row_offset, h->nr_rows); 524aca7a94dSNamhyung Kim } 525aca7a94dSNamhyung Kim break; 526aca7a94dSNamhyung Kim case 'C': 527aca7a94dSNamhyung Kim /* Collapse the whole world. */ 52805e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 529aca7a94dSNamhyung Kim break; 530aca7a94dSNamhyung Kim case 'E': 531aca7a94dSNamhyung Kim /* Expand the whole world. */ 53205e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 533aca7a94dSNamhyung Kim break; 534025bf7eaSArnaldo Carvalho de Melo case 'H': 535025bf7eaSArnaldo Carvalho de Melo browser->show_headers = !browser->show_headers; 536025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(browser); 537025bf7eaSArnaldo Carvalho de Melo break; 538aca7a94dSNamhyung Kim case K_ENTER: 53905e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 540aca7a94dSNamhyung Kim break; 541aca7a94dSNamhyung Kim /* fall thru */ 542aca7a94dSNamhyung Kim default: 543aca7a94dSNamhyung Kim goto out; 544aca7a94dSNamhyung Kim } 545aca7a94dSNamhyung Kim } 546aca7a94dSNamhyung Kim out: 54705e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 548aca7a94dSNamhyung Kim return key; 549aca7a94dSNamhyung Kim } 550aca7a94dSNamhyung Kim 55139ee533fSNamhyung Kim struct callchain_print_arg { 55239ee533fSNamhyung Kim /* for hists browser */ 55339ee533fSNamhyung Kim off_t row_offset; 55439ee533fSNamhyung Kim bool is_current_entry; 55539ee533fSNamhyung Kim 55639ee533fSNamhyung Kim /* for file dump */ 55739ee533fSNamhyung Kim FILE *fp; 55839ee533fSNamhyung Kim int printed; 55939ee533fSNamhyung Kim }; 56039ee533fSNamhyung Kim 56139ee533fSNamhyung Kim typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, 56239ee533fSNamhyung Kim struct callchain_list *chain, 56339ee533fSNamhyung Kim const char *str, int offset, 56439ee533fSNamhyung Kim unsigned short row, 56539ee533fSNamhyung Kim struct callchain_print_arg *arg); 56639ee533fSNamhyung Kim 567f4536dddSNamhyung Kim static void hist_browser__show_callchain_entry(struct hist_browser *browser, 568f4536dddSNamhyung Kim struct callchain_list *chain, 56939ee533fSNamhyung Kim const char *str, int offset, 57039ee533fSNamhyung Kim unsigned short row, 57139ee533fSNamhyung Kim struct callchain_print_arg *arg) 572f4536dddSNamhyung Kim { 573f4536dddSNamhyung Kim int color, width; 57439ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 57570e97278SArnaldo Carvalho de Melo bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src; 576f4536dddSNamhyung Kim 577f4536dddSNamhyung Kim color = HE_COLORSET_NORMAL; 578f4536dddSNamhyung Kim width = browser->b.width - (offset + 2); 579f4536dddSNamhyung Kim if (ui_browser__is_current_entry(&browser->b, row)) { 580f4536dddSNamhyung Kim browser->selection = &chain->ms; 581f4536dddSNamhyung Kim color = HE_COLORSET_SELECTED; 58239ee533fSNamhyung Kim arg->is_current_entry = true; 583f4536dddSNamhyung Kim } 584f4536dddSNamhyung Kim 585f4536dddSNamhyung Kim ui_browser__set_color(&browser->b, color); 586f4536dddSNamhyung Kim hist_browser__gotorc(browser, row, 0); 58726270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, " ", offset); 588517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c", folded_sign); 58970e97278SArnaldo Carvalho de Melo ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); 59026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, str, width); 591f4536dddSNamhyung Kim } 592f4536dddSNamhyung Kim 59339ee533fSNamhyung Kim static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, 59439ee533fSNamhyung Kim struct callchain_list *chain, 59539ee533fSNamhyung Kim const char *str, int offset, 59639ee533fSNamhyung Kim unsigned short row __maybe_unused, 59739ee533fSNamhyung Kim struct callchain_print_arg *arg) 59839ee533fSNamhyung Kim { 59939ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 60039ee533fSNamhyung Kim 60139ee533fSNamhyung Kim arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", 60239ee533fSNamhyung Kim folded_sign, str); 60339ee533fSNamhyung Kim } 60439ee533fSNamhyung Kim 60539ee533fSNamhyung Kim typedef bool (*check_output_full_fn)(struct hist_browser *browser, 60639ee533fSNamhyung Kim unsigned short row); 60739ee533fSNamhyung Kim 60839ee533fSNamhyung Kim static bool hist_browser__check_output_full(struct hist_browser *browser, 60939ee533fSNamhyung Kim unsigned short row) 61039ee533fSNamhyung Kim { 61139ee533fSNamhyung Kim return browser->b.rows == row; 61239ee533fSNamhyung Kim } 61339ee533fSNamhyung Kim 61439ee533fSNamhyung Kim static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, 61539ee533fSNamhyung Kim unsigned short row __maybe_unused) 61639ee533fSNamhyung Kim { 61739ee533fSNamhyung Kim return false; 61839ee533fSNamhyung Kim } 61939ee533fSNamhyung Kim 620aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 621aca7a94dSNamhyung Kim 62218bb8381SNamhyung Kim static int hist_browser__show_callchain_list(struct hist_browser *browser, 62318bb8381SNamhyung Kim struct callchain_node *node, 62418bb8381SNamhyung Kim struct callchain_list *chain, 62518bb8381SNamhyung Kim unsigned short row, u64 total, 62618bb8381SNamhyung Kim bool need_percent, int offset, 62718bb8381SNamhyung Kim print_callchain_entry_fn print, 62818bb8381SNamhyung Kim struct callchain_print_arg *arg) 62918bb8381SNamhyung Kim { 63018bb8381SNamhyung Kim char bf[1024], *alloc_str; 63118bb8381SNamhyung Kim const char *str; 63218bb8381SNamhyung Kim 63318bb8381SNamhyung Kim if (arg->row_offset != 0) { 63418bb8381SNamhyung Kim arg->row_offset--; 63518bb8381SNamhyung Kim return 0; 63618bb8381SNamhyung Kim } 63718bb8381SNamhyung Kim 63818bb8381SNamhyung Kim alloc_str = NULL; 63918bb8381SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 64018bb8381SNamhyung Kim browser->show_dso); 64118bb8381SNamhyung Kim 64218bb8381SNamhyung Kim if (need_percent) { 64318bb8381SNamhyung Kim char buf[64]; 64418bb8381SNamhyung Kim 64518bb8381SNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), 64618bb8381SNamhyung Kim total); 64718bb8381SNamhyung Kim 64818bb8381SNamhyung Kim if (asprintf(&alloc_str, "%s %s", buf, str) < 0) 64918bb8381SNamhyung Kim str = "Not enough memory!"; 65018bb8381SNamhyung Kim else 65118bb8381SNamhyung Kim str = alloc_str; 65218bb8381SNamhyung Kim } 65318bb8381SNamhyung Kim 65418bb8381SNamhyung Kim print(browser, chain, str, offset, row, arg); 65518bb8381SNamhyung Kim 65618bb8381SNamhyung Kim free(alloc_str); 65718bb8381SNamhyung Kim return 1; 65818bb8381SNamhyung Kim } 65918bb8381SNamhyung Kim 6604b3a3212SNamhyung Kim static int hist_browser__show_callchain_flat(struct hist_browser *browser, 6614b3a3212SNamhyung Kim struct rb_root *root, 6624b3a3212SNamhyung Kim unsigned short row, u64 total, 6634b3a3212SNamhyung Kim print_callchain_entry_fn print, 6644b3a3212SNamhyung Kim struct callchain_print_arg *arg, 6654b3a3212SNamhyung Kim check_output_full_fn is_output_full) 6664b3a3212SNamhyung Kim { 6674b3a3212SNamhyung Kim struct rb_node *node; 6684b3a3212SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 6694b3a3212SNamhyung Kim bool need_percent; 6704b3a3212SNamhyung Kim 6714b3a3212SNamhyung Kim node = rb_first(root); 6724b3a3212SNamhyung Kim need_percent = node && rb_next(node); 6734b3a3212SNamhyung Kim 6744b3a3212SNamhyung Kim while (node) { 6754b3a3212SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 6764b3a3212SNamhyung Kim struct rb_node *next = rb_next(node); 6774b3a3212SNamhyung Kim struct callchain_list *chain; 6784b3a3212SNamhyung Kim char folded_sign = ' '; 6794b3a3212SNamhyung Kim int first = true; 6804b3a3212SNamhyung Kim int extra_offset = 0; 6814b3a3212SNamhyung Kim 6824b3a3212SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 6834b3a3212SNamhyung Kim bool was_first = first; 6844b3a3212SNamhyung Kim 6854b3a3212SNamhyung Kim if (first) 6864b3a3212SNamhyung Kim first = false; 6874b3a3212SNamhyung Kim else if (need_percent) 6884b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 6894b3a3212SNamhyung Kim 6904b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 6914b3a3212SNamhyung Kim 6924b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 6934b3a3212SNamhyung Kim chain, row, total, 6944b3a3212SNamhyung Kim was_first && need_percent, 6954b3a3212SNamhyung Kim offset + extra_offset, 6964b3a3212SNamhyung Kim print, arg); 6974b3a3212SNamhyung Kim 6984b3a3212SNamhyung Kim if (is_output_full(browser, row)) 6994b3a3212SNamhyung Kim goto out; 7004b3a3212SNamhyung Kim 7014b3a3212SNamhyung Kim if (folded_sign == '+') 7024b3a3212SNamhyung Kim goto next; 7034b3a3212SNamhyung Kim } 7044b3a3212SNamhyung Kim 7054b3a3212SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 7064b3a3212SNamhyung Kim bool was_first = first; 7074b3a3212SNamhyung Kim 7084b3a3212SNamhyung Kim if (first) 7094b3a3212SNamhyung Kim first = false; 7104b3a3212SNamhyung Kim else if (need_percent) 7114b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 7124b3a3212SNamhyung Kim 7134b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 7144b3a3212SNamhyung Kim 7154b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 7164b3a3212SNamhyung Kim chain, row, total, 7174b3a3212SNamhyung Kim was_first && need_percent, 7184b3a3212SNamhyung Kim offset + extra_offset, 7194b3a3212SNamhyung Kim print, arg); 7204b3a3212SNamhyung Kim 7214b3a3212SNamhyung Kim if (is_output_full(browser, row)) 7224b3a3212SNamhyung Kim goto out; 7234b3a3212SNamhyung Kim 7244b3a3212SNamhyung Kim if (folded_sign == '+') 7254b3a3212SNamhyung Kim break; 7264b3a3212SNamhyung Kim } 7274b3a3212SNamhyung Kim 7284b3a3212SNamhyung Kim next: 7294b3a3212SNamhyung Kim if (is_output_full(browser, row)) 7304b3a3212SNamhyung Kim break; 7314b3a3212SNamhyung Kim node = next; 7324b3a3212SNamhyung Kim } 7334b3a3212SNamhyung Kim out: 7344b3a3212SNamhyung Kim return row - first_row; 7354b3a3212SNamhyung Kim } 7364b3a3212SNamhyung Kim 7378c430a34SNamhyung Kim static char *hist_browser__folded_callchain_str(struct hist_browser *browser, 7388c430a34SNamhyung Kim struct callchain_list *chain, 7398c430a34SNamhyung Kim char *value_str, char *old_str) 7408c430a34SNamhyung Kim { 7418c430a34SNamhyung Kim char bf[1024]; 7428c430a34SNamhyung Kim const char *str; 7438c430a34SNamhyung Kim char *new; 7448c430a34SNamhyung Kim 7458c430a34SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 7468c430a34SNamhyung Kim browser->show_dso); 7478c430a34SNamhyung Kim if (old_str) { 7488c430a34SNamhyung Kim if (asprintf(&new, "%s%s%s", old_str, 7498c430a34SNamhyung Kim symbol_conf.field_sep ?: ";", str) < 0) 7508c430a34SNamhyung Kim new = NULL; 7518c430a34SNamhyung Kim } else { 7528c430a34SNamhyung Kim if (value_str) { 7538c430a34SNamhyung Kim if (asprintf(&new, "%s %s", value_str, str) < 0) 7548c430a34SNamhyung Kim new = NULL; 7558c430a34SNamhyung Kim } else { 7568c430a34SNamhyung Kim if (asprintf(&new, "%s", str) < 0) 7578c430a34SNamhyung Kim new = NULL; 7588c430a34SNamhyung Kim } 7598c430a34SNamhyung Kim } 7608c430a34SNamhyung Kim return new; 7618c430a34SNamhyung Kim } 7628c430a34SNamhyung Kim 7638c430a34SNamhyung Kim static int hist_browser__show_callchain_folded(struct hist_browser *browser, 7648c430a34SNamhyung Kim struct rb_root *root, 7658c430a34SNamhyung Kim unsigned short row, u64 total, 7668c430a34SNamhyung Kim print_callchain_entry_fn print, 7678c430a34SNamhyung Kim struct callchain_print_arg *arg, 7688c430a34SNamhyung Kim check_output_full_fn is_output_full) 7698c430a34SNamhyung Kim { 7708c430a34SNamhyung Kim struct rb_node *node; 7718c430a34SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 7728c430a34SNamhyung Kim bool need_percent; 7738c430a34SNamhyung Kim 7748c430a34SNamhyung Kim node = rb_first(root); 7758c430a34SNamhyung Kim need_percent = node && rb_next(node); 7768c430a34SNamhyung Kim 7778c430a34SNamhyung Kim while (node) { 7788c430a34SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 7798c430a34SNamhyung Kim struct rb_node *next = rb_next(node); 7808c430a34SNamhyung Kim struct callchain_list *chain, *first_chain = NULL; 7818c430a34SNamhyung Kim int first = true; 7828c430a34SNamhyung Kim char *value_str = NULL, *value_str_alloc = NULL; 7838c430a34SNamhyung Kim char *chain_str = NULL, *chain_str_alloc = NULL; 7848c430a34SNamhyung Kim 7858c430a34SNamhyung Kim if (arg->row_offset != 0) { 7868c430a34SNamhyung Kim arg->row_offset--; 7878c430a34SNamhyung Kim goto next; 7888c430a34SNamhyung Kim } 7898c430a34SNamhyung Kim 7908c430a34SNamhyung Kim if (need_percent) { 7918c430a34SNamhyung Kim char buf[64]; 7928c430a34SNamhyung Kim 7938c430a34SNamhyung Kim callchain_node__scnprintf_value(child, buf, sizeof(buf), total); 7948c430a34SNamhyung Kim if (asprintf(&value_str, "%s", buf) < 0) { 7958c430a34SNamhyung Kim value_str = (char *)"<...>"; 7968c430a34SNamhyung Kim goto do_print; 7978c430a34SNamhyung Kim } 7988c430a34SNamhyung Kim value_str_alloc = value_str; 7998c430a34SNamhyung Kim } 8008c430a34SNamhyung Kim 8018c430a34SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 8028c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 8038c430a34SNamhyung Kim chain, value_str, chain_str); 8048c430a34SNamhyung Kim if (first) { 8058c430a34SNamhyung Kim first = false; 8068c430a34SNamhyung Kim first_chain = chain; 8078c430a34SNamhyung Kim } 8088c430a34SNamhyung Kim 8098c430a34SNamhyung Kim if (chain_str == NULL) { 8108c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 8118c430a34SNamhyung Kim goto do_print; 8128c430a34SNamhyung Kim } 8138c430a34SNamhyung Kim 8148c430a34SNamhyung Kim chain_str_alloc = chain_str; 8158c430a34SNamhyung Kim } 8168c430a34SNamhyung Kim 8178c430a34SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 8188c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 8198c430a34SNamhyung Kim chain, value_str, chain_str); 8208c430a34SNamhyung Kim if (first) { 8218c430a34SNamhyung Kim first = false; 8228c430a34SNamhyung Kim first_chain = chain; 8238c430a34SNamhyung Kim } 8248c430a34SNamhyung Kim 8258c430a34SNamhyung Kim if (chain_str == NULL) { 8268c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 8278c430a34SNamhyung Kim goto do_print; 8288c430a34SNamhyung Kim } 8298c430a34SNamhyung Kim 8308c430a34SNamhyung Kim chain_str_alloc = chain_str; 8318c430a34SNamhyung Kim } 8328c430a34SNamhyung Kim 8338c430a34SNamhyung Kim do_print: 8348c430a34SNamhyung Kim print(browser, first_chain, chain_str, offset, row++, arg); 8358c430a34SNamhyung Kim free(value_str_alloc); 8368c430a34SNamhyung Kim free(chain_str_alloc); 8378c430a34SNamhyung Kim 8388c430a34SNamhyung Kim next: 8398c430a34SNamhyung Kim if (is_output_full(browser, row)) 8408c430a34SNamhyung Kim break; 8418c430a34SNamhyung Kim node = next; 8428c430a34SNamhyung Kim } 8438c430a34SNamhyung Kim 8448c430a34SNamhyung Kim return row - first_row; 8458c430a34SNamhyung Kim } 8468c430a34SNamhyung Kim 847c09a7e75SNamhyung Kim static int hist_browser__show_callchain(struct hist_browser *browser, 848c09a7e75SNamhyung Kim struct rb_root *root, int level, 84939ee533fSNamhyung Kim unsigned short row, u64 total, 85039ee533fSNamhyung Kim print_callchain_entry_fn print, 85139ee533fSNamhyung Kim struct callchain_print_arg *arg, 85239ee533fSNamhyung Kim check_output_full_fn is_output_full) 853aca7a94dSNamhyung Kim { 854aca7a94dSNamhyung Kim struct rb_node *node; 855f4536dddSNamhyung Kim int first_row = row, offset = level * LEVEL_OFFSET_STEP; 85636e15dd4SNamhyung Kim u64 new_total; 8574087d11cSNamhyung Kim bool need_percent; 858aca7a94dSNamhyung Kim 859c09a7e75SNamhyung Kim node = rb_first(root); 860c09e31ccSNamhyung Kim need_percent = node && rb_next(node); 8614087d11cSNamhyung Kim 862aca7a94dSNamhyung Kim while (node) { 863aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 864aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 865aca7a94dSNamhyung Kim struct callchain_list *chain; 866aca7a94dSNamhyung Kim char folded_sign = ' '; 867aca7a94dSNamhyung Kim int first = true; 868aca7a94dSNamhyung Kim int extra_offset = 0; 869aca7a94dSNamhyung Kim 870aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 871aca7a94dSNamhyung Kim bool was_first = first; 872aca7a94dSNamhyung Kim 873aca7a94dSNamhyung Kim if (first) 874aca7a94dSNamhyung Kim first = false; 8754087d11cSNamhyung Kim else if (need_percent) 876aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 877aca7a94dSNamhyung Kim 878aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 879aca7a94dSNamhyung Kim 88018bb8381SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 88118bb8381SNamhyung Kim chain, row, total, 88218bb8381SNamhyung Kim was_first && need_percent, 88318bb8381SNamhyung Kim offset + extra_offset, 88418bb8381SNamhyung Kim print, arg); 885c09a7e75SNamhyung Kim 88618bb8381SNamhyung Kim if (is_output_full(browser, row)) 887aca7a94dSNamhyung Kim goto out; 88818bb8381SNamhyung Kim 889aca7a94dSNamhyung Kim if (folded_sign == '+') 890aca7a94dSNamhyung Kim break; 891aca7a94dSNamhyung Kim } 892aca7a94dSNamhyung Kim 893aca7a94dSNamhyung Kim if (folded_sign == '-') { 894aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 895c09a7e75SNamhyung Kim 896c09a7e75SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 897c09a7e75SNamhyung Kim new_total = child->children_hit; 898c09a7e75SNamhyung Kim else 899c09a7e75SNamhyung Kim new_total = total; 900c09a7e75SNamhyung Kim 901c09a7e75SNamhyung Kim row += hist_browser__show_callchain(browser, &child->rb_root, 90239ee533fSNamhyung Kim new_level, row, new_total, 90339ee533fSNamhyung Kim print, arg, is_output_full); 904aca7a94dSNamhyung Kim } 90539ee533fSNamhyung Kim if (is_output_full(browser, row)) 906c09a7e75SNamhyung Kim break; 907aca7a94dSNamhyung Kim node = next; 908aca7a94dSNamhyung Kim } 909aca7a94dSNamhyung Kim out: 910aca7a94dSNamhyung Kim return row - first_row; 911aca7a94dSNamhyung Kim } 912aca7a94dSNamhyung Kim 91389701460SNamhyung Kim struct hpp_arg { 91489701460SNamhyung Kim struct ui_browser *b; 91589701460SNamhyung Kim char folded_sign; 91689701460SNamhyung Kim bool current_entry; 91789701460SNamhyung Kim }; 91889701460SNamhyung Kim 9192f6d9009SNamhyung Kim static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 9202f6d9009SNamhyung Kim { 9212f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 922d675107cSNamhyung Kim int ret, len; 9232f6d9009SNamhyung Kim va_list args; 9242f6d9009SNamhyung Kim double percent; 9252f6d9009SNamhyung Kim 9262f6d9009SNamhyung Kim va_start(args, fmt); 927d675107cSNamhyung Kim len = va_arg(args, int); 9282f6d9009SNamhyung Kim percent = va_arg(args, double); 9292f6d9009SNamhyung Kim va_end(args); 9305aed9d24SNamhyung Kim 93189701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 9325aed9d24SNamhyung Kim 933d675107cSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); 934517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); 93589701460SNamhyung Kim 9362f6d9009SNamhyung Kim advance_hpp(hpp, ret); 9375aed9d24SNamhyung Kim return ret; 938f5951d56SNamhyung Kim } 939f5951d56SNamhyung Kim 940fb821c9eSNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field) \ 9415aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 9425aed9d24SNamhyung Kim { \ 9435aed9d24SNamhyung Kim return he->stat._field; \ 9445aed9d24SNamhyung Kim } \ 9455aed9d24SNamhyung Kim \ 9462c5d4b4aSJiri Olsa static int \ 9475b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 9482c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 9495aed9d24SNamhyung Kim struct hist_entry *he) \ 9505aed9d24SNamhyung Kim { \ 9515b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \ 9522f6d9009SNamhyung Kim __hpp__slsmg_color_printf, true); \ 9535aed9d24SNamhyung Kim } 954f5951d56SNamhyung Kim 9550434ddd2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 9560434ddd2SNamhyung Kim static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ 9570434ddd2SNamhyung Kim { \ 9580434ddd2SNamhyung Kim return he->stat_acc->_field; \ 9590434ddd2SNamhyung Kim } \ 9600434ddd2SNamhyung Kim \ 9610434ddd2SNamhyung Kim static int \ 9625b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 9630434ddd2SNamhyung Kim struct perf_hpp *hpp, \ 9640434ddd2SNamhyung Kim struct hist_entry *he) \ 9650434ddd2SNamhyung Kim { \ 9660434ddd2SNamhyung Kim if (!symbol_conf.cumulate_callchain) { \ 967517dfdb3SArnaldo Carvalho de Melo struct hpp_arg *arg = hpp->ptr; \ 9685b591669SNamhyung Kim int len = fmt->user_len ?: fmt->len; \ 969d675107cSNamhyung Kim int ret = scnprintf(hpp->buf, hpp->size, \ 9705b591669SNamhyung Kim "%*s", len, "N/A"); \ 971517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); \ 9720434ddd2SNamhyung Kim \ 9730434ddd2SNamhyung Kim return ret; \ 9740434ddd2SNamhyung Kim } \ 9755b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \ 9765b591669SNamhyung Kim " %*.2f%%", __hpp__slsmg_color_printf, true); \ 9770434ddd2SNamhyung Kim } 9780434ddd2SNamhyung Kim 979fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period) 980fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 981fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us) 982fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 983fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 9840434ddd2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period) 9855aed9d24SNamhyung Kim 9865aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 9870434ddd2SNamhyung Kim #undef __HPP_COLOR_ACC_PERCENT_FN 988f5951d56SNamhyung Kim 989f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 990f5951d56SNamhyung Kim { 991f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 992f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 993f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 994f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 995f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 996f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 997f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 998f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 999f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 1000f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 10010434ddd2SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = 10020434ddd2SNamhyung Kim hist_browser__hpp_color_overhead_acc; 1003f5951d56SNamhyung Kim } 1004f5951d56SNamhyung Kim 100505e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 1006aca7a94dSNamhyung Kim struct hist_entry *entry, 1007aca7a94dSNamhyung Kim unsigned short row) 1008aca7a94dSNamhyung Kim { 1009aca7a94dSNamhyung Kim char s[256]; 10101240005eSJiri Olsa int printed = 0; 101167d25916SNamhyung Kim int width = browser->b.width; 1012aca7a94dSNamhyung Kim char folded_sign = ' '; 101305e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1014aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 101563a1a3d8SNamhyung Kim bool first = true; 10161240005eSJiri Olsa struct perf_hpp_fmt *fmt; 1017aca7a94dSNamhyung Kim 1018aca7a94dSNamhyung Kim if (current_entry) { 101905e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 102005e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 1021aca7a94dSNamhyung Kim } 1022aca7a94dSNamhyung Kim 1023aca7a94dSNamhyung Kim if (symbol_conf.use_callchain) { 1024aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 1025aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 1026aca7a94dSNamhyung Kim } 1027aca7a94dSNamhyung Kim 1028aca7a94dSNamhyung Kim if (row_offset == 0) { 102989701460SNamhyung Kim struct hpp_arg arg = { 103089701460SNamhyung Kim .b = &browser->b, 103189701460SNamhyung Kim .folded_sign = folded_sign, 103289701460SNamhyung Kim .current_entry = current_entry, 103389701460SNamhyung Kim }; 1034f5951d56SNamhyung Kim struct perf_hpp hpp = { 1035f5951d56SNamhyung Kim .buf = s, 1036f5951d56SNamhyung Kim .size = sizeof(s), 103789701460SNamhyung Kim .ptr = &arg, 1038f5951d56SNamhyung Kim }; 1039c6c3c02dSArnaldo Carvalho de Melo int column = 0; 1040f5951d56SNamhyung Kim 1041ca3ff33bSArnaldo Carvalho de Melo hist_browser__gotorc(browser, row, 0); 1042f5951d56SNamhyung Kim 10431240005eSJiri Olsa perf_hpp__for_each_format(fmt) { 1044*361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1045*361459f1SNamhyung Kim column++ < browser->b.horiz_scroll) 1046e67d49a7SNamhyung Kim continue; 1047e67d49a7SNamhyung Kim 1048fb821c9eSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1049fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1050fb821c9eSNamhyung Kim HE_COLORSET_SELECTED); 1051fb821c9eSNamhyung Kim } else { 1052fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1053fb821c9eSNamhyung Kim HE_COLORSET_NORMAL); 1054fb821c9eSNamhyung Kim } 1055fb821c9eSNamhyung Kim 1056fb821c9eSNamhyung Kim if (first) { 1057fb821c9eSNamhyung Kim if (symbol_conf.use_callchain) { 1058517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c ", folded_sign); 1059f5951d56SNamhyung Kim width -= 2; 1060f5951d56SNamhyung Kim } 106163a1a3d8SNamhyung Kim first = false; 1062fb821c9eSNamhyung Kim } else { 1063517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, " "); 1064fb821c9eSNamhyung Kim width -= 2; 1065fb821c9eSNamhyung Kim } 1066f5951d56SNamhyung Kim 10671240005eSJiri Olsa if (fmt->color) { 10682c5d4b4aSJiri Olsa width -= fmt->color(fmt, &hpp, entry); 1069f5951d56SNamhyung Kim } else { 10702c5d4b4aSJiri Olsa width -= fmt->entry(fmt, &hpp, entry); 1071517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s); 1072f5951d56SNamhyung Kim } 1073f5951d56SNamhyung Kim } 1074aca7a94dSNamhyung Kim 1075aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 107605e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 1077aca7a94dSNamhyung Kim width += 1; 1078aca7a94dSNamhyung Kim 107926270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, "", width); 108026d8b338SNamhyung Kim 1081aca7a94dSNamhyung Kim ++row; 1082aca7a94dSNamhyung Kim ++printed; 1083aca7a94dSNamhyung Kim } else 1084aca7a94dSNamhyung Kim --row_offset; 1085aca7a94dSNamhyung Kim 108662c95ae3SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.rows) { 1087c09a7e75SNamhyung Kim u64 total = hists__total_period(entry->hists); 108839ee533fSNamhyung Kim struct callchain_print_arg arg = { 108939ee533fSNamhyung Kim .row_offset = row_offset, 109039ee533fSNamhyung Kim .is_current_entry = current_entry, 109139ee533fSNamhyung Kim }; 1092c09a7e75SNamhyung Kim 10934087d11cSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) { 10944087d11cSNamhyung Kim if (symbol_conf.cumulate_callchain) 10954087d11cSNamhyung Kim total = entry->stat_acc->period; 10964087d11cSNamhyung Kim else 10974087d11cSNamhyung Kim total = entry->stat.period; 10984087d11cSNamhyung Kim } 10994087d11cSNamhyung Kim 11004b3a3212SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) { 11014b3a3212SNamhyung Kim printed += hist_browser__show_callchain_flat(browser, 11024b3a3212SNamhyung Kim &entry->sorted_chain, row, total, 11034b3a3212SNamhyung Kim hist_browser__show_callchain_entry, &arg, 11044b3a3212SNamhyung Kim hist_browser__check_output_full); 11058c430a34SNamhyung Kim } else if (callchain_param.mode == CHAIN_FOLDED) { 11068c430a34SNamhyung Kim printed += hist_browser__show_callchain_folded(browser, 11078c430a34SNamhyung Kim &entry->sorted_chain, row, total, 11088c430a34SNamhyung Kim hist_browser__show_callchain_entry, &arg, 11098c430a34SNamhyung Kim hist_browser__check_output_full); 11104b3a3212SNamhyung Kim } else { 1111c09a7e75SNamhyung Kim printed += hist_browser__show_callchain(browser, 111239ee533fSNamhyung Kim &entry->sorted_chain, 1, row, total, 111339ee533fSNamhyung Kim hist_browser__show_callchain_entry, &arg, 111439ee533fSNamhyung Kim hist_browser__check_output_full); 11154b3a3212SNamhyung Kim } 1116c09a7e75SNamhyung Kim 111739ee533fSNamhyung Kim if (arg.is_current_entry) 111805e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 1119aca7a94dSNamhyung Kim } 1120aca7a94dSNamhyung Kim 1121aca7a94dSNamhyung Kim return printed; 1122aca7a94dSNamhyung Kim } 1123aca7a94dSNamhyung Kim 112481a888feSJiri Olsa static int advance_hpp_check(struct perf_hpp *hpp, int inc) 112581a888feSJiri Olsa { 112681a888feSJiri Olsa advance_hpp(hpp, inc); 112781a888feSJiri Olsa return hpp->size <= 0; 112881a888feSJiri Olsa } 112981a888feSJiri Olsa 1130c6c3c02dSArnaldo Carvalho de Melo static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size) 113181a888feSJiri Olsa { 1132c6c3c02dSArnaldo Carvalho de Melo struct hists *hists = browser->hists; 113381a888feSJiri Olsa struct perf_hpp dummy_hpp = { 113481a888feSJiri Olsa .buf = buf, 113581a888feSJiri Olsa .size = size, 113681a888feSJiri Olsa }; 113781a888feSJiri Olsa struct perf_hpp_fmt *fmt; 113881a888feSJiri Olsa size_t ret = 0; 1139c6c3c02dSArnaldo Carvalho de Melo int column = 0; 114081a888feSJiri Olsa 114181a888feSJiri Olsa if (symbol_conf.use_callchain) { 114281a888feSJiri Olsa ret = scnprintf(buf, size, " "); 114381a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 114481a888feSJiri Olsa return ret; 114581a888feSJiri Olsa } 114681a888feSJiri Olsa 114781a888feSJiri Olsa perf_hpp__for_each_format(fmt) { 1148*361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) 114981a888feSJiri Olsa continue; 115081a888feSJiri Olsa 115181a888feSJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); 115281a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 115381a888feSJiri Olsa break; 115481a888feSJiri Olsa 115581a888feSJiri Olsa ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 115681a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 115781a888feSJiri Olsa break; 115881a888feSJiri Olsa } 115981a888feSJiri Olsa 116081a888feSJiri Olsa return ret; 116181a888feSJiri Olsa } 116281a888feSJiri Olsa 1163025bf7eaSArnaldo Carvalho de Melo static void hist_browser__show_headers(struct hist_browser *browser) 1164025bf7eaSArnaldo Carvalho de Melo { 116581a888feSJiri Olsa char headers[1024]; 116681a888feSJiri Olsa 1167c6c3c02dSArnaldo Carvalho de Melo hists_browser__scnprintf_headers(browser, headers, sizeof(headers)); 1168025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, 0, 0); 1169025bf7eaSArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 117026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 1171025bf7eaSArnaldo Carvalho de Melo } 1172025bf7eaSArnaldo Carvalho de Melo 1173aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 1174aca7a94dSNamhyung Kim { 1175aca7a94dSNamhyung Kim if (browser->top == NULL) { 1176aca7a94dSNamhyung Kim struct hist_browser *hb; 1177aca7a94dSNamhyung Kim 1178aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1179aca7a94dSNamhyung Kim browser->top = rb_first(&hb->hists->entries); 1180aca7a94dSNamhyung Kim } 1181aca7a94dSNamhyung Kim } 1182aca7a94dSNamhyung Kim 118305e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 1184aca7a94dSNamhyung Kim { 1185aca7a94dSNamhyung Kim unsigned row = 0; 1186025bf7eaSArnaldo Carvalho de Melo u16 header_offset = 0; 1187aca7a94dSNamhyung Kim struct rb_node *nd; 118805e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 1189aca7a94dSNamhyung Kim 1190025bf7eaSArnaldo Carvalho de Melo if (hb->show_headers) { 1191025bf7eaSArnaldo Carvalho de Melo hist_browser__show_headers(hb); 1192025bf7eaSArnaldo Carvalho de Melo header_offset = 1; 1193025bf7eaSArnaldo Carvalho de Melo } 1194025bf7eaSArnaldo Carvalho de Melo 119505e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1196979d2cacSWang Nan hb->he_selection = NULL; 1197979d2cacSWang Nan hb->selection = NULL; 1198aca7a94dSNamhyung Kim 119905e8b080SArnaldo Carvalho de Melo for (nd = browser->top; nd; nd = rb_next(nd)) { 1200aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 120114135663SNamhyung Kim float percent; 1202aca7a94dSNamhyung Kim 1203aca7a94dSNamhyung Kim if (h->filtered) 1204aca7a94dSNamhyung Kim continue; 1205aca7a94dSNamhyung Kim 120614135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 1207064f1981SNamhyung Kim if (percent < hb->min_pcnt) 1208064f1981SNamhyung Kim continue; 1209064f1981SNamhyung Kim 1210aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 121162c95ae3SArnaldo Carvalho de Melo if (row == browser->rows) 1212aca7a94dSNamhyung Kim break; 1213aca7a94dSNamhyung Kim } 1214aca7a94dSNamhyung Kim 1215025bf7eaSArnaldo Carvalho de Melo return row + header_offset; 1216aca7a94dSNamhyung Kim } 1217aca7a94dSNamhyung Kim 1218064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 1219064f1981SNamhyung Kim float min_pcnt) 1220aca7a94dSNamhyung Kim { 1221aca7a94dSNamhyung Kim while (nd != NULL) { 1222aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 122314135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1224064f1981SNamhyung Kim 1225c0f1527bSNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1226aca7a94dSNamhyung Kim return nd; 1227aca7a94dSNamhyung Kim 1228aca7a94dSNamhyung Kim nd = rb_next(nd); 1229aca7a94dSNamhyung Kim } 1230aca7a94dSNamhyung Kim 1231aca7a94dSNamhyung Kim return NULL; 1232aca7a94dSNamhyung Kim } 1233aca7a94dSNamhyung Kim 1234064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 1235064f1981SNamhyung Kim float min_pcnt) 1236aca7a94dSNamhyung Kim { 1237aca7a94dSNamhyung Kim while (nd != NULL) { 1238aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 123914135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1240064f1981SNamhyung Kim 1241064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1242aca7a94dSNamhyung Kim return nd; 1243aca7a94dSNamhyung Kim 1244aca7a94dSNamhyung Kim nd = rb_prev(nd); 1245aca7a94dSNamhyung Kim } 1246aca7a94dSNamhyung Kim 1247aca7a94dSNamhyung Kim return NULL; 1248aca7a94dSNamhyung Kim } 1249aca7a94dSNamhyung Kim 125005e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 1251aca7a94dSNamhyung Kim off_t offset, int whence) 1252aca7a94dSNamhyung Kim { 1253aca7a94dSNamhyung Kim struct hist_entry *h; 1254aca7a94dSNamhyung Kim struct rb_node *nd; 1255aca7a94dSNamhyung Kim bool first = true; 1256064f1981SNamhyung Kim struct hist_browser *hb; 1257064f1981SNamhyung Kim 1258064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1259aca7a94dSNamhyung Kim 126005e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 1261aca7a94dSNamhyung Kim return; 1262aca7a94dSNamhyung Kim 126305e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1264aca7a94dSNamhyung Kim 1265aca7a94dSNamhyung Kim switch (whence) { 1266aca7a94dSNamhyung Kim case SEEK_SET: 1267064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 126814135663SNamhyung Kim hb->min_pcnt); 1269aca7a94dSNamhyung Kim break; 1270aca7a94dSNamhyung Kim case SEEK_CUR: 127105e8b080SArnaldo Carvalho de Melo nd = browser->top; 1272aca7a94dSNamhyung Kim goto do_offset; 1273aca7a94dSNamhyung Kim case SEEK_END: 1274064f1981SNamhyung Kim nd = hists__filter_prev_entries(rb_last(browser->entries), 127514135663SNamhyung Kim hb->min_pcnt); 1276aca7a94dSNamhyung Kim first = false; 1277aca7a94dSNamhyung Kim break; 1278aca7a94dSNamhyung Kim default: 1279aca7a94dSNamhyung Kim return; 1280aca7a94dSNamhyung Kim } 1281aca7a94dSNamhyung Kim 1282aca7a94dSNamhyung Kim /* 1283aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 1284aca7a94dSNamhyung Kim * row_offset: 1285aca7a94dSNamhyung Kim */ 128605e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 1287aca7a94dSNamhyung Kim h->row_offset = 0; 1288aca7a94dSNamhyung Kim 1289aca7a94dSNamhyung Kim /* 1290aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 1291aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 1292aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 1293aca7a94dSNamhyung Kim * 1294aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 1295aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 1296aca7a94dSNamhyung Kim * 1297aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 1298aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 1299aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 1300aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 1301aca7a94dSNamhyung Kim */ 1302aca7a94dSNamhyung Kim do_offset: 1303837eeb75SWang Nan if (!nd) 1304837eeb75SWang Nan return; 1305837eeb75SWang Nan 1306aca7a94dSNamhyung Kim if (offset > 0) { 1307aca7a94dSNamhyung Kim do { 1308aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 13093698dab1SNamhyung Kim if (h->unfolded) { 1310aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 1311aca7a94dSNamhyung Kim if (offset > remaining) { 1312aca7a94dSNamhyung Kim offset -= remaining; 1313aca7a94dSNamhyung Kim h->row_offset = 0; 1314aca7a94dSNamhyung Kim } else { 1315aca7a94dSNamhyung Kim h->row_offset += offset; 1316aca7a94dSNamhyung Kim offset = 0; 131705e8b080SArnaldo Carvalho de Melo browser->top = nd; 1318aca7a94dSNamhyung Kim break; 1319aca7a94dSNamhyung Kim } 1320aca7a94dSNamhyung Kim } 132114135663SNamhyung Kim nd = hists__filter_entries(rb_next(nd), hb->min_pcnt); 1322aca7a94dSNamhyung Kim if (nd == NULL) 1323aca7a94dSNamhyung Kim break; 1324aca7a94dSNamhyung Kim --offset; 132505e8b080SArnaldo Carvalho de Melo browser->top = nd; 1326aca7a94dSNamhyung Kim } while (offset != 0); 1327aca7a94dSNamhyung Kim } else if (offset < 0) { 1328aca7a94dSNamhyung Kim while (1) { 1329aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 13303698dab1SNamhyung Kim if (h->unfolded) { 1331aca7a94dSNamhyung Kim if (first) { 1332aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 1333aca7a94dSNamhyung Kim offset += h->row_offset; 1334aca7a94dSNamhyung Kim h->row_offset = 0; 1335aca7a94dSNamhyung Kim } else { 1336aca7a94dSNamhyung Kim h->row_offset += offset; 1337aca7a94dSNamhyung Kim offset = 0; 133805e8b080SArnaldo Carvalho de Melo browser->top = nd; 1339aca7a94dSNamhyung Kim break; 1340aca7a94dSNamhyung Kim } 1341aca7a94dSNamhyung Kim } else { 1342aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 1343aca7a94dSNamhyung Kim offset += h->nr_rows; 1344aca7a94dSNamhyung Kim h->row_offset = 0; 1345aca7a94dSNamhyung Kim } else { 1346aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 1347aca7a94dSNamhyung Kim offset = 0; 134805e8b080SArnaldo Carvalho de Melo browser->top = nd; 1349aca7a94dSNamhyung Kim break; 1350aca7a94dSNamhyung Kim } 1351aca7a94dSNamhyung Kim } 1352aca7a94dSNamhyung Kim } 1353aca7a94dSNamhyung Kim 135414135663SNamhyung Kim nd = hists__filter_prev_entries(rb_prev(nd), 1355064f1981SNamhyung Kim hb->min_pcnt); 1356aca7a94dSNamhyung Kim if (nd == NULL) 1357aca7a94dSNamhyung Kim break; 1358aca7a94dSNamhyung Kim ++offset; 135905e8b080SArnaldo Carvalho de Melo browser->top = nd; 1360aca7a94dSNamhyung Kim if (offset == 0) { 1361aca7a94dSNamhyung Kim /* 1362aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 1363aca7a94dSNamhyung Kim * unfolded, if it is then we should have 1364aca7a94dSNamhyung Kim * row_offset at its last entry. 1365aca7a94dSNamhyung Kim */ 1366aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 13673698dab1SNamhyung Kim if (h->unfolded) 1368aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 1369aca7a94dSNamhyung Kim break; 1370aca7a94dSNamhyung Kim } 1371aca7a94dSNamhyung Kim first = false; 1372aca7a94dSNamhyung Kim } 1373aca7a94dSNamhyung Kim } else { 137405e8b080SArnaldo Carvalho de Melo browser->top = nd; 1375aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1376aca7a94dSNamhyung Kim h->row_offset = 0; 1377aca7a94dSNamhyung Kim } 1378aca7a94dSNamhyung Kim } 1379aca7a94dSNamhyung Kim 1380aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 138139ee533fSNamhyung Kim struct hist_entry *he, FILE *fp) 1382aff3f3f6SArnaldo Carvalho de Melo { 138339ee533fSNamhyung Kim u64 total = hists__total_period(he->hists); 138439ee533fSNamhyung Kim struct callchain_print_arg arg = { 138539ee533fSNamhyung Kim .fp = fp, 138639ee533fSNamhyung Kim }; 1387aff3f3f6SArnaldo Carvalho de Melo 138839ee533fSNamhyung Kim if (symbol_conf.cumulate_callchain) 138939ee533fSNamhyung Kim total = he->stat_acc->period; 1390aff3f3f6SArnaldo Carvalho de Melo 139139ee533fSNamhyung Kim hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total, 139239ee533fSNamhyung Kim hist_browser__fprintf_callchain_entry, &arg, 139339ee533fSNamhyung Kim hist_browser__check_dump_full); 139439ee533fSNamhyung Kim return arg.printed; 1395aff3f3f6SArnaldo Carvalho de Melo } 1396aff3f3f6SArnaldo Carvalho de Melo 1397aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 1398aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 1399aff3f3f6SArnaldo Carvalho de Melo { 1400aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 1401aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1402aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 140326d8b338SNamhyung Kim struct perf_hpp hpp = { 140426d8b338SNamhyung Kim .buf = s, 140526d8b338SNamhyung Kim .size = sizeof(s), 140626d8b338SNamhyung Kim }; 140726d8b338SNamhyung Kim struct perf_hpp_fmt *fmt; 140826d8b338SNamhyung Kim bool first = true; 140926d8b338SNamhyung Kim int ret; 1410aff3f3f6SArnaldo Carvalho de Melo 1411aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1412aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 1413aff3f3f6SArnaldo Carvalho de Melo 1414aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1415aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 1416aff3f3f6SArnaldo Carvalho de Melo 141726d8b338SNamhyung Kim perf_hpp__for_each_format(fmt) { 1418*361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, he->hists)) 1419e67d49a7SNamhyung Kim continue; 1420e67d49a7SNamhyung Kim 142126d8b338SNamhyung Kim if (!first) { 142226d8b338SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 142326d8b338SNamhyung Kim advance_hpp(&hpp, ret); 142426d8b338SNamhyung Kim } else 142526d8b338SNamhyung Kim first = false; 1426aff3f3f6SArnaldo Carvalho de Melo 142726d8b338SNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 142826d8b338SNamhyung Kim advance_hpp(&hpp, ret); 142926d8b338SNamhyung Kim } 1430aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", rtrim(s)); 1431aff3f3f6SArnaldo Carvalho de Melo 1432aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 143339ee533fSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp); 1434aff3f3f6SArnaldo Carvalho de Melo 1435aff3f3f6SArnaldo Carvalho de Melo return printed; 1436aff3f3f6SArnaldo Carvalho de Melo } 1437aff3f3f6SArnaldo Carvalho de Melo 1438aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1439aff3f3f6SArnaldo Carvalho de Melo { 1440064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1441064f1981SNamhyung Kim browser->min_pcnt); 1442aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1443aff3f3f6SArnaldo Carvalho de Melo 1444aff3f3f6SArnaldo Carvalho de Melo while (nd) { 1445aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1446aff3f3f6SArnaldo Carvalho de Melo 1447aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 144814135663SNamhyung Kim nd = hists__filter_entries(rb_next(nd), browser->min_pcnt); 1449aff3f3f6SArnaldo Carvalho de Melo } 1450aff3f3f6SArnaldo Carvalho de Melo 1451aff3f3f6SArnaldo Carvalho de Melo return printed; 1452aff3f3f6SArnaldo Carvalho de Melo } 1453aff3f3f6SArnaldo Carvalho de Melo 1454aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 1455aff3f3f6SArnaldo Carvalho de Melo { 1456aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 1457aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 1458aff3f3f6SArnaldo Carvalho de Melo 1459aff3f3f6SArnaldo Carvalho de Melo while (1) { 1460aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 1461aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 1462aff3f3f6SArnaldo Carvalho de Melo break; 1463aff3f3f6SArnaldo Carvalho de Melo /* 1464aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 1465aff3f3f6SArnaldo Carvalho de Melo */ 1466aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 1467aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 1468aff3f3f6SArnaldo Carvalho de Melo return -1; 1469aff3f3f6SArnaldo Carvalho de Melo } 1470aff3f3f6SArnaldo Carvalho de Melo } 1471aff3f3f6SArnaldo Carvalho de Melo 1472aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 1473aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 1474aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 14754cc49d4dSKirill A. Shutemov const char *err = strerror_r(errno, bf, sizeof(bf)); 14764cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 1477aff3f3f6SArnaldo Carvalho de Melo return -1; 1478aff3f3f6SArnaldo Carvalho de Melo } 1479aff3f3f6SArnaldo Carvalho de Melo 1480aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 1481aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 1482aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 1483aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 1484aff3f3f6SArnaldo Carvalho de Melo 1485aff3f3f6SArnaldo Carvalho de Melo return 0; 1486aff3f3f6SArnaldo Carvalho de Melo } 1487aff3f3f6SArnaldo Carvalho de Melo 1488c2a51ab8SNamhyung Kim static struct hist_browser *hist_browser__new(struct hists *hists, 1489b1a9ceefSNamhyung Kim struct hist_browser_timer *hbt, 1490ce80d3beSKan Liang struct perf_env *env) 1491aca7a94dSNamhyung Kim { 149205e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = zalloc(sizeof(*browser)); 1493aca7a94dSNamhyung Kim 149405e8b080SArnaldo Carvalho de Melo if (browser) { 149505e8b080SArnaldo Carvalho de Melo browser->hists = hists; 149605e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 1497357cfff1SArnaldo Carvalho de Melo browser->b.refresh_dimensions = hist_browser__refresh_dimensions; 149805e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 149905e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 1500c8302367SJiri Olsa browser->show_headers = symbol_conf.show_hist_headers; 1501c2a51ab8SNamhyung Kim browser->hbt = hbt; 1502b1a9ceefSNamhyung Kim browser->env = env; 1503aca7a94dSNamhyung Kim } 1504aca7a94dSNamhyung Kim 150505e8b080SArnaldo Carvalho de Melo return browser; 1506aca7a94dSNamhyung Kim } 1507aca7a94dSNamhyung Kim 150805e8b080SArnaldo Carvalho de Melo static void hist_browser__delete(struct hist_browser *browser) 1509aca7a94dSNamhyung Kim { 151005e8b080SArnaldo Carvalho de Melo free(browser); 1511aca7a94dSNamhyung Kim } 1512aca7a94dSNamhyung Kim 151305e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 1514aca7a94dSNamhyung Kim { 151505e8b080SArnaldo Carvalho de Melo return browser->he_selection; 1516aca7a94dSNamhyung Kim } 1517aca7a94dSNamhyung Kim 151805e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 1519aca7a94dSNamhyung Kim { 152005e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 1521aca7a94dSNamhyung Kim } 1522aca7a94dSNamhyung Kim 15231e378ebdSTaeung Song /* Check whether the browser is for 'top' or 'report' */ 15241e378ebdSTaeung Song static inline bool is_report_browser(void *timer) 15251e378ebdSTaeung Song { 15261e378ebdSTaeung Song return timer == NULL; 15271e378ebdSTaeung Song } 15281e378ebdSTaeung Song 15291e378ebdSTaeung Song static int hists__browser_title(struct hists *hists, 15301e378ebdSTaeung Song struct hist_browser_timer *hbt, 15311e378ebdSTaeung Song char *bf, size_t size) 1532aca7a94dSNamhyung Kim { 1533aca7a94dSNamhyung Kim char unit; 1534aca7a94dSNamhyung Kim int printed; 153505e8b080SArnaldo Carvalho de Melo const struct dso *dso = hists->dso_filter; 153605e8b080SArnaldo Carvalho de Melo const struct thread *thread = hists->thread_filter; 153784734b06SKan Liang int socket_id = hists->socket_filter; 153805e8b080SArnaldo Carvalho de Melo unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 153905e8b080SArnaldo Carvalho de Melo u64 nr_events = hists->stats.total_period; 1540717e263fSNamhyung Kim struct perf_evsel *evsel = hists_to_evsel(hists); 1541dd00d486SJiri Olsa const char *ev_name = perf_evsel__name(evsel); 1542717e263fSNamhyung Kim char buf[512]; 1543717e263fSNamhyung Kim size_t buflen = sizeof(buf); 15449e207ddfSKan Liang char ref[30] = " show reference callgraph, "; 15459e207ddfSKan Liang bool enable_ref = false; 1546717e263fSNamhyung Kim 1547f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 1548f2148330SNamhyung Kim nr_samples = hists->stats.nr_non_filtered_samples; 1549f2148330SNamhyung Kim nr_events = hists->stats.total_non_filtered_period; 1550f2148330SNamhyung Kim } 1551f2148330SNamhyung Kim 1552759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1553717e263fSNamhyung Kim struct perf_evsel *pos; 1554717e263fSNamhyung Kim 1555717e263fSNamhyung Kim perf_evsel__group_desc(evsel, buf, buflen); 1556717e263fSNamhyung Kim ev_name = buf; 1557717e263fSNamhyung Kim 1558717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 15594ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 15604ea062edSArnaldo Carvalho de Melo 1561f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 15624ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_non_filtered_samples; 15634ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_non_filtered_period; 1564f2148330SNamhyung Kim } else { 15654ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 15664ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_period; 1567717e263fSNamhyung Kim } 1568717e263fSNamhyung Kim } 1569f2148330SNamhyung Kim } 1570aca7a94dSNamhyung Kim 15719e207ddfSKan Liang if (symbol_conf.show_ref_callgraph && 15729e207ddfSKan Liang strstr(ev_name, "call-graph=no")) 15739e207ddfSKan Liang enable_ref = true; 1574aca7a94dSNamhyung Kim nr_samples = convert_unit(nr_samples, &unit); 1575aca7a94dSNamhyung Kim printed = scnprintf(bf, size, 15769e207ddfSKan Liang "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64, 15779e207ddfSKan Liang nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events); 1578aca7a94dSNamhyung Kim 1579aca7a94dSNamhyung Kim 158005e8b080SArnaldo Carvalho de Melo if (hists->uid_filter_str) 1581aca7a94dSNamhyung Kim printed += snprintf(bf + printed, size - printed, 158205e8b080SArnaldo Carvalho de Melo ", UID: %s", hists->uid_filter_str); 1583aca7a94dSNamhyung Kim if (thread) 1584aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1585aca7a94dSNamhyung Kim ", Thread: %s(%d)", 1586b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 158738051234SAdrian Hunter thread->tid); 1588aca7a94dSNamhyung Kim if (dso) 1589aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1590aca7a94dSNamhyung Kim ", DSO: %s", dso->short_name); 159184734b06SKan Liang if (socket_id > -1) 159221394d94SKan Liang printed += scnprintf(bf + printed, size - printed, 159384734b06SKan Liang ", Processor Socket: %d", socket_id); 15941e378ebdSTaeung Song if (!is_report_browser(hbt)) { 15951e378ebdSTaeung Song struct perf_top *top = hbt->arg; 15961e378ebdSTaeung Song 15971e378ebdSTaeung Song if (top->zero) 15981e378ebdSTaeung Song printed += scnprintf(bf + printed, size - printed, " [z]"); 15991e378ebdSTaeung Song } 16001e378ebdSTaeung Song 1601aca7a94dSNamhyung Kim return printed; 1602aca7a94dSNamhyung Kim } 1603aca7a94dSNamhyung Kim 1604aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 1605aca7a94dSNamhyung Kim { 1606aca7a94dSNamhyung Kim int i; 1607aca7a94dSNamhyung Kim 160804662523SArnaldo Carvalho de Melo for (i = 0; i < n; ++i) 160904662523SArnaldo Carvalho de Melo zfree(&options[i]); 1610aca7a94dSNamhyung Kim } 1611aca7a94dSNamhyung Kim 1612341487abSFeng Tang /* 1613341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 1614341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 1615341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 1616341487abSFeng Tang */ 1617341487abSFeng Tang static bool is_input_name_malloced = false; 1618341487abSFeng Tang 1619341487abSFeng Tang static int switch_data_file(void) 1620341487abSFeng Tang { 1621341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 1622341487abSFeng Tang DIR *pwd_dir; 1623341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 1624341487abSFeng Tang struct dirent *dent; 1625341487abSFeng Tang 1626341487abSFeng Tang pwd = getenv("PWD"); 1627341487abSFeng Tang if (!pwd) 1628341487abSFeng Tang return ret; 1629341487abSFeng Tang 1630341487abSFeng Tang pwd_dir = opendir(pwd); 1631341487abSFeng Tang if (!pwd_dir) 1632341487abSFeng Tang return ret; 1633341487abSFeng Tang 1634341487abSFeng Tang memset(options, 0, sizeof(options)); 1635341487abSFeng Tang memset(options, 0, sizeof(abs_path)); 1636341487abSFeng Tang 1637341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 1638341487abSFeng Tang char path[PATH_MAX]; 1639341487abSFeng Tang u64 magic; 1640341487abSFeng Tang char *name = dent->d_name; 1641341487abSFeng Tang FILE *file; 1642341487abSFeng Tang 1643341487abSFeng Tang if (!(dent->d_type == DT_REG)) 1644341487abSFeng Tang continue; 1645341487abSFeng Tang 1646341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 1647341487abSFeng Tang 1648341487abSFeng Tang file = fopen(path, "r"); 1649341487abSFeng Tang if (!file) 1650341487abSFeng Tang continue; 1651341487abSFeng Tang 1652341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 1653341487abSFeng Tang goto close_file_and_continue; 1654341487abSFeng Tang 1655341487abSFeng Tang if (is_perf_magic(magic)) { 1656341487abSFeng Tang options[nr_options] = strdup(name); 1657341487abSFeng Tang if (!options[nr_options]) 1658341487abSFeng Tang goto close_file_and_continue; 1659341487abSFeng Tang 1660341487abSFeng Tang abs_path[nr_options] = strdup(path); 1661341487abSFeng Tang if (!abs_path[nr_options]) { 166274cf249dSArnaldo Carvalho de Melo zfree(&options[nr_options]); 1663341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 1664341487abSFeng Tang fclose(file); 1665341487abSFeng Tang break; 1666341487abSFeng Tang } 1667341487abSFeng Tang 1668341487abSFeng Tang nr_options++; 1669341487abSFeng Tang } 1670341487abSFeng Tang 1671341487abSFeng Tang close_file_and_continue: 1672341487abSFeng Tang fclose(file); 1673341487abSFeng Tang if (nr_options >= 32) { 1674341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 1675341487abSFeng Tang "Only the first 32 files will be listed.\n"); 1676341487abSFeng Tang break; 1677341487abSFeng Tang } 1678341487abSFeng Tang } 1679341487abSFeng Tang closedir(pwd_dir); 1680341487abSFeng Tang 1681341487abSFeng Tang if (nr_options) { 1682341487abSFeng Tang choice = ui__popup_menu(nr_options, options); 1683341487abSFeng Tang if (choice < nr_options && choice >= 0) { 1684341487abSFeng Tang tmp = strdup(abs_path[choice]); 1685341487abSFeng Tang if (tmp) { 1686341487abSFeng Tang if (is_input_name_malloced) 1687341487abSFeng Tang free((void *)input_name); 1688341487abSFeng Tang input_name = tmp; 1689341487abSFeng Tang is_input_name_malloced = true; 1690341487abSFeng Tang ret = 0; 1691341487abSFeng Tang } else 1692341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 1693341487abSFeng Tang } 1694341487abSFeng Tang } 1695341487abSFeng Tang 1696341487abSFeng Tang free_popup_options(options, nr_options); 1697341487abSFeng Tang free_popup_options(abs_path, nr_options); 1698341487abSFeng Tang return ret; 1699341487abSFeng Tang } 1700341487abSFeng Tang 1701ea7cd592SNamhyung Kim struct popup_action { 1702ea7cd592SNamhyung Kim struct thread *thread; 1703ea7cd592SNamhyung Kim struct map_symbol ms; 170484734b06SKan Liang int socket; 1705ea7cd592SNamhyung Kim 1706ea7cd592SNamhyung Kim int (*fn)(struct hist_browser *browser, struct popup_action *act); 1707ea7cd592SNamhyung Kim }; 1708ea7cd592SNamhyung Kim 1709bc7cad42SNamhyung Kim static int 1710ea7cd592SNamhyung Kim do_annotate(struct hist_browser *browser, struct popup_action *act) 1711bc7cad42SNamhyung Kim { 1712bc7cad42SNamhyung Kim struct perf_evsel *evsel; 1713bc7cad42SNamhyung Kim struct annotation *notes; 1714bc7cad42SNamhyung Kim struct hist_entry *he; 1715bc7cad42SNamhyung Kim int err; 1716bc7cad42SNamhyung Kim 1717eebd0bfcSArnaldo Carvalho de Melo if (!objdump_path && perf_env__lookup_objdump(browser->env)) 1718bc7cad42SNamhyung Kim return 0; 1719bc7cad42SNamhyung Kim 1720ea7cd592SNamhyung Kim notes = symbol__annotation(act->ms.sym); 1721bc7cad42SNamhyung Kim if (!notes->src) 1722bc7cad42SNamhyung Kim return 0; 1723bc7cad42SNamhyung Kim 1724bc7cad42SNamhyung Kim evsel = hists_to_evsel(browser->hists); 1725ea7cd592SNamhyung Kim err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); 1726bc7cad42SNamhyung Kim he = hist_browser__selected_entry(browser); 1727bc7cad42SNamhyung Kim /* 1728bc7cad42SNamhyung Kim * offer option to annotate the other branch source or target 1729bc7cad42SNamhyung Kim * (if they exists) when returning from annotate 1730bc7cad42SNamhyung Kim */ 1731bc7cad42SNamhyung Kim if ((err == 'q' || err == CTRL('c')) && he->branch_info) 1732bc7cad42SNamhyung Kim return 1; 1733bc7cad42SNamhyung Kim 1734bc7cad42SNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1735bc7cad42SNamhyung Kim if (err) 1736bc7cad42SNamhyung Kim ui_browser__handle_resize(&browser->b); 1737bc7cad42SNamhyung Kim return 0; 1738bc7cad42SNamhyung Kim } 1739bc7cad42SNamhyung Kim 1740bc7cad42SNamhyung Kim static int 1741ea7cd592SNamhyung Kim add_annotate_opt(struct hist_browser *browser __maybe_unused, 1742ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 1743ea7cd592SNamhyung Kim struct map *map, struct symbol *sym) 1744bc7cad42SNamhyung Kim { 1745ea7cd592SNamhyung Kim if (sym == NULL || map->dso->annotate_warned) 1746ea7cd592SNamhyung Kim return 0; 1747ea7cd592SNamhyung Kim 1748ea7cd592SNamhyung Kim if (asprintf(optstr, "Annotate %s", sym->name) < 0) 1749ea7cd592SNamhyung Kim return 0; 1750ea7cd592SNamhyung Kim 1751ea7cd592SNamhyung Kim act->ms.map = map; 1752ea7cd592SNamhyung Kim act->ms.sym = sym; 1753ea7cd592SNamhyung Kim act->fn = do_annotate; 1754ea7cd592SNamhyung Kim return 1; 1755ea7cd592SNamhyung Kim } 1756ea7cd592SNamhyung Kim 1757ea7cd592SNamhyung Kim static int 1758ea7cd592SNamhyung Kim do_zoom_thread(struct hist_browser *browser, struct popup_action *act) 1759ea7cd592SNamhyung Kim { 1760ea7cd592SNamhyung Kim struct thread *thread = act->thread; 1761ea7cd592SNamhyung Kim 1762bc7cad42SNamhyung Kim if (browser->hists->thread_filter) { 1763bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->thread_filter); 1764bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 1765bc7cad42SNamhyung Kim thread__zput(browser->hists->thread_filter); 1766bc7cad42SNamhyung Kim ui_helpline__pop(); 1767bc7cad42SNamhyung Kim } else { 17687727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 1769bc7cad42SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 1770bc7cad42SNamhyung Kim thread->tid); 1771bc7cad42SNamhyung Kim browser->hists->thread_filter = thread__get(thread); 1772bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 1773bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->thread_filter); 1774bc7cad42SNamhyung Kim } 1775bc7cad42SNamhyung Kim 1776bc7cad42SNamhyung Kim hists__filter_by_thread(browser->hists); 1777bc7cad42SNamhyung Kim hist_browser__reset(browser); 1778bc7cad42SNamhyung Kim return 0; 1779bc7cad42SNamhyung Kim } 1780bc7cad42SNamhyung Kim 1781bc7cad42SNamhyung Kim static int 1782ea7cd592SNamhyung Kim add_thread_opt(struct hist_browser *browser, struct popup_action *act, 1783ea7cd592SNamhyung Kim char **optstr, struct thread *thread) 1784bc7cad42SNamhyung Kim { 1785ea7cd592SNamhyung Kim if (thread == NULL) 1786ea7cd592SNamhyung Kim return 0; 1787ea7cd592SNamhyung Kim 1788ea7cd592SNamhyung Kim if (asprintf(optstr, "Zoom %s %s(%d) thread", 1789ea7cd592SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 1790ea7cd592SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 1791ea7cd592SNamhyung Kim thread->tid) < 0) 1792ea7cd592SNamhyung Kim return 0; 1793ea7cd592SNamhyung Kim 1794ea7cd592SNamhyung Kim act->thread = thread; 1795ea7cd592SNamhyung Kim act->fn = do_zoom_thread; 1796ea7cd592SNamhyung Kim return 1; 1797ea7cd592SNamhyung Kim } 1798ea7cd592SNamhyung Kim 1799ea7cd592SNamhyung Kim static int 1800ea7cd592SNamhyung Kim do_zoom_dso(struct hist_browser *browser, struct popup_action *act) 1801ea7cd592SNamhyung Kim { 1802045b80ddSArnaldo Carvalho de Melo struct map *map = act->ms.map; 1803ea7cd592SNamhyung Kim 1804bc7cad42SNamhyung Kim if (browser->hists->dso_filter) { 1805bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->dso_filter); 1806bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, false); 1807bc7cad42SNamhyung Kim browser->hists->dso_filter = NULL; 1808bc7cad42SNamhyung Kim ui_helpline__pop(); 1809bc7cad42SNamhyung Kim } else { 1810045b80ddSArnaldo Carvalho de Melo if (map == NULL) 1811bc7cad42SNamhyung Kim return 0; 18127727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", 1813045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); 1814045b80ddSArnaldo Carvalho de Melo browser->hists->dso_filter = map->dso; 1815bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, true); 1816bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->dso_filter); 1817bc7cad42SNamhyung Kim } 1818bc7cad42SNamhyung Kim 1819bc7cad42SNamhyung Kim hists__filter_by_dso(browser->hists); 1820bc7cad42SNamhyung Kim hist_browser__reset(browser); 1821bc7cad42SNamhyung Kim return 0; 1822bc7cad42SNamhyung Kim } 1823bc7cad42SNamhyung Kim 1824bc7cad42SNamhyung Kim static int 1825ea7cd592SNamhyung Kim add_dso_opt(struct hist_browser *browser, struct popup_action *act, 1826045b80ddSArnaldo Carvalho de Melo char **optstr, struct map *map) 1827bc7cad42SNamhyung Kim { 1828045b80ddSArnaldo Carvalho de Melo if (map == NULL) 1829ea7cd592SNamhyung Kim return 0; 1830ea7cd592SNamhyung Kim 1831ea7cd592SNamhyung Kim if (asprintf(optstr, "Zoom %s %s DSO", 1832ea7cd592SNamhyung Kim browser->hists->dso_filter ? "out of" : "into", 1833045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) 1834ea7cd592SNamhyung Kim return 0; 1835ea7cd592SNamhyung Kim 1836045b80ddSArnaldo Carvalho de Melo act->ms.map = map; 1837ea7cd592SNamhyung Kim act->fn = do_zoom_dso; 1838ea7cd592SNamhyung Kim return 1; 1839ea7cd592SNamhyung Kim } 1840ea7cd592SNamhyung Kim 1841ea7cd592SNamhyung Kim static int 1842ea7cd592SNamhyung Kim do_browse_map(struct hist_browser *browser __maybe_unused, 1843ea7cd592SNamhyung Kim struct popup_action *act) 1844ea7cd592SNamhyung Kim { 1845ea7cd592SNamhyung Kim map__browse(act->ms.map); 1846bc7cad42SNamhyung Kim return 0; 1847bc7cad42SNamhyung Kim } 1848bc7cad42SNamhyung Kim 1849bc7cad42SNamhyung Kim static int 1850ea7cd592SNamhyung Kim add_map_opt(struct hist_browser *browser __maybe_unused, 1851ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, struct map *map) 1852ea7cd592SNamhyung Kim { 1853ea7cd592SNamhyung Kim if (map == NULL) 1854ea7cd592SNamhyung Kim return 0; 1855ea7cd592SNamhyung Kim 1856ea7cd592SNamhyung Kim if (asprintf(optstr, "Browse map details") < 0) 1857ea7cd592SNamhyung Kim return 0; 1858ea7cd592SNamhyung Kim 1859ea7cd592SNamhyung Kim act->ms.map = map; 1860ea7cd592SNamhyung Kim act->fn = do_browse_map; 1861ea7cd592SNamhyung Kim return 1; 1862ea7cd592SNamhyung Kim } 1863ea7cd592SNamhyung Kim 1864ea7cd592SNamhyung Kim static int 1865bc7cad42SNamhyung Kim do_run_script(struct hist_browser *browser __maybe_unused, 1866ea7cd592SNamhyung Kim struct popup_action *act) 1867bc7cad42SNamhyung Kim { 1868bc7cad42SNamhyung Kim char script_opt[64]; 1869bc7cad42SNamhyung Kim memset(script_opt, 0, sizeof(script_opt)); 1870bc7cad42SNamhyung Kim 1871ea7cd592SNamhyung Kim if (act->thread) { 1872bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -c %s ", 1873ea7cd592SNamhyung Kim thread__comm_str(act->thread)); 1874ea7cd592SNamhyung Kim } else if (act->ms.sym) { 1875bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -S %s ", 1876ea7cd592SNamhyung Kim act->ms.sym->name); 1877bc7cad42SNamhyung Kim } 1878bc7cad42SNamhyung Kim 1879bc7cad42SNamhyung Kim script_browse(script_opt); 1880bc7cad42SNamhyung Kim return 0; 1881bc7cad42SNamhyung Kim } 1882bc7cad42SNamhyung Kim 1883bc7cad42SNamhyung Kim static int 1884ea7cd592SNamhyung Kim add_script_opt(struct hist_browser *browser __maybe_unused, 1885ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 1886ea7cd592SNamhyung Kim struct thread *thread, struct symbol *sym) 1887ea7cd592SNamhyung Kim { 1888ea7cd592SNamhyung Kim if (thread) { 1889ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of thread [%s]", 1890ea7cd592SNamhyung Kim thread__comm_str(thread)) < 0) 1891ea7cd592SNamhyung Kim return 0; 1892ea7cd592SNamhyung Kim } else if (sym) { 1893ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of symbol [%s]", 1894ea7cd592SNamhyung Kim sym->name) < 0) 1895ea7cd592SNamhyung Kim return 0; 1896ea7cd592SNamhyung Kim } else { 1897ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for all samples") < 0) 1898ea7cd592SNamhyung Kim return 0; 1899ea7cd592SNamhyung Kim } 1900ea7cd592SNamhyung Kim 1901ea7cd592SNamhyung Kim act->thread = thread; 1902ea7cd592SNamhyung Kim act->ms.sym = sym; 1903ea7cd592SNamhyung Kim act->fn = do_run_script; 1904ea7cd592SNamhyung Kim return 1; 1905ea7cd592SNamhyung Kim } 1906ea7cd592SNamhyung Kim 1907ea7cd592SNamhyung Kim static int 1908ea7cd592SNamhyung Kim do_switch_data(struct hist_browser *browser __maybe_unused, 1909ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 1910bc7cad42SNamhyung Kim { 1911bc7cad42SNamhyung Kim if (switch_data_file()) { 1912bc7cad42SNamhyung Kim ui__warning("Won't switch the data files due to\n" 1913bc7cad42SNamhyung Kim "no valid data file get selected!\n"); 1914ea7cd592SNamhyung Kim return 0; 1915bc7cad42SNamhyung Kim } 1916bc7cad42SNamhyung Kim 1917bc7cad42SNamhyung Kim return K_SWITCH_INPUT_DATA; 1918bc7cad42SNamhyung Kim } 1919bc7cad42SNamhyung Kim 1920ea7cd592SNamhyung Kim static int 1921ea7cd592SNamhyung Kim add_switch_opt(struct hist_browser *browser, 1922ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 1923ea7cd592SNamhyung Kim { 1924ea7cd592SNamhyung Kim if (!is_report_browser(browser->hbt)) 1925ea7cd592SNamhyung Kim return 0; 1926ea7cd592SNamhyung Kim 1927ea7cd592SNamhyung Kim if (asprintf(optstr, "Switch to another data file in PWD") < 0) 1928ea7cd592SNamhyung Kim return 0; 1929ea7cd592SNamhyung Kim 1930ea7cd592SNamhyung Kim act->fn = do_switch_data; 1931ea7cd592SNamhyung Kim return 1; 1932ea7cd592SNamhyung Kim } 1933ea7cd592SNamhyung Kim 1934ea7cd592SNamhyung Kim static int 1935ea7cd592SNamhyung Kim do_exit_browser(struct hist_browser *browser __maybe_unused, 1936ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 1937ea7cd592SNamhyung Kim { 1938ea7cd592SNamhyung Kim return 0; 1939ea7cd592SNamhyung Kim } 1940ea7cd592SNamhyung Kim 1941ea7cd592SNamhyung Kim static int 1942ea7cd592SNamhyung Kim add_exit_opt(struct hist_browser *browser __maybe_unused, 1943ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 1944ea7cd592SNamhyung Kim { 1945ea7cd592SNamhyung Kim if (asprintf(optstr, "Exit") < 0) 1946ea7cd592SNamhyung Kim return 0; 1947ea7cd592SNamhyung Kim 1948ea7cd592SNamhyung Kim act->fn = do_exit_browser; 1949ea7cd592SNamhyung Kim return 1; 1950ea7cd592SNamhyung Kim } 1951ea7cd592SNamhyung Kim 195284734b06SKan Liang static int 195384734b06SKan Liang do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 195484734b06SKan Liang { 195584734b06SKan Liang if (browser->hists->socket_filter > -1) { 195684734b06SKan Liang pstack__remove(browser->pstack, &browser->hists->socket_filter); 195784734b06SKan Liang browser->hists->socket_filter = -1; 195884734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, false); 195984734b06SKan Liang } else { 196084734b06SKan Liang browser->hists->socket_filter = act->socket; 196184734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, true); 196284734b06SKan Liang pstack__push(browser->pstack, &browser->hists->socket_filter); 196384734b06SKan Liang } 196484734b06SKan Liang 196584734b06SKan Liang hists__filter_by_socket(browser->hists); 196684734b06SKan Liang hist_browser__reset(browser); 196784734b06SKan Liang return 0; 196884734b06SKan Liang } 196984734b06SKan Liang 197084734b06SKan Liang static int 197184734b06SKan Liang add_socket_opt(struct hist_browser *browser, struct popup_action *act, 197284734b06SKan Liang char **optstr, int socket_id) 197384734b06SKan Liang { 197484734b06SKan Liang if (socket_id < 0) 197584734b06SKan Liang return 0; 197684734b06SKan Liang 197784734b06SKan Liang if (asprintf(optstr, "Zoom %s Processor Socket %d", 197884734b06SKan Liang (browser->hists->socket_filter > -1) ? "out of" : "into", 197984734b06SKan Liang socket_id) < 0) 198084734b06SKan Liang return 0; 198184734b06SKan Liang 198284734b06SKan Liang act->socket = socket_id; 198384734b06SKan Liang act->fn = do_zoom_socket; 198484734b06SKan Liang return 1; 198584734b06SKan Liang } 198684734b06SKan Liang 1987112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb) 1988064f1981SNamhyung Kim { 1989064f1981SNamhyung Kim u64 nr_entries = 0; 1990064f1981SNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 1991064f1981SNamhyung Kim 1992268397cbSNamhyung Kim if (hb->min_pcnt == 0) { 1993268397cbSNamhyung Kim hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 1994268397cbSNamhyung Kim return; 1995268397cbSNamhyung Kim } 1996268397cbSNamhyung Kim 199714135663SNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 1998064f1981SNamhyung Kim nr_entries++; 1999c481f930SNamhyung Kim nd = rb_next(nd); 2000064f1981SNamhyung Kim } 2001064f1981SNamhyung Kim 2002112f761fSNamhyung Kim hb->nr_non_filtered_entries = nr_entries; 2003064f1981SNamhyung Kim } 2004341487abSFeng Tang 2005aca7a94dSNamhyung Kim static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 2006dd00d486SJiri Olsa const char *helpline, 2007aca7a94dSNamhyung Kim bool left_exits, 200868d80758SNamhyung Kim struct hist_browser_timer *hbt, 2009064f1981SNamhyung Kim float min_pcnt, 2010ce80d3beSKan Liang struct perf_env *env) 2011aca7a94dSNamhyung Kim { 20124ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 2013b1a9ceefSNamhyung Kim struct hist_browser *browser = hist_browser__new(hists, hbt, env); 2014aca7a94dSNamhyung Kim struct branch_info *bi; 2015f2b487dbSNamhyung Kim #define MAX_OPTIONS 16 2016f2b487dbSNamhyung Kim char *options[MAX_OPTIONS]; 2017ea7cd592SNamhyung Kim struct popup_action actions[MAX_OPTIONS]; 2018aca7a94dSNamhyung Kim int nr_options = 0; 2019aca7a94dSNamhyung Kim int key = -1; 2020aca7a94dSNamhyung Kim char buf[64]; 20219783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 202259dc9f25SNamhyung Kim struct perf_hpp_fmt *fmt; 2023aca7a94dSNamhyung Kim 2024e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 2025e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 2026e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 2027e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 2028e8e684a5SNamhyung Kim "q/ESC/CTRL+C Exit browser\n\n" \ 2029e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 2030e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 2031e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 20327727a925SArnaldo Carvalho de Melo "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \ 20337727a925SArnaldo Carvalho de Melo "ESC Zoom out\n" \ 2034e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 2035e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 2036e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 2037e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 2038105eb30fSNamhyung Kim "F Toggle percentage of filtered entries\n" \ 2039025bf7eaSArnaldo Carvalho de Melo "H Display column headers\n" \ 204031eb4360SNamhyung Kim "m Display context menu\n" \ 204184734b06SKan Liang "S Zoom into current Processor Socket\n" \ 2042e8e684a5SNamhyung Kim 2043e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 2044e8e684a5SNamhyung Kim const char report_help[] = HIST_BROWSER_HELP_COMMON 20456dd60135SNamhyung Kim "i Show header information\n" 2046e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2047e8e684a5SNamhyung Kim "r Run available scripts\n" 2048e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 2049e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2050e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 2051e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2052e8e684a5SNamhyung Kim const char top_help[] = HIST_BROWSER_HELP_COMMON 2053e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2054e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2055e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 205642337a22SNamhyung Kim "z Toggle zeroing of samples\n" 2057fbb7997eSArnaldo Carvalho de Melo "f Enable/Disable events\n" 2058e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2059e8e684a5SNamhyung Kim 2060aca7a94dSNamhyung Kim if (browser == NULL) 2061aca7a94dSNamhyung Kim return -1; 2062aca7a94dSNamhyung Kim 2063ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 2064ed426915SNamhyung Kim SLang_reset_tty(); 2065ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 2066ed426915SNamhyung Kim 206703905048SNamhyung Kim if (min_pcnt) 2068064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 2069112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 2070064f1981SNamhyung Kim 207184734b06SKan Liang browser->pstack = pstack__new(3); 207201f00a1cSNamhyung Kim if (browser->pstack == NULL) 2073aca7a94dSNamhyung Kim goto out; 2074aca7a94dSNamhyung Kim 2075aca7a94dSNamhyung Kim ui_helpline__push(helpline); 2076aca7a94dSNamhyung Kim 2077aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 2078ea7cd592SNamhyung Kim memset(actions, 0, sizeof(actions)); 2079aca7a94dSNamhyung Kim 2080c6c3c02dSArnaldo Carvalho de Melo perf_hpp__for_each_format(fmt) { 208159dc9f25SNamhyung Kim perf_hpp__reset_width(fmt, hists); 2082c6c3c02dSArnaldo Carvalho de Melo /* 2083c6c3c02dSArnaldo Carvalho de Melo * This is done just once, and activates the horizontal scrolling 2084c6c3c02dSArnaldo Carvalho de Melo * code in the ui_browser code, it would be better to have a the 2085c6c3c02dSArnaldo Carvalho de Melo * counter in the perf_hpp code, but I couldn't find doing it here 2086c6c3c02dSArnaldo Carvalho de Melo * works, FIXME by setting this in hist_browser__new, for now, be 2087c6c3c02dSArnaldo Carvalho de Melo * clever 8-) 2088c6c3c02dSArnaldo Carvalho de Melo */ 2089c6c3c02dSArnaldo Carvalho de Melo ++browser->b.columns; 2090c6c3c02dSArnaldo Carvalho de Melo } 209159dc9f25SNamhyung Kim 20925b591669SNamhyung Kim if (symbol_conf.col_width_list_str) 20935b591669SNamhyung Kim perf_hpp__set_user_width(symbol_conf.col_width_list_str); 20945b591669SNamhyung Kim 2095aca7a94dSNamhyung Kim while (1) { 2096f3b623b8SArnaldo Carvalho de Melo struct thread *thread = NULL; 2097045b80ddSArnaldo Carvalho de Melo struct map *map = NULL; 2098ea7cd592SNamhyung Kim int choice = 0; 209984734b06SKan Liang int socked_id = -1; 2100aca7a94dSNamhyung Kim 2101aca7a94dSNamhyung Kim nr_options = 0; 2102aca7a94dSNamhyung Kim 21035f00b0f4SArnaldo Carvalho de Melo key = hist_browser__run(browser, helpline); 2104aca7a94dSNamhyung Kim 2105aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 2106aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 2107045b80ddSArnaldo Carvalho de Melo map = browser->selection->map; 210884734b06SKan Liang socked_id = browser->he_selection->socket; 2109aca7a94dSNamhyung Kim } 2110aca7a94dSNamhyung Kim switch (key) { 2111aca7a94dSNamhyung Kim case K_TAB: 2112aca7a94dSNamhyung Kim case K_UNTAB: 2113aca7a94dSNamhyung Kim if (nr_events == 1) 2114aca7a94dSNamhyung Kim continue; 2115aca7a94dSNamhyung Kim /* 2116aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 2117aca7a94dSNamhyung Kim * go to the next or previous 2118aca7a94dSNamhyung Kim */ 2119aca7a94dSNamhyung Kim goto out_free_stack; 2120aca7a94dSNamhyung Kim case 'a': 21219c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) { 2122aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 2123aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 2124aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 2125aca7a94dSNamhyung Kim continue; 2126aca7a94dSNamhyung Kim } 2127aca7a94dSNamhyung Kim 2128aca7a94dSNamhyung Kim if (browser->selection == NULL || 2129aca7a94dSNamhyung Kim browser->selection->sym == NULL || 2130aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 2131aca7a94dSNamhyung Kim continue; 2132bc7cad42SNamhyung Kim 2133ea7cd592SNamhyung Kim actions->ms.map = browser->selection->map; 2134ea7cd592SNamhyung Kim actions->ms.sym = browser->selection->sym; 2135ea7cd592SNamhyung Kim do_annotate(browser, actions); 2136bc7cad42SNamhyung Kim continue; 2137aff3f3f6SArnaldo Carvalho de Melo case 'P': 2138aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 2139aff3f3f6SArnaldo Carvalho de Melo continue; 2140aca7a94dSNamhyung Kim case 'd': 2141fae00650SArnaldo Carvalho de Melo actions->ms.map = map; 2142ea7cd592SNamhyung Kim do_zoom_dso(browser, actions); 2143bc7cad42SNamhyung Kim continue; 2144a7cb8863SArnaldo Carvalho de Melo case 'V': 2145a7cb8863SArnaldo Carvalho de Melo browser->show_dso = !browser->show_dso; 2146a7cb8863SArnaldo Carvalho de Melo continue; 2147aca7a94dSNamhyung Kim case 't': 2148ea7cd592SNamhyung Kim actions->thread = thread; 2149ea7cd592SNamhyung Kim do_zoom_thread(browser, actions); 2150bc7cad42SNamhyung Kim continue; 215184734b06SKan Liang case 'S': 215284734b06SKan Liang actions->socket = socked_id; 215384734b06SKan Liang do_zoom_socket(browser, actions); 215484734b06SKan Liang continue; 21555a5626b1SArnaldo Carvalho de Melo case '/': 2156aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 21574aa8e454SArnaldo Carvalho de Melo "Please enter the name of symbol you want to see.\n" 21584aa8e454SArnaldo Carvalho de Melo "To remove the filter later, press / + ENTER.", 2159aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 2160aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 216105e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 216205e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 2163aca7a94dSNamhyung Kim hist_browser__reset(browser); 2164aca7a94dSNamhyung Kim } 2165aca7a94dSNamhyung Kim continue; 2166cdbab7c2SFeng Tang case 'r': 2167ea7cd592SNamhyung Kim if (is_report_browser(hbt)) { 2168ea7cd592SNamhyung Kim actions->thread = NULL; 2169ea7cd592SNamhyung Kim actions->ms.sym = NULL; 2170ea7cd592SNamhyung Kim do_run_script(browser, actions); 2171ea7cd592SNamhyung Kim } 2172c77d8d70SFeng Tang continue; 2173341487abSFeng Tang case 's': 2174bc7cad42SNamhyung Kim if (is_report_browser(hbt)) { 2175ea7cd592SNamhyung Kim key = do_switch_data(browser, actions); 2176bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 2177bc7cad42SNamhyung Kim goto out_free_stack; 2178bc7cad42SNamhyung Kim } 2179341487abSFeng Tang continue; 21806dd60135SNamhyung Kim case 'i': 21816dd60135SNamhyung Kim /* env->arch is NULL for live-mode (i.e. perf top) */ 21826dd60135SNamhyung Kim if (env->arch) 21836dd60135SNamhyung Kim tui__header_window(env); 21846dd60135SNamhyung Kim continue; 2185105eb30fSNamhyung Kim case 'F': 2186105eb30fSNamhyung Kim symbol_conf.filter_relative ^= 1; 2187105eb30fSNamhyung Kim continue; 218842337a22SNamhyung Kim case 'z': 218942337a22SNamhyung Kim if (!is_report_browser(hbt)) { 219042337a22SNamhyung Kim struct perf_top *top = hbt->arg; 219142337a22SNamhyung Kim 219242337a22SNamhyung Kim top->zero = !top->zero; 219342337a22SNamhyung Kim } 219442337a22SNamhyung Kim continue; 2195aca7a94dSNamhyung Kim case K_F1: 2196aca7a94dSNamhyung Kim case 'h': 2197aca7a94dSNamhyung Kim case '?': 2198aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 2199e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 2200aca7a94dSNamhyung Kim continue; 2201aca7a94dSNamhyung Kim case K_ENTER: 2202aca7a94dSNamhyung Kim case K_RIGHT: 220331eb4360SNamhyung Kim case 'm': 2204aca7a94dSNamhyung Kim /* menu */ 2205aca7a94dSNamhyung Kim break; 220663ab1749SArnaldo Carvalho de Melo case K_ESC: 2207aca7a94dSNamhyung Kim case K_LEFT: { 2208aca7a94dSNamhyung Kim const void *top; 2209aca7a94dSNamhyung Kim 221001f00a1cSNamhyung Kim if (pstack__empty(browser->pstack)) { 2211aca7a94dSNamhyung Kim /* 2212aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 2213aca7a94dSNamhyung Kim */ 2214aca7a94dSNamhyung Kim if (left_exits) 2215aca7a94dSNamhyung Kim goto out_free_stack; 221663ab1749SArnaldo Carvalho de Melo 221763ab1749SArnaldo Carvalho de Melo if (key == K_ESC && 221863ab1749SArnaldo Carvalho de Melo ui_browser__dialog_yesno(&browser->b, 221963ab1749SArnaldo Carvalho de Melo "Do you really want to exit?")) 222063ab1749SArnaldo Carvalho de Melo goto out_free_stack; 222163ab1749SArnaldo Carvalho de Melo 2222aca7a94dSNamhyung Kim continue; 2223aca7a94dSNamhyung Kim } 22246422184bSNamhyung Kim top = pstack__peek(browser->pstack); 2225bc7cad42SNamhyung Kim if (top == &browser->hists->dso_filter) { 22266422184bSNamhyung Kim /* 22276422184bSNamhyung Kim * No need to set actions->dso here since 22286422184bSNamhyung Kim * it's just to remove the current filter. 22296422184bSNamhyung Kim * Ditto for thread below. 22306422184bSNamhyung Kim */ 22316422184bSNamhyung Kim do_zoom_dso(browser, actions); 223284734b06SKan Liang } else if (top == &browser->hists->thread_filter) { 22336422184bSNamhyung Kim do_zoom_thread(browser, actions); 223484734b06SKan Liang } else if (top == &browser->hists->socket_filter) { 223584734b06SKan Liang do_zoom_socket(browser, actions); 223684734b06SKan Liang } 2237aca7a94dSNamhyung Kim continue; 2238aca7a94dSNamhyung Kim } 2239aca7a94dSNamhyung Kim case 'q': 2240aca7a94dSNamhyung Kim case CTRL('c'): 2241516e5368SArnaldo Carvalho de Melo goto out_free_stack; 2242fbb7997eSArnaldo Carvalho de Melo case 'f': 224313d1e536SNamhyung Kim if (!is_report_browser(hbt)) { 224413d1e536SNamhyung Kim struct perf_top *top = hbt->arg; 224513d1e536SNamhyung Kim 224613d1e536SNamhyung Kim perf_evlist__toggle_enable(top->evlist); 224713d1e536SNamhyung Kim /* 224813d1e536SNamhyung Kim * No need to refresh, resort/decay histogram 224913d1e536SNamhyung Kim * entries if we are not collecting samples: 225013d1e536SNamhyung Kim */ 225113d1e536SNamhyung Kim if (top->evlist->enabled) { 225213d1e536SNamhyung Kim helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; 225313d1e536SNamhyung Kim hbt->refresh = delay_secs; 225413d1e536SNamhyung Kim } else { 225513d1e536SNamhyung Kim helpline = "Press 'f' again to re-enable the events"; 225613d1e536SNamhyung Kim hbt->refresh = 0; 225713d1e536SNamhyung Kim } 225813d1e536SNamhyung Kim continue; 225913d1e536SNamhyung Kim } 22603e323dc0SArnaldo Carvalho de Melo /* Fall thru */ 2261aca7a94dSNamhyung Kim default: 22623e323dc0SArnaldo Carvalho de Melo helpline = "Press '?' for help on key bindings"; 2263aca7a94dSNamhyung Kim continue; 2264aca7a94dSNamhyung Kim } 2265aca7a94dSNamhyung Kim 22669c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) 2267aca7a94dSNamhyung Kim goto add_exit_option; 2268aca7a94dSNamhyung Kim 22690ba332f7SArnaldo Carvalho de Melo if (browser->selection == NULL) 22700ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 22710ba332f7SArnaldo Carvalho de Melo 227255369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 2273aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 22740ba332f7SArnaldo Carvalho de Melo 22750ba332f7SArnaldo Carvalho de Melo if (bi == NULL) 22760ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 22770ba332f7SArnaldo Carvalho de Melo 2278ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2279ea7cd592SNamhyung Kim &actions[nr_options], 2280ea7cd592SNamhyung Kim &options[nr_options], 2281ea7cd592SNamhyung Kim bi->from.map, 2282ea7cd592SNamhyung Kim bi->from.sym); 2283ea7cd592SNamhyung Kim if (bi->to.sym != bi->from.sym) 2284ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2285ea7cd592SNamhyung Kim &actions[nr_options], 2286ea7cd592SNamhyung Kim &options[nr_options], 2287ea7cd592SNamhyung Kim bi->to.map, 2288ea7cd592SNamhyung Kim bi->to.sym); 2289aca7a94dSNamhyung Kim } else { 2290ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2291ea7cd592SNamhyung Kim &actions[nr_options], 2292ea7cd592SNamhyung Kim &options[nr_options], 2293ea7cd592SNamhyung Kim browser->selection->map, 2294ea7cd592SNamhyung Kim browser->selection->sym); 2295446fb96cSArnaldo Carvalho de Melo } 22960ba332f7SArnaldo Carvalho de Melo skip_annotation: 2297ea7cd592SNamhyung Kim nr_options += add_thread_opt(browser, &actions[nr_options], 2298ea7cd592SNamhyung Kim &options[nr_options], thread); 2299ea7cd592SNamhyung Kim nr_options += add_dso_opt(browser, &actions[nr_options], 2300045b80ddSArnaldo Carvalho de Melo &options[nr_options], map); 2301ea7cd592SNamhyung Kim nr_options += add_map_opt(browser, &actions[nr_options], 2302ea7cd592SNamhyung Kim &options[nr_options], 2303bd315aabSWang Nan browser->selection ? 2304bd315aabSWang Nan browser->selection->map : NULL); 230584734b06SKan Liang nr_options += add_socket_opt(browser, &actions[nr_options], 230684734b06SKan Liang &options[nr_options], 230784734b06SKan Liang socked_id); 2308cdbab7c2SFeng Tang /* perf script support */ 2309cdbab7c2SFeng Tang if (browser->he_selection) { 2310ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 2311ea7cd592SNamhyung Kim &actions[nr_options], 2312ea7cd592SNamhyung Kim &options[nr_options], 2313ea7cd592SNamhyung Kim thread, NULL); 2314bd315aabSWang Nan /* 2315bd315aabSWang Nan * Note that browser->selection != NULL 2316bd315aabSWang Nan * when browser->he_selection is not NULL, 2317bd315aabSWang Nan * so we don't need to check browser->selection 2318bd315aabSWang Nan * before fetching browser->selection->sym like what 2319bd315aabSWang Nan * we do before fetching browser->selection->map. 2320bd315aabSWang Nan * 2321bd315aabSWang Nan * See hist_browser__show_entry. 2322bd315aabSWang Nan */ 2323ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 2324ea7cd592SNamhyung Kim &actions[nr_options], 2325ea7cd592SNamhyung Kim &options[nr_options], 2326ea7cd592SNamhyung Kim NULL, browser->selection->sym); 2327cdbab7c2SFeng Tang } 2328ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, &actions[nr_options], 2329ea7cd592SNamhyung Kim &options[nr_options], NULL, NULL); 2330ea7cd592SNamhyung Kim nr_options += add_switch_opt(browser, &actions[nr_options], 2331ea7cd592SNamhyung Kim &options[nr_options]); 2332aca7a94dSNamhyung Kim add_exit_option: 2333ea7cd592SNamhyung Kim nr_options += add_exit_opt(browser, &actions[nr_options], 2334ea7cd592SNamhyung Kim &options[nr_options]); 2335aca7a94dSNamhyung Kim 2336ea7cd592SNamhyung Kim do { 2337ea7cd592SNamhyung Kim struct popup_action *act; 2338ea7cd592SNamhyung Kim 2339ea7cd592SNamhyung Kim choice = ui__popup_menu(nr_options, options); 2340ea7cd592SNamhyung Kim if (choice == -1 || choice >= nr_options) 2341aca7a94dSNamhyung Kim break; 2342aca7a94dSNamhyung Kim 2343ea7cd592SNamhyung Kim act = &actions[choice]; 2344ea7cd592SNamhyung Kim key = act->fn(browser, act); 2345ea7cd592SNamhyung Kim } while (key == 1); 2346aca7a94dSNamhyung Kim 2347bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 2348341487abSFeng Tang break; 2349341487abSFeng Tang } 2350aca7a94dSNamhyung Kim out_free_stack: 235101f00a1cSNamhyung Kim pstack__delete(browser->pstack); 2352aca7a94dSNamhyung Kim out: 2353aca7a94dSNamhyung Kim hist_browser__delete(browser); 2354f2b487dbSNamhyung Kim free_popup_options(options, MAX_OPTIONS); 2355aca7a94dSNamhyung Kim return key; 2356aca7a94dSNamhyung Kim } 2357aca7a94dSNamhyung Kim 2358aca7a94dSNamhyung Kim struct perf_evsel_menu { 2359aca7a94dSNamhyung Kim struct ui_browser b; 2360aca7a94dSNamhyung Kim struct perf_evsel *selection; 2361aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 2362064f1981SNamhyung Kim float min_pcnt; 2363ce80d3beSKan Liang struct perf_env *env; 2364aca7a94dSNamhyung Kim }; 2365aca7a94dSNamhyung Kim 2366aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 2367aca7a94dSNamhyung Kim void *entry, int row) 2368aca7a94dSNamhyung Kim { 2369aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 2370aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 2371aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 23724ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 2373aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 23744ea062edSArnaldo Carvalho de Melo unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 23757289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 2376aca7a94dSNamhyung Kim char bf[256], unit; 2377aca7a94dSNamhyung Kim const char *warn = " "; 2378aca7a94dSNamhyung Kim size_t printed; 2379aca7a94dSNamhyung Kim 2380aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 2381aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 2382aca7a94dSNamhyung Kim 2383759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 2384717e263fSNamhyung Kim struct perf_evsel *pos; 2385717e263fSNamhyung Kim 2386717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 2387717e263fSNamhyung Kim 2388717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 23894ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 23904ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 2391717e263fSNamhyung Kim } 2392717e263fSNamhyung Kim } 2393717e263fSNamhyung Kim 2394aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 2395aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 2396aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 2397517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%s", bf); 2398aca7a94dSNamhyung Kim 23994ea062edSArnaldo Carvalho de Melo nr_events = hists->stats.nr_events[PERF_RECORD_LOST]; 2400aca7a94dSNamhyung Kim if (nr_events != 0) { 2401aca7a94dSNamhyung Kim menu->lost_events = true; 2402aca7a94dSNamhyung Kim if (!current_entry) 2403aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 2404aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 2405aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 2406aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 2407aca7a94dSNamhyung Kim warn = bf; 2408aca7a94dSNamhyung Kim } 2409aca7a94dSNamhyung Kim 241026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, warn, browser->width - printed); 2411aca7a94dSNamhyung Kim 2412aca7a94dSNamhyung Kim if (current_entry) 2413aca7a94dSNamhyung Kim menu->selection = evsel; 2414aca7a94dSNamhyung Kim } 2415aca7a94dSNamhyung Kim 2416aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 2417aca7a94dSNamhyung Kim int nr_events, const char *help, 24189783adf7SNamhyung Kim struct hist_browser_timer *hbt) 2419aca7a94dSNamhyung Kim { 2420aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 2421aca7a94dSNamhyung Kim struct perf_evsel *pos; 2422dd00d486SJiri Olsa const char *title = "Available samples"; 24239783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 2424aca7a94dSNamhyung Kim int key; 2425aca7a94dSNamhyung Kim 2426aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 2427aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 2428aca7a94dSNamhyung Kim return -1; 2429aca7a94dSNamhyung Kim 2430aca7a94dSNamhyung Kim while (1) { 2431aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 2432aca7a94dSNamhyung Kim 2433aca7a94dSNamhyung Kim switch (key) { 2434aca7a94dSNamhyung Kim case K_TIMER: 24359783adf7SNamhyung Kim hbt->timer(hbt->arg); 2436aca7a94dSNamhyung Kim 2437aca7a94dSNamhyung Kim if (!menu->lost_events_warned && menu->lost_events) { 2438aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 2439aca7a94dSNamhyung Kim menu->lost_events_warned = true; 2440aca7a94dSNamhyung Kim } 2441aca7a94dSNamhyung Kim continue; 2442aca7a94dSNamhyung Kim case K_RIGHT: 2443aca7a94dSNamhyung Kim case K_ENTER: 2444aca7a94dSNamhyung Kim if (!menu->selection) 2445aca7a94dSNamhyung Kim continue; 2446aca7a94dSNamhyung Kim pos = menu->selection; 2447aca7a94dSNamhyung Kim browse_hists: 2448aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 2449aca7a94dSNamhyung Kim /* 2450aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 2451aca7a94dSNamhyung Kim * default evsel resorted hists tree. 2452aca7a94dSNamhyung Kim */ 24539783adf7SNamhyung Kim if (hbt) 24549783adf7SNamhyung Kim hbt->timer(hbt->arg); 2455aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 2456dd00d486SJiri Olsa true, hbt, 2457064f1981SNamhyung Kim menu->min_pcnt, 245868d80758SNamhyung Kim menu->env); 2459aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 2460aca7a94dSNamhyung Kim switch (key) { 2461aca7a94dSNamhyung Kim case K_TAB: 2462aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 24639a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__first(evlist); 2464aca7a94dSNamhyung Kim else 24659a354cdcSArnaldo Carvalho de Melo pos = perf_evsel__next(pos); 2466aca7a94dSNamhyung Kim goto browse_hists; 2467aca7a94dSNamhyung Kim case K_UNTAB: 2468aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 24699a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__last(evlist); 2470aca7a94dSNamhyung Kim else 2471d87fcb4aSArnaldo Carvalho de Melo pos = perf_evsel__prev(pos); 2472aca7a94dSNamhyung Kim goto browse_hists; 2473341487abSFeng Tang case K_SWITCH_INPUT_DATA: 2474aca7a94dSNamhyung Kim case 'q': 2475aca7a94dSNamhyung Kim case CTRL('c'): 2476aca7a94dSNamhyung Kim goto out; 247763ab1749SArnaldo Carvalho de Melo case K_ESC: 2478aca7a94dSNamhyung Kim default: 2479aca7a94dSNamhyung Kim continue; 2480aca7a94dSNamhyung Kim } 2481aca7a94dSNamhyung Kim case K_LEFT: 2482aca7a94dSNamhyung Kim continue; 2483aca7a94dSNamhyung Kim case K_ESC: 2484aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 2485aca7a94dSNamhyung Kim "Do you really want to exit?")) 2486aca7a94dSNamhyung Kim continue; 2487aca7a94dSNamhyung Kim /* Fall thru */ 2488aca7a94dSNamhyung Kim case 'q': 2489aca7a94dSNamhyung Kim case CTRL('c'): 2490aca7a94dSNamhyung Kim goto out; 2491aca7a94dSNamhyung Kim default: 2492aca7a94dSNamhyung Kim continue; 2493aca7a94dSNamhyung Kim } 2494aca7a94dSNamhyung Kim } 2495aca7a94dSNamhyung Kim 2496aca7a94dSNamhyung Kim out: 2497aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 2498aca7a94dSNamhyung Kim return key; 2499aca7a94dSNamhyung Kim } 2500aca7a94dSNamhyung Kim 2501316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 2502fc24d7c2SNamhyung Kim void *entry) 2503fc24d7c2SNamhyung Kim { 2504fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 2505fc24d7c2SNamhyung Kim 2506fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 2507fc24d7c2SNamhyung Kim return true; 2508fc24d7c2SNamhyung Kim 2509fc24d7c2SNamhyung Kim return false; 2510fc24d7c2SNamhyung Kim } 2511fc24d7c2SNamhyung Kim 2512aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 2513fc24d7c2SNamhyung Kim int nr_entries, const char *help, 251468d80758SNamhyung Kim struct hist_browser_timer *hbt, 2515064f1981SNamhyung Kim float min_pcnt, 2516ce80d3beSKan Liang struct perf_env *env) 2517aca7a94dSNamhyung Kim { 2518aca7a94dSNamhyung Kim struct perf_evsel *pos; 2519aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 2520aca7a94dSNamhyung Kim .b = { 2521aca7a94dSNamhyung Kim .entries = &evlist->entries, 2522aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 2523aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 2524aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 2525fc24d7c2SNamhyung Kim .filter = filter_group_entries, 2526fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 2527aca7a94dSNamhyung Kim .priv = evlist, 2528aca7a94dSNamhyung Kim }, 2529064f1981SNamhyung Kim .min_pcnt = min_pcnt, 253068d80758SNamhyung Kim .env = env, 2531aca7a94dSNamhyung Kim }; 2532aca7a94dSNamhyung Kim 2533aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 2534aca7a94dSNamhyung Kim 25350050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 25367289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 2537aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 2538aca7a94dSNamhyung Kim 2539aca7a94dSNamhyung Kim if (menu.b.width < line_len) 2540aca7a94dSNamhyung Kim menu.b.width = line_len; 2541aca7a94dSNamhyung Kim } 2542aca7a94dSNamhyung Kim 2543fc24d7c2SNamhyung Kim return perf_evsel_menu__run(&menu, nr_entries, help, hbt); 2544aca7a94dSNamhyung Kim } 2545aca7a94dSNamhyung Kim 2546aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 254768d80758SNamhyung Kim struct hist_browser_timer *hbt, 2548064f1981SNamhyung Kim float min_pcnt, 2549ce80d3beSKan Liang struct perf_env *env) 2550aca7a94dSNamhyung Kim { 2551fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 2552fc24d7c2SNamhyung Kim 2553fc24d7c2SNamhyung Kim single_entry: 2554fc24d7c2SNamhyung Kim if (nr_entries == 1) { 25559a354cdcSArnaldo Carvalho de Melo struct perf_evsel *first = perf_evlist__first(evlist); 2556fc24d7c2SNamhyung Kim 2557fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 2558dd00d486SJiri Olsa false, hbt, min_pcnt, 2559064f1981SNamhyung Kim env); 2560aca7a94dSNamhyung Kim } 2561aca7a94dSNamhyung Kim 2562fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 2563fc24d7c2SNamhyung Kim struct perf_evsel *pos; 2564fc24d7c2SNamhyung Kim 2565fc24d7c2SNamhyung Kim nr_entries = 0; 25660050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 2567fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 2568fc24d7c2SNamhyung Kim nr_entries++; 25690050f7aaSArnaldo Carvalho de Melo } 2570fc24d7c2SNamhyung Kim 2571fc24d7c2SNamhyung Kim if (nr_entries == 1) 2572fc24d7c2SNamhyung Kim goto single_entry; 2573fc24d7c2SNamhyung Kim } 2574fc24d7c2SNamhyung Kim 2575fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 2576064f1981SNamhyung Kim hbt, min_pcnt, env); 2577aca7a94dSNamhyung Kim } 2578