1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 276b31a29SArnaldo Carvalho de Melo #include <dirent.h> 3a43783aeSArnaldo Carvalho de Melo #include <errno.h> 4fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 5aca7a94dSNamhyung Kim #include <stdio.h> 6aca7a94dSNamhyung Kim #include <stdlib.h> 7aca7a94dSNamhyung Kim #include <string.h> 8aca7a94dSNamhyung Kim #include <linux/rbtree.h> 9b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h> 10aca7a94dSNamhyung Kim 11aca7a94dSNamhyung Kim #include "../../util/evsel.h" 12aca7a94dSNamhyung Kim #include "../../util/evlist.h" 13aca7a94dSNamhyung Kim #include "../../util/hist.h" 14aca7a94dSNamhyung Kim #include "../../util/pstack.h" 15aca7a94dSNamhyung Kim #include "../../util/sort.h" 16aca7a94dSNamhyung Kim #include "../../util/util.h" 1742337a22SNamhyung Kim #include "../../util/top.h" 18e7ff8920SArnaldo Carvalho de Melo #include "../../util/thread.h" 1968d80758SNamhyung Kim #include "../../arch/common.h" 20aca7a94dSNamhyung Kim 21f758990fSJiri Olsa #include "../browsers/hists.h" 22aca7a94dSNamhyung Kim #include "../helpline.h" 23aca7a94dSNamhyung Kim #include "../util.h" 24aca7a94dSNamhyung Kim #include "../ui.h" 25aca7a94dSNamhyung Kim #include "map.h" 26d755330cSJiri Olsa #include "annotate.h" 27632a5cabSArnaldo Carvalho de Melo #include "srcline.h" 28a067558eSArnaldo Carvalho de Melo #include "string2.h" 2958db1d6eSArnaldo Carvalho de Melo #include "units.h" 30aca7a94dSNamhyung Kim 313d689ed6SArnaldo Carvalho de Melo #include "sane_ctype.h" 323d689ed6SArnaldo Carvalho de Melo 33f5951d56SNamhyung Kim extern void hist_browser__init_hpp(void); 34f5951d56SNamhyung Kim 355b91a86fSJiri Olsa static int perf_evsel_browser_title(struct hist_browser *browser, 361e378ebdSTaeung Song char *bf, size_t size); 37112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb); 38aca7a94dSNamhyung Kim 39c3b78952SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 40c3b78952SNamhyung Kim float min_pcnt); 41c3b78952SNamhyung Kim 42268397cbSNamhyung Kim static bool hist_browser__has_filter(struct hist_browser *hb) 43268397cbSNamhyung Kim { 445a1a99cdSJiri Olsa return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter; 45268397cbSNamhyung Kim } 46268397cbSNamhyung Kim 474fabf3d1SHe Kuang static int hist_browser__get_folding(struct hist_browser *browser) 484fabf3d1SHe Kuang { 494fabf3d1SHe Kuang struct rb_node *nd; 504fabf3d1SHe Kuang struct hists *hists = browser->hists; 514fabf3d1SHe Kuang int unfolded_rows = 0; 524fabf3d1SHe Kuang 534fabf3d1SHe Kuang for (nd = rb_first(&hists->entries); 544fabf3d1SHe Kuang (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 55f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd)) { 564fabf3d1SHe Kuang struct hist_entry *he = 574fabf3d1SHe Kuang rb_entry(nd, struct hist_entry, rb_node); 584fabf3d1SHe Kuang 59f5b763feSNamhyung Kim if (he->leaf && he->unfolded) 604fabf3d1SHe Kuang unfolded_rows += he->nr_rows; 614fabf3d1SHe Kuang } 624fabf3d1SHe Kuang return unfolded_rows; 634fabf3d1SHe Kuang } 644fabf3d1SHe Kuang 65c3b78952SNamhyung Kim static u32 hist_browser__nr_entries(struct hist_browser *hb) 66c3b78952SNamhyung Kim { 67c3b78952SNamhyung Kim u32 nr_entries; 68c3b78952SNamhyung Kim 69f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 70f5b763feSNamhyung Kim nr_entries = hb->nr_hierarchy_entries; 71f5b763feSNamhyung Kim else if (hist_browser__has_filter(hb)) 72c3b78952SNamhyung Kim nr_entries = hb->nr_non_filtered_entries; 73c3b78952SNamhyung Kim else 74c3b78952SNamhyung Kim nr_entries = hb->hists->nr_entries; 75c3b78952SNamhyung Kim 764fabf3d1SHe Kuang hb->nr_callchain_rows = hist_browser__get_folding(hb); 77c3b78952SNamhyung Kim return nr_entries + hb->nr_callchain_rows; 78c3b78952SNamhyung Kim } 79c3b78952SNamhyung Kim 80025bf7eaSArnaldo Carvalho de Melo static void hist_browser__update_rows(struct hist_browser *hb) 81025bf7eaSArnaldo Carvalho de Melo { 82025bf7eaSArnaldo Carvalho de Melo struct ui_browser *browser = &hb->b; 83f8e6710dSJiri Olsa struct hists *hists = hb->hists; 84f8e6710dSJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 85f8e6710dSJiri Olsa u16 header_offset, index_row; 86025bf7eaSArnaldo Carvalho de Melo 87f8e6710dSJiri Olsa header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0; 88025bf7eaSArnaldo Carvalho de Melo browser->rows = browser->height - header_offset; 89025bf7eaSArnaldo Carvalho de Melo /* 90025bf7eaSArnaldo Carvalho de Melo * Verify if we were at the last line and that line isn't 91025bf7eaSArnaldo Carvalho de Melo * visibe because we now show the header line(s). 92025bf7eaSArnaldo Carvalho de Melo */ 93025bf7eaSArnaldo Carvalho de Melo index_row = browser->index - browser->top_idx; 94025bf7eaSArnaldo Carvalho de Melo if (index_row >= browser->rows) 95025bf7eaSArnaldo Carvalho de Melo browser->index -= index_row - browser->rows + 1; 96025bf7eaSArnaldo Carvalho de Melo } 97025bf7eaSArnaldo Carvalho de Melo 98357cfff1SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct ui_browser *browser) 99aca7a94dSNamhyung Kim { 100357cfff1SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 101357cfff1SArnaldo Carvalho de Melo 102aca7a94dSNamhyung Kim /* 3 == +/- toggle symbol before actual hist_entry rendering */ 103357cfff1SArnaldo Carvalho de Melo browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]")); 104357cfff1SArnaldo Carvalho de Melo /* 105357cfff1SArnaldo Carvalho de Melo * FIXME: Just keeping existing behaviour, but this really should be 106357cfff1SArnaldo Carvalho de Melo * before updating browser->width, as it will invalidate the 107357cfff1SArnaldo Carvalho de Melo * calculation above. Fix this and the fallout in another 108357cfff1SArnaldo Carvalho de Melo * changeset. 109357cfff1SArnaldo Carvalho de Melo */ 110357cfff1SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(browser); 111025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(hb); 112aca7a94dSNamhyung Kim } 113aca7a94dSNamhyung Kim 114ca3ff33bSArnaldo Carvalho de Melo static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) 115ca3ff33bSArnaldo Carvalho de Melo { 116f8e6710dSJiri Olsa struct hists *hists = browser->hists; 117f8e6710dSJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 118f8e6710dSJiri Olsa u16 header_offset; 119025bf7eaSArnaldo Carvalho de Melo 120f8e6710dSJiri Olsa header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0; 121025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row + header_offset, column); 122ca3ff33bSArnaldo Carvalho de Melo } 123ca3ff33bSArnaldo Carvalho de Melo 12405e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser) 125aca7a94dSNamhyung Kim { 126c3b78952SNamhyung Kim /* 127c3b78952SNamhyung Kim * The hists__remove_entry_filter() already folds non-filtered 128c3b78952SNamhyung Kim * entries so we can assume it has 0 callchain rows. 129c3b78952SNamhyung Kim */ 130c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 131c3b78952SNamhyung Kim 132268397cbSNamhyung Kim hist_browser__update_nr_entries(browser); 133c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 134357cfff1SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(&browser->b); 13505e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 136aca7a94dSNamhyung Kim } 137aca7a94dSNamhyung Kim 138aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded) 139aca7a94dSNamhyung Kim { 140aca7a94dSNamhyung Kim return unfolded ? '-' : '+'; 141aca7a94dSNamhyung Kim } 142aca7a94dSNamhyung Kim 14305e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he) 144aca7a94dSNamhyung Kim { 1453698dab1SNamhyung Kim return he->has_children ? tree__folded_sign(he->unfolded) : ' '; 146aca7a94dSNamhyung Kim } 147aca7a94dSNamhyung Kim 14805e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl) 149aca7a94dSNamhyung Kim { 1503698dab1SNamhyung Kim return cl->has_children ? tree__folded_sign(cl->unfolded) : ' '; 151aca7a94dSNamhyung Kim } 152aca7a94dSNamhyung Kim 1533698dab1SNamhyung Kim static void callchain_list__set_folding(struct callchain_list *cl, bool unfold) 154aca7a94dSNamhyung Kim { 1553698dab1SNamhyung Kim cl->unfolded = unfold ? cl->has_children : false; 156aca7a94dSNamhyung Kim } 157aca7a94dSNamhyung Kim 15805e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 159aca7a94dSNamhyung Kim { 1602a704fc8SMilian Wolff int n = 0; 161aca7a94dSNamhyung Kim struct rb_node *nd; 162aca7a94dSNamhyung Kim 16305e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 164aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 165aca7a94dSNamhyung Kim struct callchain_list *chain; 166aca7a94dSNamhyung Kim char folded_sign = ' '; /* No children */ 167aca7a94dSNamhyung Kim 168aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 169aca7a94dSNamhyung Kim ++n; 1700d3eb0b7SJin Yao 171aca7a94dSNamhyung Kim /* We need this because we may not have children */ 172aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 173aca7a94dSNamhyung Kim if (folded_sign == '+') 174aca7a94dSNamhyung Kim break; 175aca7a94dSNamhyung Kim } 176aca7a94dSNamhyung Kim 177aca7a94dSNamhyung Kim if (folded_sign == '-') /* Have children and they're unfolded */ 178aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(child); 179aca7a94dSNamhyung Kim } 180aca7a94dSNamhyung Kim 181aca7a94dSNamhyung Kim return n; 182aca7a94dSNamhyung Kim } 183aca7a94dSNamhyung Kim 1844b3a3212SNamhyung Kim static int callchain_node__count_flat_rows(struct callchain_node *node) 1854b3a3212SNamhyung Kim { 1864b3a3212SNamhyung Kim struct callchain_list *chain; 1874b3a3212SNamhyung Kim char folded_sign = 0; 1884b3a3212SNamhyung Kim int n = 0; 1894b3a3212SNamhyung Kim 1904b3a3212SNamhyung Kim list_for_each_entry(chain, &node->parent_val, list) { 1914b3a3212SNamhyung Kim if (!folded_sign) { 1924b3a3212SNamhyung Kim /* only check first chain list entry */ 1934b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 1944b3a3212SNamhyung Kim if (folded_sign == '+') 1954b3a3212SNamhyung Kim return 1; 1964b3a3212SNamhyung Kim } 1974b3a3212SNamhyung Kim n++; 1984b3a3212SNamhyung Kim } 1994b3a3212SNamhyung Kim 2004b3a3212SNamhyung Kim list_for_each_entry(chain, &node->val, list) { 2014b3a3212SNamhyung Kim if (!folded_sign) { 2024b3a3212SNamhyung Kim /* node->parent_val list might be empty */ 2034b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 2044b3a3212SNamhyung Kim if (folded_sign == '+') 2054b3a3212SNamhyung Kim return 1; 2064b3a3212SNamhyung Kim } 2074b3a3212SNamhyung Kim n++; 2084b3a3212SNamhyung Kim } 2094b3a3212SNamhyung Kim 2104b3a3212SNamhyung Kim return n; 2114b3a3212SNamhyung Kim } 2124b3a3212SNamhyung Kim 2138c430a34SNamhyung Kim static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused) 2148c430a34SNamhyung Kim { 2158c430a34SNamhyung Kim return 1; 2168c430a34SNamhyung Kim } 2178c430a34SNamhyung Kim 218aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 219aca7a94dSNamhyung Kim { 220aca7a94dSNamhyung Kim struct callchain_list *chain; 221aca7a94dSNamhyung Kim bool unfolded = false; 2222a704fc8SMilian Wolff int n = 0; 223aca7a94dSNamhyung Kim 2244b3a3212SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) 2254b3a3212SNamhyung Kim return callchain_node__count_flat_rows(node); 2268c430a34SNamhyung Kim else if (callchain_param.mode == CHAIN_FOLDED) 2278c430a34SNamhyung Kim return callchain_node__count_folded_rows(node); 2284b3a3212SNamhyung Kim 229aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 230aca7a94dSNamhyung Kim ++n; 2310d3eb0b7SJin Yao 2323698dab1SNamhyung Kim unfolded = chain->unfolded; 233aca7a94dSNamhyung Kim } 234aca7a94dSNamhyung Kim 235aca7a94dSNamhyung Kim if (unfolded) 236aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 237aca7a94dSNamhyung Kim 238aca7a94dSNamhyung Kim return n; 239aca7a94dSNamhyung Kim } 240aca7a94dSNamhyung Kim 241aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 242aca7a94dSNamhyung Kim { 243aca7a94dSNamhyung Kim struct rb_node *nd; 244aca7a94dSNamhyung Kim int n = 0; 245aca7a94dSNamhyung Kim 246aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 247aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 248aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 249aca7a94dSNamhyung Kim } 250aca7a94dSNamhyung Kim 251aca7a94dSNamhyung Kim return n; 252aca7a94dSNamhyung Kim } 253aca7a94dSNamhyung Kim 254f5b763feSNamhyung Kim static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he, 255f5b763feSNamhyung Kim bool include_children) 256f5b763feSNamhyung Kim { 257f5b763feSNamhyung Kim int count = 0; 258f5b763feSNamhyung Kim struct rb_node *node; 259f5b763feSNamhyung Kim struct hist_entry *child; 260f5b763feSNamhyung Kim 261f5b763feSNamhyung Kim if (he->leaf) 262f5b763feSNamhyung Kim return callchain__count_rows(&he->sorted_chain); 263f5b763feSNamhyung Kim 26479dded87SNamhyung Kim if (he->has_no_entry) 26579dded87SNamhyung Kim return 1; 26679dded87SNamhyung Kim 267f5b763feSNamhyung Kim node = rb_first(&he->hroot_out); 268f5b763feSNamhyung Kim while (node) { 269f5b763feSNamhyung Kim float percent; 270f5b763feSNamhyung Kim 271f5b763feSNamhyung Kim child = rb_entry(node, struct hist_entry, rb_node); 272f5b763feSNamhyung Kim percent = hist_entry__get_percent_limit(child); 273f5b763feSNamhyung Kim 274f5b763feSNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) { 275f5b763feSNamhyung Kim count++; 276f5b763feSNamhyung Kim 277f5b763feSNamhyung Kim if (include_children && child->unfolded) 278f5b763feSNamhyung Kim count += hierarchy_count_rows(hb, child, true); 279f5b763feSNamhyung Kim } 280f5b763feSNamhyung Kim 281f5b763feSNamhyung Kim node = rb_next(node); 282f5b763feSNamhyung Kim } 283f5b763feSNamhyung Kim return count; 284f5b763feSNamhyung Kim } 285f5b763feSNamhyung Kim 2863698dab1SNamhyung Kim static bool hist_entry__toggle_fold(struct hist_entry *he) 287aca7a94dSNamhyung Kim { 2883698dab1SNamhyung Kim if (!he) 289aca7a94dSNamhyung Kim return false; 290aca7a94dSNamhyung Kim 2913698dab1SNamhyung Kim if (!he->has_children) 292aca7a94dSNamhyung Kim return false; 293aca7a94dSNamhyung Kim 2943698dab1SNamhyung Kim he->unfolded = !he->unfolded; 2953698dab1SNamhyung Kim return true; 2963698dab1SNamhyung Kim } 2973698dab1SNamhyung Kim 2983698dab1SNamhyung Kim static bool callchain_list__toggle_fold(struct callchain_list *cl) 2993698dab1SNamhyung Kim { 3003698dab1SNamhyung Kim if (!cl) 3013698dab1SNamhyung Kim return false; 3023698dab1SNamhyung Kim 3033698dab1SNamhyung Kim if (!cl->has_children) 3043698dab1SNamhyung Kim return false; 3053698dab1SNamhyung Kim 3063698dab1SNamhyung Kim cl->unfolded = !cl->unfolded; 307aca7a94dSNamhyung Kim return true; 308aca7a94dSNamhyung Kim } 309aca7a94dSNamhyung Kim 31005e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 311aca7a94dSNamhyung Kim { 31205e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 313aca7a94dSNamhyung Kim 31405e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 315aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 316aca7a94dSNamhyung Kim struct callchain_list *chain; 317aca7a94dSNamhyung Kim bool first = true; 318aca7a94dSNamhyung Kim 319aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 320aca7a94dSNamhyung Kim if (first) { 321aca7a94dSNamhyung Kim first = false; 3223698dab1SNamhyung Kim chain->has_children = chain->list.next != &child->val || 323aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 324aca7a94dSNamhyung Kim } else 3253698dab1SNamhyung Kim chain->has_children = chain->list.next == &child->val && 326aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 327aca7a94dSNamhyung Kim } 328aca7a94dSNamhyung Kim 329aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 330aca7a94dSNamhyung Kim } 331aca7a94dSNamhyung Kim } 332aca7a94dSNamhyung Kim 333a7444af6SNamhyung Kim static void callchain_node__init_have_children(struct callchain_node *node, 334a7444af6SNamhyung Kim bool has_sibling) 335aca7a94dSNamhyung Kim { 336aca7a94dSNamhyung Kim struct callchain_list *chain; 337aca7a94dSNamhyung Kim 338a7444af6SNamhyung Kim chain = list_entry(node->val.next, struct callchain_list, list); 3393698dab1SNamhyung Kim chain->has_children = has_sibling; 340a7444af6SNamhyung Kim 34190989035SAndres Freund if (!list_empty(&node->val)) { 34282162b5aSNamhyung Kim chain = list_entry(node->val.prev, struct callchain_list, list); 3433698dab1SNamhyung Kim chain->has_children = !RB_EMPTY_ROOT(&node->rb_root); 34482162b5aSNamhyung Kim } 345aca7a94dSNamhyung Kim 34605e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 347aca7a94dSNamhyung Kim } 348aca7a94dSNamhyung Kim 34905e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 350aca7a94dSNamhyung Kim { 351a7444af6SNamhyung Kim struct rb_node *nd = rb_first(root); 352a7444af6SNamhyung Kim bool has_sibling = nd && rb_next(nd); 353aca7a94dSNamhyung Kim 35405e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 355aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 356a7444af6SNamhyung Kim callchain_node__init_have_children(node, has_sibling); 3578c430a34SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT || 3588c430a34SNamhyung Kim callchain_param.mode == CHAIN_FOLDED) 3594b3a3212SNamhyung Kim callchain_node__make_parent_list(node); 360aca7a94dSNamhyung Kim } 361aca7a94dSNamhyung Kim } 362aca7a94dSNamhyung Kim 36305e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 364aca7a94dSNamhyung Kim { 365f5b763feSNamhyung Kim if (he->init_have_children) 366f5b763feSNamhyung Kim return; 367f5b763feSNamhyung Kim 368f5b763feSNamhyung Kim if (he->leaf) { 3693698dab1SNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 37005e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 371f5b763feSNamhyung Kim } else { 372f5b763feSNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->hroot_out); 373aca7a94dSNamhyung Kim } 374f5b763feSNamhyung Kim 375f5b763feSNamhyung Kim he->init_have_children = true; 376aca7a94dSNamhyung Kim } 377aca7a94dSNamhyung Kim 37805e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 379aca7a94dSNamhyung Kim { 38005e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 3813698dab1SNamhyung Kim struct map_symbol *ms = browser->selection; 3823698dab1SNamhyung Kim struct callchain_list *cl = container_of(ms, struct callchain_list, ms); 3833698dab1SNamhyung Kim bool has_children; 384aca7a94dSNamhyung Kim 3854938cf0cSWang Nan if (!he || !ms) 3864938cf0cSWang Nan return false; 3874938cf0cSWang Nan 3883698dab1SNamhyung Kim if (ms == &he->ms) 3893698dab1SNamhyung Kim has_children = hist_entry__toggle_fold(he); 3903698dab1SNamhyung Kim else 3913698dab1SNamhyung Kim has_children = callchain_list__toggle_fold(cl); 3923698dab1SNamhyung Kim 3933698dab1SNamhyung Kim if (has_children) { 394f5b763feSNamhyung Kim int child_rows = 0; 395f5b763feSNamhyung Kim 396aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 397c3b78952SNamhyung Kim browser->b.nr_entries -= he->nr_rows; 398aca7a94dSNamhyung Kim 399f5b763feSNamhyung Kim if (he->leaf) 400f5b763feSNamhyung Kim browser->nr_callchain_rows -= he->nr_rows; 401f5b763feSNamhyung Kim else 402f5b763feSNamhyung Kim browser->nr_hierarchy_entries -= he->nr_rows; 403f5b763feSNamhyung Kim 404f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 405f5b763feSNamhyung Kim child_rows = hierarchy_count_rows(browser, he, true); 406f5b763feSNamhyung Kim 407f5b763feSNamhyung Kim if (he->unfolded) { 408f5b763feSNamhyung Kim if (he->leaf) 4090d3eb0b7SJin Yao he->nr_rows = callchain__count_rows( 4100d3eb0b7SJin Yao &he->sorted_chain); 411aca7a94dSNamhyung Kim else 412f5b763feSNamhyung Kim he->nr_rows = hierarchy_count_rows(browser, he, false); 413f5b763feSNamhyung Kim 414f5b763feSNamhyung Kim /* account grand children */ 415f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 416f5b763feSNamhyung Kim browser->b.nr_entries += child_rows - he->nr_rows; 41779dded87SNamhyung Kim 41879dded87SNamhyung Kim if (!he->leaf && he->nr_rows == 0) { 41979dded87SNamhyung Kim he->has_no_entry = true; 42079dded87SNamhyung Kim he->nr_rows = 1; 42179dded87SNamhyung Kim } 422f5b763feSNamhyung Kim } else { 423f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 424f5b763feSNamhyung Kim browser->b.nr_entries -= child_rows - he->nr_rows; 425f5b763feSNamhyung Kim 42679dded87SNamhyung Kim if (he->has_no_entry) 42779dded87SNamhyung Kim he->has_no_entry = false; 42879dded87SNamhyung Kim 429aca7a94dSNamhyung Kim he->nr_rows = 0; 430f5b763feSNamhyung Kim } 431c3b78952SNamhyung Kim 432c3b78952SNamhyung Kim browser->b.nr_entries += he->nr_rows; 433f5b763feSNamhyung Kim 434f5b763feSNamhyung Kim if (he->leaf) 435c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 436f5b763feSNamhyung Kim else 437f5b763feSNamhyung Kim browser->nr_hierarchy_entries += he->nr_rows; 438aca7a94dSNamhyung Kim 439aca7a94dSNamhyung Kim return true; 440aca7a94dSNamhyung Kim } 441aca7a94dSNamhyung Kim 442aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 443aca7a94dSNamhyung Kim return false; 444aca7a94dSNamhyung Kim } 445aca7a94dSNamhyung Kim 44605e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 447aca7a94dSNamhyung Kim { 448aca7a94dSNamhyung Kim int n = 0; 449aca7a94dSNamhyung Kim struct rb_node *nd; 450aca7a94dSNamhyung Kim 45105e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 452aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 453aca7a94dSNamhyung Kim struct callchain_list *chain; 454aca7a94dSNamhyung Kim bool has_children = false; 455aca7a94dSNamhyung Kim 456aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 457aca7a94dSNamhyung Kim ++n; 4583698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 4593698dab1SNamhyung Kim has_children = chain->has_children; 460aca7a94dSNamhyung Kim } 461aca7a94dSNamhyung Kim 462aca7a94dSNamhyung Kim if (has_children) 463aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 464aca7a94dSNamhyung Kim } 465aca7a94dSNamhyung Kim 466aca7a94dSNamhyung Kim return n; 467aca7a94dSNamhyung Kim } 468aca7a94dSNamhyung Kim 469aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 470aca7a94dSNamhyung Kim { 471aca7a94dSNamhyung Kim struct callchain_list *chain; 472aca7a94dSNamhyung Kim bool has_children = false; 473aca7a94dSNamhyung Kim int n = 0; 474aca7a94dSNamhyung Kim 475aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 476aca7a94dSNamhyung Kim ++n; 4773698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 4783698dab1SNamhyung Kim has_children = chain->has_children; 479aca7a94dSNamhyung Kim } 480aca7a94dSNamhyung Kim 481aca7a94dSNamhyung Kim if (has_children) 482aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 483aca7a94dSNamhyung Kim 484aca7a94dSNamhyung Kim return n; 485aca7a94dSNamhyung Kim } 486aca7a94dSNamhyung Kim 487aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 488aca7a94dSNamhyung Kim { 489aca7a94dSNamhyung Kim struct rb_node *nd; 490aca7a94dSNamhyung Kim int n = 0; 491aca7a94dSNamhyung Kim 492aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 493aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 494aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 495aca7a94dSNamhyung Kim } 496aca7a94dSNamhyung Kim 497aca7a94dSNamhyung Kim return n; 498aca7a94dSNamhyung Kim } 499aca7a94dSNamhyung Kim 500492b1010SNamhyung Kim static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he, 501492b1010SNamhyung Kim bool unfold __maybe_unused) 502492b1010SNamhyung Kim { 503492b1010SNamhyung Kim float percent; 504492b1010SNamhyung Kim struct rb_node *nd; 505492b1010SNamhyung Kim struct hist_entry *child; 506492b1010SNamhyung Kim int n = 0; 507492b1010SNamhyung Kim 508492b1010SNamhyung Kim for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) { 509492b1010SNamhyung Kim child = rb_entry(nd, struct hist_entry, rb_node); 510492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(child); 511492b1010SNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) 512492b1010SNamhyung Kim n++; 513492b1010SNamhyung Kim } 514492b1010SNamhyung Kim 515492b1010SNamhyung Kim return n; 516492b1010SNamhyung Kim } 517492b1010SNamhyung Kim 518b33f9226SJiri Olsa static void __hist_entry__set_folding(struct hist_entry *he, 519492b1010SNamhyung Kim struct hist_browser *hb, bool unfold) 520aca7a94dSNamhyung Kim { 52105e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 5223698dab1SNamhyung Kim he->unfolded = unfold ? he->has_children : false; 523aca7a94dSNamhyung Kim 5243698dab1SNamhyung Kim if (he->has_children) { 525492b1010SNamhyung Kim int n; 526492b1010SNamhyung Kim 527492b1010SNamhyung Kim if (he->leaf) 528492b1010SNamhyung Kim n = callchain__set_folding(&he->sorted_chain, unfold); 529492b1010SNamhyung Kim else 530492b1010SNamhyung Kim n = hierarchy_set_folding(hb, he, unfold); 531492b1010SNamhyung Kim 53205e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 533aca7a94dSNamhyung Kim } else 53405e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 535aca7a94dSNamhyung Kim } 536aca7a94dSNamhyung Kim 537b33f9226SJiri Olsa static void hist_entry__set_folding(struct hist_entry *he, 538b33f9226SJiri Olsa struct hist_browser *browser, bool unfold) 539aca7a94dSNamhyung Kim { 540492b1010SNamhyung Kim double percent; 541aca7a94dSNamhyung Kim 542492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(he); 543492b1010SNamhyung Kim if (he->filtered || percent < browser->min_pcnt) 544b33f9226SJiri Olsa return; 545b33f9226SJiri Olsa 546b33f9226SJiri Olsa __hist_entry__set_folding(he, browser, unfold); 547492b1010SNamhyung Kim 548492b1010SNamhyung Kim if (!he->depth || unfold) 549492b1010SNamhyung Kim browser->nr_hierarchy_entries++; 550492b1010SNamhyung Kim if (he->leaf) 551c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 55279dded87SNamhyung Kim else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) { 55379dded87SNamhyung Kim browser->nr_hierarchy_entries++; 55479dded87SNamhyung Kim he->has_no_entry = true; 55579dded87SNamhyung Kim he->nr_rows = 1; 55679dded87SNamhyung Kim } else 55779dded87SNamhyung Kim he->has_no_entry = false; 558aca7a94dSNamhyung Kim } 559b33f9226SJiri Olsa 560b33f9226SJiri Olsa static void 561b33f9226SJiri Olsa __hist_browser__set_folding(struct hist_browser *browser, bool unfold) 562b33f9226SJiri Olsa { 563b33f9226SJiri Olsa struct rb_node *nd; 564b33f9226SJiri Olsa struct hist_entry *he; 565b33f9226SJiri Olsa 566b33f9226SJiri Olsa nd = rb_first(&browser->hists->entries); 567b33f9226SJiri Olsa while (nd) { 568b33f9226SJiri Olsa he = rb_entry(nd, struct hist_entry, rb_node); 569b33f9226SJiri Olsa 570b33f9226SJiri Olsa /* set folding state even if it's currently folded */ 571b33f9226SJiri Olsa nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 572b33f9226SJiri Olsa 573b33f9226SJiri Olsa hist_entry__set_folding(he, browser, unfold); 574b33f9226SJiri Olsa } 575aca7a94dSNamhyung Kim } 576aca7a94dSNamhyung Kim 57705e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 578aca7a94dSNamhyung Kim { 579492b1010SNamhyung Kim browser->nr_hierarchy_entries = 0; 580c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 581c3b78952SNamhyung Kim __hist_browser__set_folding(browser, unfold); 582c3b78952SNamhyung Kim 583c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 584aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 58505e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 586aca7a94dSNamhyung Kim } 587aca7a94dSNamhyung Kim 5880e3fa7a7SJiri Olsa static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold) 5890e3fa7a7SJiri Olsa { 5900e3fa7a7SJiri Olsa if (!browser->he_selection) 5910e3fa7a7SJiri Olsa return; 5920e3fa7a7SJiri Olsa 5930e3fa7a7SJiri Olsa hist_entry__set_folding(browser->he_selection, browser, unfold); 5940e3fa7a7SJiri Olsa browser->b.nr_entries = hist_browser__nr_entries(browser); 5950e3fa7a7SJiri Olsa } 5960e3fa7a7SJiri Olsa 597aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 598aca7a94dSNamhyung Kim { 599aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 600aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 601aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 602aca7a94dSNamhyung Kim " perf top -r 80\n\n" 603aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 604aca7a94dSNamhyung Kim } 605aca7a94dSNamhyung Kim 6065b91a86fSJiri Olsa static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size) 6075b91a86fSJiri Olsa { 6085b91a86fSJiri Olsa return browser->title ? browser->title(browser, bf, size) : 0; 6095b91a86fSJiri Olsa } 6105b91a86fSJiri Olsa 611*06cc1a47SKan Liang int hist_browser__run(struct hist_browser *browser, const char *help, 612*06cc1a47SKan Liang bool warn_lost_event) 613aca7a94dSNamhyung Kim { 614aca7a94dSNamhyung Kim int key; 615aca7a94dSNamhyung Kim char title[160]; 616c2a51ab8SNamhyung Kim struct hist_browser_timer *hbt = browser->hbt; 6179783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 618aca7a94dSNamhyung Kim 61905e8b080SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 620c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 621aca7a94dSNamhyung Kim 6225b91a86fSJiri Olsa hist_browser__title(browser, title, sizeof(title)); 623aca7a94dSNamhyung Kim 624090cff3eSNamhyung Kim if (ui_browser__show(&browser->b, title, "%s", help) < 0) 625aca7a94dSNamhyung Kim return -1; 626aca7a94dSNamhyung Kim 627aca7a94dSNamhyung Kim while (1) { 62805e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 629aca7a94dSNamhyung Kim 630aca7a94dSNamhyung Kim switch (key) { 631fa5df943SNamhyung Kim case K_TIMER: { 632fa5df943SNamhyung Kim u64 nr_entries; 6339783adf7SNamhyung Kim hbt->timer(hbt->arg); 634fa5df943SNamhyung Kim 635c6111523SNamhyung Kim if (hist_browser__has_filter(browser) || 636c6111523SNamhyung Kim symbol_conf.report_hierarchy) 637112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 638fa5df943SNamhyung Kim 639c3b78952SNamhyung Kim nr_entries = hist_browser__nr_entries(browser); 640fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 641aca7a94dSNamhyung Kim 642*06cc1a47SKan Liang if (warn_lost_event && 643*06cc1a47SKan Liang (browser->hists->stats.nr_lost_warned != 644*06cc1a47SKan Liang browser->hists->stats.nr_events[PERF_RECORD_LOST])) { 64505e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 64605e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 64705e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 648aca7a94dSNamhyung Kim } 649aca7a94dSNamhyung Kim 6505b91a86fSJiri Olsa hist_browser__title(browser, title, sizeof(title)); 65105e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 652aca7a94dSNamhyung Kim continue; 653fa5df943SNamhyung Kim } 654aca7a94dSNamhyung Kim case 'D': { /* Debug */ 655aca7a94dSNamhyung Kim static int seq; 65605e8b080SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, 657aca7a94dSNamhyung Kim struct hist_entry, rb_node); 658aca7a94dSNamhyung Kim ui_helpline__pop(); 65962c95ae3SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 66005e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 66105e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries, 66262c95ae3SArnaldo Carvalho de Melo browser->b.rows, 66305e8b080SArnaldo Carvalho de Melo browser->b.index, 66405e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 665aca7a94dSNamhyung Kim h->row_offset, h->nr_rows); 666aca7a94dSNamhyung Kim } 667aca7a94dSNamhyung Kim break; 668aca7a94dSNamhyung Kim case 'C': 669aca7a94dSNamhyung Kim /* Collapse the whole world. */ 67005e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 671aca7a94dSNamhyung Kim break; 6720e3fa7a7SJiri Olsa case 'c': 6730e3fa7a7SJiri Olsa /* Collapse the selected entry. */ 6740e3fa7a7SJiri Olsa hist_browser__set_folding_selected(browser, false); 6750e3fa7a7SJiri Olsa break; 676aca7a94dSNamhyung Kim case 'E': 677aca7a94dSNamhyung Kim /* Expand the whole world. */ 67805e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 679aca7a94dSNamhyung Kim break; 6800e3fa7a7SJiri Olsa case 'e': 6810e3fa7a7SJiri Olsa /* Expand the selected entry. */ 6820e3fa7a7SJiri Olsa hist_browser__set_folding_selected(browser, true); 6830e3fa7a7SJiri Olsa break; 684025bf7eaSArnaldo Carvalho de Melo case 'H': 685025bf7eaSArnaldo Carvalho de Melo browser->show_headers = !browser->show_headers; 686025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(browser); 687025bf7eaSArnaldo Carvalho de Melo break; 688aca7a94dSNamhyung Kim case K_ENTER: 68905e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 690aca7a94dSNamhyung Kim break; 691aca7a94dSNamhyung Kim /* fall thru */ 692aca7a94dSNamhyung Kim default: 693aca7a94dSNamhyung Kim goto out; 694aca7a94dSNamhyung Kim } 695aca7a94dSNamhyung Kim } 696aca7a94dSNamhyung Kim out: 69705e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 698aca7a94dSNamhyung Kim return key; 699aca7a94dSNamhyung Kim } 700aca7a94dSNamhyung Kim 70139ee533fSNamhyung Kim struct callchain_print_arg { 70239ee533fSNamhyung Kim /* for hists browser */ 70339ee533fSNamhyung Kim off_t row_offset; 70439ee533fSNamhyung Kim bool is_current_entry; 70539ee533fSNamhyung Kim 70639ee533fSNamhyung Kim /* for file dump */ 70739ee533fSNamhyung Kim FILE *fp; 70839ee533fSNamhyung Kim int printed; 70939ee533fSNamhyung Kim }; 71039ee533fSNamhyung Kim 71139ee533fSNamhyung Kim typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, 71239ee533fSNamhyung Kim struct callchain_list *chain, 71339ee533fSNamhyung Kim const char *str, int offset, 71439ee533fSNamhyung Kim unsigned short row, 71539ee533fSNamhyung Kim struct callchain_print_arg *arg); 71639ee533fSNamhyung Kim 717f4536dddSNamhyung Kim static void hist_browser__show_callchain_entry(struct hist_browser *browser, 718f4536dddSNamhyung Kim struct callchain_list *chain, 71939ee533fSNamhyung Kim const char *str, int offset, 72039ee533fSNamhyung Kim unsigned short row, 72139ee533fSNamhyung Kim struct callchain_print_arg *arg) 722f4536dddSNamhyung Kim { 723f4536dddSNamhyung Kim int color, width; 72439ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 72570e97278SArnaldo Carvalho de Melo bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src; 726f4536dddSNamhyung Kim 727f4536dddSNamhyung Kim color = HE_COLORSET_NORMAL; 728f4536dddSNamhyung Kim width = browser->b.width - (offset + 2); 729f4536dddSNamhyung Kim if (ui_browser__is_current_entry(&browser->b, row)) { 730f4536dddSNamhyung Kim browser->selection = &chain->ms; 731f4536dddSNamhyung Kim color = HE_COLORSET_SELECTED; 73239ee533fSNamhyung Kim arg->is_current_entry = true; 733f4536dddSNamhyung Kim } 734f4536dddSNamhyung Kim 735f4536dddSNamhyung Kim ui_browser__set_color(&browser->b, color); 736f4536dddSNamhyung Kim hist_browser__gotorc(browser, row, 0); 73726270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, " ", offset); 738517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c", folded_sign); 73970e97278SArnaldo Carvalho de Melo ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); 74026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, str, width); 741f4536dddSNamhyung Kim } 742f4536dddSNamhyung Kim 74339ee533fSNamhyung Kim static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, 74439ee533fSNamhyung Kim struct callchain_list *chain, 74539ee533fSNamhyung Kim const char *str, int offset, 74639ee533fSNamhyung Kim unsigned short row __maybe_unused, 74739ee533fSNamhyung Kim struct callchain_print_arg *arg) 74839ee533fSNamhyung Kim { 74939ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 75039ee533fSNamhyung Kim 75139ee533fSNamhyung Kim arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", 75239ee533fSNamhyung Kim folded_sign, str); 75339ee533fSNamhyung Kim } 75439ee533fSNamhyung Kim 75539ee533fSNamhyung Kim typedef bool (*check_output_full_fn)(struct hist_browser *browser, 75639ee533fSNamhyung Kim unsigned short row); 75739ee533fSNamhyung Kim 75839ee533fSNamhyung Kim static bool hist_browser__check_output_full(struct hist_browser *browser, 75939ee533fSNamhyung Kim unsigned short row) 76039ee533fSNamhyung Kim { 76139ee533fSNamhyung Kim return browser->b.rows == row; 76239ee533fSNamhyung Kim } 76339ee533fSNamhyung Kim 76439ee533fSNamhyung Kim static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, 76539ee533fSNamhyung Kim unsigned short row __maybe_unused) 76639ee533fSNamhyung Kim { 76739ee533fSNamhyung Kim return false; 76839ee533fSNamhyung Kim } 76939ee533fSNamhyung Kim 770aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 771aca7a94dSNamhyung Kim 77218bb8381SNamhyung Kim static int hist_browser__show_callchain_list(struct hist_browser *browser, 77318bb8381SNamhyung Kim struct callchain_node *node, 77418bb8381SNamhyung Kim struct callchain_list *chain, 77518bb8381SNamhyung Kim unsigned short row, u64 total, 77618bb8381SNamhyung Kim bool need_percent, int offset, 77718bb8381SNamhyung Kim print_callchain_entry_fn print, 77818bb8381SNamhyung Kim struct callchain_print_arg *arg) 77918bb8381SNamhyung Kim { 78018bb8381SNamhyung Kim char bf[1024], *alloc_str; 781fef51ecdSJin Yao char buf[64], *alloc_str2; 78218bb8381SNamhyung Kim const char *str; 7832a704fc8SMilian Wolff int ret = 1; 78418bb8381SNamhyung Kim 78518bb8381SNamhyung Kim if (arg->row_offset != 0) { 78618bb8381SNamhyung Kim arg->row_offset--; 78718bb8381SNamhyung Kim return 0; 78818bb8381SNamhyung Kim } 78918bb8381SNamhyung Kim 79018bb8381SNamhyung Kim alloc_str = NULL; 791fef51ecdSJin Yao alloc_str2 = NULL; 792fef51ecdSJin Yao 79318bb8381SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 79418bb8381SNamhyung Kim browser->show_dso); 79518bb8381SNamhyung Kim 796fef51ecdSJin Yao if (symbol_conf.show_branchflag_count) { 797c4ee0625SJin Yao callchain_list_counts__printf_value(chain, NULL, 798fef51ecdSJin Yao buf, sizeof(buf)); 79918bb8381SNamhyung Kim 800fef51ecdSJin Yao if (asprintf(&alloc_str2, "%s%s", str, buf) < 0) 801fef51ecdSJin Yao str = "Not enough memory!"; 802fef51ecdSJin Yao else 803fef51ecdSJin Yao str = alloc_str2; 804fef51ecdSJin Yao } 805fef51ecdSJin Yao 806fef51ecdSJin Yao if (need_percent) { 80718bb8381SNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), 80818bb8381SNamhyung Kim total); 80918bb8381SNamhyung Kim 81018bb8381SNamhyung Kim if (asprintf(&alloc_str, "%s %s", buf, str) < 0) 81118bb8381SNamhyung Kim str = "Not enough memory!"; 81218bb8381SNamhyung Kim else 81318bb8381SNamhyung Kim str = alloc_str; 81418bb8381SNamhyung Kim } 81518bb8381SNamhyung Kim 81618bb8381SNamhyung Kim print(browser, chain, str, offset, row, arg); 81718bb8381SNamhyung Kim free(alloc_str); 818fef51ecdSJin Yao free(alloc_str2); 8190d3eb0b7SJin Yao 8202a704fc8SMilian Wolff return ret; 82118bb8381SNamhyung Kim } 82218bb8381SNamhyung Kim 82359c624e2SNamhyung Kim static bool check_percent_display(struct rb_node *node, u64 parent_total) 82459c624e2SNamhyung Kim { 82559c624e2SNamhyung Kim struct callchain_node *child; 82659c624e2SNamhyung Kim 82759c624e2SNamhyung Kim if (node == NULL) 82859c624e2SNamhyung Kim return false; 82959c624e2SNamhyung Kim 83059c624e2SNamhyung Kim if (rb_next(node)) 83159c624e2SNamhyung Kim return true; 83259c624e2SNamhyung Kim 83359c624e2SNamhyung Kim child = rb_entry(node, struct callchain_node, rb_node); 83459c624e2SNamhyung Kim return callchain_cumul_hits(child) != parent_total; 83559c624e2SNamhyung Kim } 83659c624e2SNamhyung Kim 8374b3a3212SNamhyung Kim static int hist_browser__show_callchain_flat(struct hist_browser *browser, 8384b3a3212SNamhyung Kim struct rb_root *root, 8394b3a3212SNamhyung Kim unsigned short row, u64 total, 84059c624e2SNamhyung Kim u64 parent_total, 8414b3a3212SNamhyung Kim print_callchain_entry_fn print, 8424b3a3212SNamhyung Kim struct callchain_print_arg *arg, 8434b3a3212SNamhyung Kim check_output_full_fn is_output_full) 8444b3a3212SNamhyung Kim { 8454b3a3212SNamhyung Kim struct rb_node *node; 8464b3a3212SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 8474b3a3212SNamhyung Kim bool need_percent; 8484b3a3212SNamhyung Kim 8494b3a3212SNamhyung Kim node = rb_first(root); 85059c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 8514b3a3212SNamhyung Kim 8524b3a3212SNamhyung Kim while (node) { 8534b3a3212SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 8544b3a3212SNamhyung Kim struct rb_node *next = rb_next(node); 8554b3a3212SNamhyung Kim struct callchain_list *chain; 8564b3a3212SNamhyung Kim char folded_sign = ' '; 8574b3a3212SNamhyung Kim int first = true; 8584b3a3212SNamhyung Kim int extra_offset = 0; 8594b3a3212SNamhyung Kim 8604b3a3212SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 8614b3a3212SNamhyung Kim bool was_first = first; 8624b3a3212SNamhyung Kim 8634b3a3212SNamhyung Kim if (first) 8644b3a3212SNamhyung Kim first = false; 8654b3a3212SNamhyung Kim else if (need_percent) 8664b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 8674b3a3212SNamhyung Kim 8684b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 8694b3a3212SNamhyung Kim 8704b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 8714b3a3212SNamhyung Kim chain, row, total, 8724b3a3212SNamhyung Kim was_first && need_percent, 8734b3a3212SNamhyung Kim offset + extra_offset, 8744b3a3212SNamhyung Kim print, arg); 8754b3a3212SNamhyung Kim 8764b3a3212SNamhyung Kim if (is_output_full(browser, row)) 8774b3a3212SNamhyung Kim goto out; 8784b3a3212SNamhyung Kim 8794b3a3212SNamhyung Kim if (folded_sign == '+') 8804b3a3212SNamhyung Kim goto next; 8814b3a3212SNamhyung Kim } 8824b3a3212SNamhyung Kim 8834b3a3212SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 8844b3a3212SNamhyung Kim bool was_first = first; 8854b3a3212SNamhyung Kim 8864b3a3212SNamhyung Kim if (first) 8874b3a3212SNamhyung Kim first = false; 8884b3a3212SNamhyung Kim else if (need_percent) 8894b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 8904b3a3212SNamhyung Kim 8914b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 8924b3a3212SNamhyung Kim 8934b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 8944b3a3212SNamhyung Kim chain, row, total, 8954b3a3212SNamhyung Kim was_first && need_percent, 8964b3a3212SNamhyung Kim offset + extra_offset, 8974b3a3212SNamhyung Kim print, arg); 8984b3a3212SNamhyung Kim 8994b3a3212SNamhyung Kim if (is_output_full(browser, row)) 9004b3a3212SNamhyung Kim goto out; 9014b3a3212SNamhyung Kim 9024b3a3212SNamhyung Kim if (folded_sign == '+') 9034b3a3212SNamhyung Kim break; 9044b3a3212SNamhyung Kim } 9054b3a3212SNamhyung Kim 9064b3a3212SNamhyung Kim next: 9074b3a3212SNamhyung Kim if (is_output_full(browser, row)) 9084b3a3212SNamhyung Kim break; 9094b3a3212SNamhyung Kim node = next; 9104b3a3212SNamhyung Kim } 9114b3a3212SNamhyung Kim out: 9124b3a3212SNamhyung Kim return row - first_row; 9134b3a3212SNamhyung Kim } 9144b3a3212SNamhyung Kim 9158c430a34SNamhyung Kim static char *hist_browser__folded_callchain_str(struct hist_browser *browser, 9168c430a34SNamhyung Kim struct callchain_list *chain, 9178c430a34SNamhyung Kim char *value_str, char *old_str) 9188c430a34SNamhyung Kim { 9198c430a34SNamhyung Kim char bf[1024]; 9208c430a34SNamhyung Kim const char *str; 9218c430a34SNamhyung Kim char *new; 9228c430a34SNamhyung Kim 9238c430a34SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 9248c430a34SNamhyung Kim browser->show_dso); 9258c430a34SNamhyung Kim if (old_str) { 9268c430a34SNamhyung Kim if (asprintf(&new, "%s%s%s", old_str, 9278c430a34SNamhyung Kim symbol_conf.field_sep ?: ";", str) < 0) 9288c430a34SNamhyung Kim new = NULL; 9298c430a34SNamhyung Kim } else { 9308c430a34SNamhyung Kim if (value_str) { 9318c430a34SNamhyung Kim if (asprintf(&new, "%s %s", value_str, str) < 0) 9328c430a34SNamhyung Kim new = NULL; 9338c430a34SNamhyung Kim } else { 9348c430a34SNamhyung Kim if (asprintf(&new, "%s", str) < 0) 9358c430a34SNamhyung Kim new = NULL; 9368c430a34SNamhyung Kim } 9378c430a34SNamhyung Kim } 9388c430a34SNamhyung Kim return new; 9398c430a34SNamhyung Kim } 9408c430a34SNamhyung Kim 9418c430a34SNamhyung Kim static int hist_browser__show_callchain_folded(struct hist_browser *browser, 9428c430a34SNamhyung Kim struct rb_root *root, 9438c430a34SNamhyung Kim unsigned short row, u64 total, 94459c624e2SNamhyung Kim u64 parent_total, 9458c430a34SNamhyung Kim print_callchain_entry_fn print, 9468c430a34SNamhyung Kim struct callchain_print_arg *arg, 9478c430a34SNamhyung Kim check_output_full_fn is_output_full) 9488c430a34SNamhyung Kim { 9498c430a34SNamhyung Kim struct rb_node *node; 9508c430a34SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 9518c430a34SNamhyung Kim bool need_percent; 9528c430a34SNamhyung Kim 9538c430a34SNamhyung Kim node = rb_first(root); 95459c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 9558c430a34SNamhyung Kim 9568c430a34SNamhyung Kim while (node) { 9578c430a34SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 9588c430a34SNamhyung Kim struct rb_node *next = rb_next(node); 9598c430a34SNamhyung Kim struct callchain_list *chain, *first_chain = NULL; 9608c430a34SNamhyung Kim int first = true; 9618c430a34SNamhyung Kim char *value_str = NULL, *value_str_alloc = NULL; 9628c430a34SNamhyung Kim char *chain_str = NULL, *chain_str_alloc = NULL; 9638c430a34SNamhyung Kim 9648c430a34SNamhyung Kim if (arg->row_offset != 0) { 9658c430a34SNamhyung Kim arg->row_offset--; 9668c430a34SNamhyung Kim goto next; 9678c430a34SNamhyung Kim } 9688c430a34SNamhyung Kim 9698c430a34SNamhyung Kim if (need_percent) { 9708c430a34SNamhyung Kim char buf[64]; 9718c430a34SNamhyung Kim 9728c430a34SNamhyung Kim callchain_node__scnprintf_value(child, buf, sizeof(buf), total); 9738c430a34SNamhyung Kim if (asprintf(&value_str, "%s", buf) < 0) { 9748c430a34SNamhyung Kim value_str = (char *)"<...>"; 9758c430a34SNamhyung Kim goto do_print; 9768c430a34SNamhyung Kim } 9778c430a34SNamhyung Kim value_str_alloc = value_str; 9788c430a34SNamhyung Kim } 9798c430a34SNamhyung Kim 9808c430a34SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 9818c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 9828c430a34SNamhyung Kim chain, value_str, chain_str); 9838c430a34SNamhyung Kim if (first) { 9848c430a34SNamhyung Kim first = false; 9858c430a34SNamhyung Kim first_chain = chain; 9868c430a34SNamhyung Kim } 9878c430a34SNamhyung Kim 9888c430a34SNamhyung Kim if (chain_str == NULL) { 9898c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 9908c430a34SNamhyung Kim goto do_print; 9918c430a34SNamhyung Kim } 9928c430a34SNamhyung Kim 9938c430a34SNamhyung Kim chain_str_alloc = chain_str; 9948c430a34SNamhyung Kim } 9958c430a34SNamhyung Kim 9968c430a34SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 9978c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 9988c430a34SNamhyung Kim chain, value_str, chain_str); 9998c430a34SNamhyung Kim if (first) { 10008c430a34SNamhyung Kim first = false; 10018c430a34SNamhyung Kim first_chain = chain; 10028c430a34SNamhyung Kim } 10038c430a34SNamhyung Kim 10048c430a34SNamhyung Kim if (chain_str == NULL) { 10058c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 10068c430a34SNamhyung Kim goto do_print; 10078c430a34SNamhyung Kim } 10088c430a34SNamhyung Kim 10098c430a34SNamhyung Kim chain_str_alloc = chain_str; 10108c430a34SNamhyung Kim } 10118c430a34SNamhyung Kim 10128c430a34SNamhyung Kim do_print: 10138c430a34SNamhyung Kim print(browser, first_chain, chain_str, offset, row++, arg); 10148c430a34SNamhyung Kim free(value_str_alloc); 10158c430a34SNamhyung Kim free(chain_str_alloc); 10168c430a34SNamhyung Kim 10178c430a34SNamhyung Kim next: 10188c430a34SNamhyung Kim if (is_output_full(browser, row)) 10198c430a34SNamhyung Kim break; 10208c430a34SNamhyung Kim node = next; 10218c430a34SNamhyung Kim } 10228c430a34SNamhyung Kim 10238c430a34SNamhyung Kim return row - first_row; 10248c430a34SNamhyung Kim } 10258c430a34SNamhyung Kim 10260c841c6cSNamhyung Kim static int hist_browser__show_callchain_graph(struct hist_browser *browser, 1027c09a7e75SNamhyung Kim struct rb_root *root, int level, 102839ee533fSNamhyung Kim unsigned short row, u64 total, 10295eca104eSNamhyung Kim u64 parent_total, 103039ee533fSNamhyung Kim print_callchain_entry_fn print, 103139ee533fSNamhyung Kim struct callchain_print_arg *arg, 103239ee533fSNamhyung Kim check_output_full_fn is_output_full) 1033aca7a94dSNamhyung Kim { 1034aca7a94dSNamhyung Kim struct rb_node *node; 1035f4536dddSNamhyung Kim int first_row = row, offset = level * LEVEL_OFFSET_STEP; 10364087d11cSNamhyung Kim bool need_percent; 10375eca104eSNamhyung Kim u64 percent_total = total; 10385eca104eSNamhyung Kim 10395eca104eSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 10405eca104eSNamhyung Kim percent_total = parent_total; 1041aca7a94dSNamhyung Kim 1042c09a7e75SNamhyung Kim node = rb_first(root); 104359c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 10444087d11cSNamhyung Kim 1045aca7a94dSNamhyung Kim while (node) { 1046aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 1047aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 1048aca7a94dSNamhyung Kim struct callchain_list *chain; 1049aca7a94dSNamhyung Kim char folded_sign = ' '; 1050aca7a94dSNamhyung Kim int first = true; 1051aca7a94dSNamhyung Kim int extra_offset = 0; 1052aca7a94dSNamhyung Kim 1053aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 1054aca7a94dSNamhyung Kim bool was_first = first; 1055aca7a94dSNamhyung Kim 1056aca7a94dSNamhyung Kim if (first) 1057aca7a94dSNamhyung Kim first = false; 10584087d11cSNamhyung Kim else if (need_percent) 1059aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 1060aca7a94dSNamhyung Kim 1061aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 1062aca7a94dSNamhyung Kim 106318bb8381SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 10645eca104eSNamhyung Kim chain, row, percent_total, 106518bb8381SNamhyung Kim was_first && need_percent, 106618bb8381SNamhyung Kim offset + extra_offset, 106718bb8381SNamhyung Kim print, arg); 1068c09a7e75SNamhyung Kim 106918bb8381SNamhyung Kim if (is_output_full(browser, row)) 1070aca7a94dSNamhyung Kim goto out; 107118bb8381SNamhyung Kim 1072aca7a94dSNamhyung Kim if (folded_sign == '+') 1073aca7a94dSNamhyung Kim break; 1074aca7a94dSNamhyung Kim } 1075aca7a94dSNamhyung Kim 1076aca7a94dSNamhyung Kim if (folded_sign == '-') { 1077aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 1078c09a7e75SNamhyung Kim 10790c841c6cSNamhyung Kim row += hist_browser__show_callchain_graph(browser, &child->rb_root, 10805eca104eSNamhyung Kim new_level, row, total, 10815eca104eSNamhyung Kim child->children_hit, 108239ee533fSNamhyung Kim print, arg, is_output_full); 1083aca7a94dSNamhyung Kim } 108439ee533fSNamhyung Kim if (is_output_full(browser, row)) 1085c09a7e75SNamhyung Kim break; 1086aca7a94dSNamhyung Kim node = next; 1087aca7a94dSNamhyung Kim } 1088aca7a94dSNamhyung Kim out: 1089aca7a94dSNamhyung Kim return row - first_row; 1090aca7a94dSNamhyung Kim } 1091aca7a94dSNamhyung Kim 10920c841c6cSNamhyung Kim static int hist_browser__show_callchain(struct hist_browser *browser, 10930c841c6cSNamhyung Kim struct hist_entry *entry, int level, 10940c841c6cSNamhyung Kim unsigned short row, 10950c841c6cSNamhyung Kim print_callchain_entry_fn print, 10960c841c6cSNamhyung Kim struct callchain_print_arg *arg, 10970c841c6cSNamhyung Kim check_output_full_fn is_output_full) 10980c841c6cSNamhyung Kim { 10990c841c6cSNamhyung Kim u64 total = hists__total_period(entry->hists); 11005eca104eSNamhyung Kim u64 parent_total; 11010c841c6cSNamhyung Kim int printed; 11020c841c6cSNamhyung Kim 11030c841c6cSNamhyung Kim if (symbol_conf.cumulate_callchain) 11045eca104eSNamhyung Kim parent_total = entry->stat_acc->period; 11050c841c6cSNamhyung Kim else 11065eca104eSNamhyung Kim parent_total = entry->stat.period; 11070c841c6cSNamhyung Kim 11080c841c6cSNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) { 11090c841c6cSNamhyung Kim printed = hist_browser__show_callchain_flat(browser, 11105eca104eSNamhyung Kim &entry->sorted_chain, row, 11115eca104eSNamhyung Kim total, parent_total, print, arg, 11125eca104eSNamhyung Kim is_output_full); 11130c841c6cSNamhyung Kim } else if (callchain_param.mode == CHAIN_FOLDED) { 11140c841c6cSNamhyung Kim printed = hist_browser__show_callchain_folded(browser, 11155eca104eSNamhyung Kim &entry->sorted_chain, row, 11165eca104eSNamhyung Kim total, parent_total, print, arg, 11175eca104eSNamhyung Kim is_output_full); 11180c841c6cSNamhyung Kim } else { 11190c841c6cSNamhyung Kim printed = hist_browser__show_callchain_graph(browser, 11205eca104eSNamhyung Kim &entry->sorted_chain, level, row, 11215eca104eSNamhyung Kim total, parent_total, print, arg, 11225eca104eSNamhyung Kim is_output_full); 11230c841c6cSNamhyung Kim } 11240c841c6cSNamhyung Kim 11250c841c6cSNamhyung Kim if (arg->is_current_entry) 11260c841c6cSNamhyung Kim browser->he_selection = entry; 11270c841c6cSNamhyung Kim 11280c841c6cSNamhyung Kim return printed; 11290c841c6cSNamhyung Kim } 11300c841c6cSNamhyung Kim 113189701460SNamhyung Kim struct hpp_arg { 113289701460SNamhyung Kim struct ui_browser *b; 113389701460SNamhyung Kim char folded_sign; 113489701460SNamhyung Kim bool current_entry; 113589701460SNamhyung Kim }; 113689701460SNamhyung Kim 113798ba1609SJiri Olsa int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 11382f6d9009SNamhyung Kim { 11392f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 1140d675107cSNamhyung Kim int ret, len; 11412f6d9009SNamhyung Kim va_list args; 11422f6d9009SNamhyung Kim double percent; 11432f6d9009SNamhyung Kim 11442f6d9009SNamhyung Kim va_start(args, fmt); 1145d675107cSNamhyung Kim len = va_arg(args, int); 11462f6d9009SNamhyung Kim percent = va_arg(args, double); 11472f6d9009SNamhyung Kim va_end(args); 11485aed9d24SNamhyung Kim 114989701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 11505aed9d24SNamhyung Kim 1151d675107cSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); 1152517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); 115389701460SNamhyung Kim 11545aed9d24SNamhyung Kim return ret; 1155f5951d56SNamhyung Kim } 1156f5951d56SNamhyung Kim 1157fb821c9eSNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field) \ 11585aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 11595aed9d24SNamhyung Kim { \ 11605aed9d24SNamhyung Kim return he->stat._field; \ 11615aed9d24SNamhyung Kim } \ 11625aed9d24SNamhyung Kim \ 11632c5d4b4aSJiri Olsa static int \ 11645b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 11652c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 11665aed9d24SNamhyung Kim struct hist_entry *he) \ 11675aed9d24SNamhyung Kim { \ 11685b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \ 11692f6d9009SNamhyung Kim __hpp__slsmg_color_printf, true); \ 11705aed9d24SNamhyung Kim } 1171f5951d56SNamhyung Kim 11720434ddd2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 11730434ddd2SNamhyung Kim static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ 11740434ddd2SNamhyung Kim { \ 11750434ddd2SNamhyung Kim return he->stat_acc->_field; \ 11760434ddd2SNamhyung Kim } \ 11770434ddd2SNamhyung Kim \ 11780434ddd2SNamhyung Kim static int \ 11795b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 11800434ddd2SNamhyung Kim struct perf_hpp *hpp, \ 11810434ddd2SNamhyung Kim struct hist_entry *he) \ 11820434ddd2SNamhyung Kim { \ 11830434ddd2SNamhyung Kim if (!symbol_conf.cumulate_callchain) { \ 1184517dfdb3SArnaldo Carvalho de Melo struct hpp_arg *arg = hpp->ptr; \ 11855b591669SNamhyung Kim int len = fmt->user_len ?: fmt->len; \ 1186d675107cSNamhyung Kim int ret = scnprintf(hpp->buf, hpp->size, \ 11875b591669SNamhyung Kim "%*s", len, "N/A"); \ 1188517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); \ 11890434ddd2SNamhyung Kim \ 11900434ddd2SNamhyung Kim return ret; \ 11910434ddd2SNamhyung Kim } \ 11925b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \ 11935b591669SNamhyung Kim " %*.2f%%", __hpp__slsmg_color_printf, true); \ 11940434ddd2SNamhyung Kim } 11950434ddd2SNamhyung Kim 1196fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period) 1197fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 1198fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us) 1199fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 1200fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 12010434ddd2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period) 12025aed9d24SNamhyung Kim 12035aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 12040434ddd2SNamhyung Kim #undef __HPP_COLOR_ACC_PERCENT_FN 1205f5951d56SNamhyung Kim 1206f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 1207f5951d56SNamhyung Kim { 1208f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 1209f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 1210f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 1211f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 1212f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 1213f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 1214f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 1215f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 1216f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 1217f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 12180434ddd2SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = 12190434ddd2SNamhyung Kim hist_browser__hpp_color_overhead_acc; 1220f5951d56SNamhyung Kim } 1221f5951d56SNamhyung Kim 122205e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 1223aca7a94dSNamhyung Kim struct hist_entry *entry, 1224aca7a94dSNamhyung Kim unsigned short row) 1225aca7a94dSNamhyung Kim { 12261240005eSJiri Olsa int printed = 0; 122767d25916SNamhyung Kim int width = browser->b.width; 1228aca7a94dSNamhyung Kim char folded_sign = ' '; 122905e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1230aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 123163a1a3d8SNamhyung Kim bool first = true; 12321240005eSJiri Olsa struct perf_hpp_fmt *fmt; 1233aca7a94dSNamhyung Kim 1234aca7a94dSNamhyung Kim if (current_entry) { 123505e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 123605e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 1237aca7a94dSNamhyung Kim } 1238aca7a94dSNamhyung Kim 1239aca7a94dSNamhyung Kim if (symbol_conf.use_callchain) { 1240aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 1241aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 1242aca7a94dSNamhyung Kim } 1243aca7a94dSNamhyung Kim 1244aca7a94dSNamhyung Kim if (row_offset == 0) { 124589701460SNamhyung Kim struct hpp_arg arg = { 124689701460SNamhyung Kim .b = &browser->b, 124789701460SNamhyung Kim .folded_sign = folded_sign, 124889701460SNamhyung Kim .current_entry = current_entry, 124989701460SNamhyung Kim }; 1250c6c3c02dSArnaldo Carvalho de Melo int column = 0; 1251f5951d56SNamhyung Kim 1252ca3ff33bSArnaldo Carvalho de Melo hist_browser__gotorc(browser, row, 0); 1253f5951d56SNamhyung Kim 1254f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 125589fee709SArnaldo Carvalho de Melo char s[2048]; 125689fee709SArnaldo Carvalho de Melo struct perf_hpp hpp = { 125789fee709SArnaldo Carvalho de Melo .buf = s, 125889fee709SArnaldo Carvalho de Melo .size = sizeof(s), 125989fee709SArnaldo Carvalho de Melo .ptr = &arg, 126089fee709SArnaldo Carvalho de Melo }; 126189fee709SArnaldo Carvalho de Melo 1262361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1263361459f1SNamhyung Kim column++ < browser->b.horiz_scroll) 1264e67d49a7SNamhyung Kim continue; 1265e67d49a7SNamhyung Kim 1266fb821c9eSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1267fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1268fb821c9eSNamhyung Kim HE_COLORSET_SELECTED); 1269fb821c9eSNamhyung Kim } else { 1270fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1271fb821c9eSNamhyung Kim HE_COLORSET_NORMAL); 1272fb821c9eSNamhyung Kim } 1273fb821c9eSNamhyung Kim 1274fb821c9eSNamhyung Kim if (first) { 12752a704fc8SMilian Wolff if (symbol_conf.use_callchain) { 1276517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c ", folded_sign); 1277f5951d56SNamhyung Kim width -= 2; 1278f5951d56SNamhyung Kim } 127963a1a3d8SNamhyung Kim first = false; 1280fb821c9eSNamhyung Kim } else { 1281517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, " "); 1282fb821c9eSNamhyung Kim width -= 2; 1283fb821c9eSNamhyung Kim } 1284f5951d56SNamhyung Kim 12851240005eSJiri Olsa if (fmt->color) { 128689fee709SArnaldo Carvalho de Melo int ret = fmt->color(fmt, &hpp, entry); 128789fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 128889fee709SArnaldo Carvalho de Melo /* 128989fee709SArnaldo Carvalho de Melo * fmt->color() already used ui_browser to 129089fee709SArnaldo Carvalho de Melo * print the non alignment bits, skip it (+ret): 129189fee709SArnaldo Carvalho de Melo */ 129289fee709SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s + ret); 1293f5951d56SNamhyung Kim } else { 129489fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry)); 1295517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s); 1296f5951d56SNamhyung Kim } 129789fee709SArnaldo Carvalho de Melo width -= hpp.buf - s; 1298f5951d56SNamhyung Kim } 1299aca7a94dSNamhyung Kim 1300aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 130105e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 1302aca7a94dSNamhyung Kim width += 1; 1303aca7a94dSNamhyung Kim 130426270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, "", width); 130526d8b338SNamhyung Kim 1306aca7a94dSNamhyung Kim ++row; 1307aca7a94dSNamhyung Kim ++printed; 1308aca7a94dSNamhyung Kim } else 1309aca7a94dSNamhyung Kim --row_offset; 1310aca7a94dSNamhyung Kim 131162c95ae3SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.rows) { 131239ee533fSNamhyung Kim struct callchain_print_arg arg = { 131339ee533fSNamhyung Kim .row_offset = row_offset, 131439ee533fSNamhyung Kim .is_current_entry = current_entry, 131539ee533fSNamhyung Kim }; 1316c09a7e75SNamhyung Kim 13170d3eb0b7SJin Yao printed += hist_browser__show_callchain(browser, 13180d3eb0b7SJin Yao entry, 1, row, 13190d3eb0b7SJin Yao hist_browser__show_callchain_entry, 13200d3eb0b7SJin Yao &arg, 13214b3a3212SNamhyung Kim hist_browser__check_output_full); 1322aca7a94dSNamhyung Kim } 1323aca7a94dSNamhyung Kim 1324aca7a94dSNamhyung Kim return printed; 1325aca7a94dSNamhyung Kim } 1326aca7a94dSNamhyung Kim 1327d0506edbSNamhyung Kim static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, 1328d0506edbSNamhyung Kim struct hist_entry *entry, 1329d0506edbSNamhyung Kim unsigned short row, 13302dbbe9f2SNamhyung Kim int level) 1331d0506edbSNamhyung Kim { 1332d0506edbSNamhyung Kim int printed = 0; 1333d0506edbSNamhyung Kim int width = browser->b.width; 1334d0506edbSNamhyung Kim char folded_sign = ' '; 1335d0506edbSNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1336d0506edbSNamhyung Kim off_t row_offset = entry->row_offset; 1337d0506edbSNamhyung Kim bool first = true; 1338d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 1339a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1340d0506edbSNamhyung Kim struct hpp_arg arg = { 1341d0506edbSNamhyung Kim .b = &browser->b, 1342d0506edbSNamhyung Kim .current_entry = current_entry, 1343d0506edbSNamhyung Kim }; 1344d0506edbSNamhyung Kim int column = 0; 13452dbbe9f2SNamhyung Kim int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 1346d0506edbSNamhyung Kim 1347d0506edbSNamhyung Kim if (current_entry) { 1348d0506edbSNamhyung Kim browser->he_selection = entry; 1349d0506edbSNamhyung Kim browser->selection = &entry->ms; 1350d0506edbSNamhyung Kim } 1351d0506edbSNamhyung Kim 1352d0506edbSNamhyung Kim hist_entry__init_have_children(entry); 1353d0506edbSNamhyung Kim folded_sign = hist_entry__folded(entry); 1354d0506edbSNamhyung Kim arg.folded_sign = folded_sign; 1355d0506edbSNamhyung Kim 1356d0506edbSNamhyung Kim if (entry->leaf && row_offset) { 1357d0506edbSNamhyung Kim row_offset--; 1358d0506edbSNamhyung Kim goto show_callchain; 1359d0506edbSNamhyung Kim } 1360d0506edbSNamhyung Kim 1361d0506edbSNamhyung Kim hist_browser__gotorc(browser, row, 0); 1362d0506edbSNamhyung Kim 1363d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) 1364d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 1365d0506edbSNamhyung Kim else 1366d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 1367d0506edbSNamhyung Kim 1368d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 1369d0506edbSNamhyung Kim width -= level * HIERARCHY_INDENT; 1370d0506edbSNamhyung Kim 1371a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1372a61a22f6SNamhyung Kim fmt_node = list_first_entry(&entry->hists->hpp_formats, 1373a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1374a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1375d0506edbSNamhyung Kim char s[2048]; 1376d0506edbSNamhyung Kim struct perf_hpp hpp = { 1377d0506edbSNamhyung Kim .buf = s, 1378d0506edbSNamhyung Kim .size = sizeof(s), 1379d0506edbSNamhyung Kim .ptr = &arg, 1380d0506edbSNamhyung Kim }; 1381d0506edbSNamhyung Kim 1382d0506edbSNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1383d0506edbSNamhyung Kim column++ < browser->b.horiz_scroll) 1384d0506edbSNamhyung Kim continue; 1385d0506edbSNamhyung Kim 1386d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1387d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1388d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1389d0506edbSNamhyung Kim } else { 1390d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1391d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1392d0506edbSNamhyung Kim } 1393d0506edbSNamhyung Kim 1394d0506edbSNamhyung Kim if (first) { 1395d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%c ", folded_sign); 13963d9f4683SNamhyung Kim width -= 2; 1397d0506edbSNamhyung Kim first = false; 1398d0506edbSNamhyung Kim } else { 1399d0506edbSNamhyung Kim ui_browser__printf(&browser->b, " "); 1400d0506edbSNamhyung Kim width -= 2; 1401d0506edbSNamhyung Kim } 1402d0506edbSNamhyung Kim 1403d0506edbSNamhyung Kim if (fmt->color) { 1404d0506edbSNamhyung Kim int ret = fmt->color(fmt, &hpp, entry); 1405d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1406d0506edbSNamhyung Kim /* 1407d0506edbSNamhyung Kim * fmt->color() already used ui_browser to 1408d0506edbSNamhyung Kim * print the non alignment bits, skip it (+ret): 1409d0506edbSNamhyung Kim */ 1410d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s + ret); 1411d0506edbSNamhyung Kim } else { 1412d0506edbSNamhyung Kim int ret = fmt->entry(fmt, &hpp, entry); 1413d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1414d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s); 1415d0506edbSNamhyung Kim } 1416d0506edbSNamhyung Kim width -= hpp.buf - s; 1417d0506edbSNamhyung Kim } 1418d0506edbSNamhyung Kim 1419b9bf911eSNamhyung Kim if (!first) { 1420d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", hierarchy_indent); 1421d0506edbSNamhyung Kim width -= hierarchy_indent; 1422b9bf911eSNamhyung Kim } 1423d0506edbSNamhyung Kim 1424d0506edbSNamhyung Kim if (column >= browser->b.horiz_scroll) { 1425d0506edbSNamhyung Kim char s[2048]; 1426d0506edbSNamhyung Kim struct perf_hpp hpp = { 1427d0506edbSNamhyung Kim .buf = s, 1428d0506edbSNamhyung Kim .size = sizeof(s), 1429d0506edbSNamhyung Kim .ptr = &arg, 1430d0506edbSNamhyung Kim }; 1431d0506edbSNamhyung Kim 1432d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1433d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1434d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1435d0506edbSNamhyung Kim } else { 1436d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1437d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1438d0506edbSNamhyung Kim } 1439d0506edbSNamhyung Kim 14401b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(entry->hpp_list, fmt) { 1441131d51ebSNamhyung Kim if (first) { 1442131d51ebSNamhyung Kim ui_browser__printf(&browser->b, "%c ", folded_sign); 1443131d51ebSNamhyung Kim first = false; 1444131d51ebSNamhyung Kim } else { 1445d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", 2); 1446131d51ebSNamhyung Kim } 1447131d51ebSNamhyung Kim 1448d0506edbSNamhyung Kim width -= 2; 1449d0506edbSNamhyung Kim 1450d0506edbSNamhyung Kim /* 1451d0506edbSNamhyung Kim * No need to call hist_entry__snprintf_alignment() 1452d0506edbSNamhyung Kim * since this fmt is always the last column in the 1453d0506edbSNamhyung Kim * hierarchy mode. 1454d0506edbSNamhyung Kim */ 1455d0506edbSNamhyung Kim if (fmt->color) { 1456d0506edbSNamhyung Kim width -= fmt->color(fmt, &hpp, entry); 1457d0506edbSNamhyung Kim } else { 1458cb1fab91SNamhyung Kim int i = 0; 1459cb1fab91SNamhyung Kim 1460d0506edbSNamhyung Kim width -= fmt->entry(fmt, &hpp, entry); 1461cb1fab91SNamhyung Kim ui_browser__printf(&browser->b, "%s", ltrim(s)); 1462cb1fab91SNamhyung Kim 1463cb1fab91SNamhyung Kim while (isspace(s[i++])) 1464cb1fab91SNamhyung Kim width++; 1465d0506edbSNamhyung Kim } 1466d0506edbSNamhyung Kim } 14671b2dbbf4SNamhyung Kim } 1468d0506edbSNamhyung Kim 1469d0506edbSNamhyung Kim /* The scroll bar isn't being used */ 1470d0506edbSNamhyung Kim if (!browser->b.navkeypressed) 1471d0506edbSNamhyung Kim width += 1; 1472d0506edbSNamhyung Kim 1473d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 1474d0506edbSNamhyung Kim 1475d0506edbSNamhyung Kim ++row; 1476d0506edbSNamhyung Kim ++printed; 1477d0506edbSNamhyung Kim 1478d0506edbSNamhyung Kim show_callchain: 1479d0506edbSNamhyung Kim if (entry->leaf && folded_sign == '-' && row != browser->b.rows) { 1480d0506edbSNamhyung Kim struct callchain_print_arg carg = { 1481d0506edbSNamhyung Kim .row_offset = row_offset, 1482d0506edbSNamhyung Kim }; 1483d0506edbSNamhyung Kim 1484d0506edbSNamhyung Kim printed += hist_browser__show_callchain(browser, entry, 1485d0506edbSNamhyung Kim level + 1, row, 1486d0506edbSNamhyung Kim hist_browser__show_callchain_entry, &carg, 1487d0506edbSNamhyung Kim hist_browser__check_output_full); 1488d0506edbSNamhyung Kim } 1489d0506edbSNamhyung Kim 1490d0506edbSNamhyung Kim return printed; 1491d0506edbSNamhyung Kim } 1492d0506edbSNamhyung Kim 149379dded87SNamhyung Kim static int hist_browser__show_no_entry(struct hist_browser *browser, 14942dbbe9f2SNamhyung Kim unsigned short row, int level) 149579dded87SNamhyung Kim { 149679dded87SNamhyung Kim int width = browser->b.width; 149779dded87SNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 149879dded87SNamhyung Kim bool first = true; 149979dded87SNamhyung Kim int column = 0; 150079dded87SNamhyung Kim int ret; 150179dded87SNamhyung Kim struct perf_hpp_fmt *fmt; 1502a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 15032dbbe9f2SNamhyung Kim int indent = browser->hists->nr_hpp_node - 2; 150479dded87SNamhyung Kim 150579dded87SNamhyung Kim if (current_entry) { 150679dded87SNamhyung Kim browser->he_selection = NULL; 150779dded87SNamhyung Kim browser->selection = NULL; 150879dded87SNamhyung Kim } 150979dded87SNamhyung Kim 151079dded87SNamhyung Kim hist_browser__gotorc(browser, row, 0); 151179dded87SNamhyung Kim 151279dded87SNamhyung Kim if (current_entry && browser->b.navkeypressed) 151379dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 151479dded87SNamhyung Kim else 151579dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 151679dded87SNamhyung Kim 151779dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 151879dded87SNamhyung Kim width -= level * HIERARCHY_INDENT; 151979dded87SNamhyung Kim 1520a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1521a61a22f6SNamhyung Kim fmt_node = list_first_entry(&browser->hists->hpp_formats, 1522a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1523a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 152479dded87SNamhyung Kim if (perf_hpp__should_skip(fmt, browser->hists) || 152579dded87SNamhyung Kim column++ < browser->b.horiz_scroll) 152679dded87SNamhyung Kim continue; 152779dded87SNamhyung Kim 1528da1b0407SJiri Olsa ret = fmt->width(fmt, NULL, browser->hists); 152979dded87SNamhyung Kim 153079dded87SNamhyung Kim if (first) { 153179dded87SNamhyung Kim /* for folded sign */ 153279dded87SNamhyung Kim first = false; 153379dded87SNamhyung Kim ret++; 153479dded87SNamhyung Kim } else { 153579dded87SNamhyung Kim /* space between columns */ 153679dded87SNamhyung Kim ret += 2; 153779dded87SNamhyung Kim } 153879dded87SNamhyung Kim 153979dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", ret); 154079dded87SNamhyung Kim width -= ret; 154179dded87SNamhyung Kim } 154279dded87SNamhyung Kim 15432dbbe9f2SNamhyung Kim ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT); 15442dbbe9f2SNamhyung Kim width -= indent * HIERARCHY_INDENT; 154579dded87SNamhyung Kim 154679dded87SNamhyung Kim if (column >= browser->b.horiz_scroll) { 154779dded87SNamhyung Kim char buf[32]; 154879dded87SNamhyung Kim 154979dded87SNamhyung Kim ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt); 155079dded87SNamhyung Kim ui_browser__printf(&browser->b, " %s", buf); 155179dded87SNamhyung Kim width -= ret + 2; 155279dded87SNamhyung Kim } 155379dded87SNamhyung Kim 155479dded87SNamhyung Kim /* The scroll bar isn't being used */ 155579dded87SNamhyung Kim if (!browser->b.navkeypressed) 155679dded87SNamhyung Kim width += 1; 155779dded87SNamhyung Kim 155879dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 155979dded87SNamhyung Kim return 1; 156079dded87SNamhyung Kim } 156179dded87SNamhyung Kim 156281a888feSJiri Olsa static int advance_hpp_check(struct perf_hpp *hpp, int inc) 156381a888feSJiri Olsa { 156481a888feSJiri Olsa advance_hpp(hpp, inc); 156581a888feSJiri Olsa return hpp->size <= 0; 156681a888feSJiri Olsa } 156781a888feSJiri Olsa 156869705b35SJiri Olsa static int 156969705b35SJiri Olsa hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, 157069705b35SJiri Olsa size_t size, int line) 157181a888feSJiri Olsa { 1572c6c3c02dSArnaldo Carvalho de Melo struct hists *hists = browser->hists; 157381a888feSJiri Olsa struct perf_hpp dummy_hpp = { 157481a888feSJiri Olsa .buf = buf, 157581a888feSJiri Olsa .size = size, 157681a888feSJiri Olsa }; 157781a888feSJiri Olsa struct perf_hpp_fmt *fmt; 157881a888feSJiri Olsa size_t ret = 0; 1579c6c3c02dSArnaldo Carvalho de Melo int column = 0; 158029659ab4SJiri Olsa int span = 0; 158181a888feSJiri Olsa 158281a888feSJiri Olsa if (symbol_conf.use_callchain) { 158381a888feSJiri Olsa ret = scnprintf(buf, size, " "); 158481a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 158581a888feSJiri Olsa return ret; 158681a888feSJiri Olsa } 158781a888feSJiri Olsa 1588f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 1589361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) 159081a888feSJiri Olsa continue; 159181a888feSJiri Olsa 159229659ab4SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists, line, &span); 159381a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 159481a888feSJiri Olsa break; 159581a888feSJiri Olsa 159629659ab4SJiri Olsa if (span) 159729659ab4SJiri Olsa continue; 159829659ab4SJiri Olsa 159981a888feSJiri Olsa ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 160081a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 160181a888feSJiri Olsa break; 160281a888feSJiri Olsa } 160381a888feSJiri Olsa 160481a888feSJiri Olsa return ret; 160581a888feSJiri Olsa } 160681a888feSJiri Olsa 1607d8b92400SNamhyung Kim static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size) 1608d8b92400SNamhyung Kim { 1609d8b92400SNamhyung Kim struct hists *hists = browser->hists; 1610d8b92400SNamhyung Kim struct perf_hpp dummy_hpp = { 1611d8b92400SNamhyung Kim .buf = buf, 1612d8b92400SNamhyung Kim .size = size, 1613d8b92400SNamhyung Kim }; 1614d8b92400SNamhyung Kim struct perf_hpp_fmt *fmt; 1615a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1616d8b92400SNamhyung Kim size_t ret = 0; 1617d8b92400SNamhyung Kim int column = 0; 16182dbbe9f2SNamhyung Kim int indent = hists->nr_hpp_node - 2; 1619a61a22f6SNamhyung Kim bool first_node, first_col; 1620d8b92400SNamhyung Kim 1621d8b92400SNamhyung Kim ret = scnprintf(buf, size, " "); 1622d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1623d8b92400SNamhyung Kim return ret; 1624d8b92400SNamhyung Kim 1625b9bf911eSNamhyung Kim first_node = true; 1626a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1627a61a22f6SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 1628a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1629a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1630d8b92400SNamhyung Kim if (column++ < browser->b.horiz_scroll) 1631d8b92400SNamhyung Kim continue; 1632d8b92400SNamhyung Kim 163329659ab4SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL); 1634d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1635d8b92400SNamhyung Kim break; 1636d8b92400SNamhyung Kim 1637d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 1638d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1639d8b92400SNamhyung Kim break; 1640b9bf911eSNamhyung Kim 1641b9bf911eSNamhyung Kim first_node = false; 1642d8b92400SNamhyung Kim } 1643d8b92400SNamhyung Kim 1644b9bf911eSNamhyung Kim if (!first_node) { 1645d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s", 16462dbbe9f2SNamhyung Kim indent * HIERARCHY_INDENT, ""); 1647d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1648d8b92400SNamhyung Kim return ret; 1649b9bf911eSNamhyung Kim } 1650d8b92400SNamhyung Kim 1651a61a22f6SNamhyung Kim first_node = true; 1652a61a22f6SNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) { 1653a61a22f6SNamhyung Kim if (!first_node) { 1654d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / "); 1655d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1656d8b92400SNamhyung Kim break; 1657d8b92400SNamhyung Kim } 1658a61a22f6SNamhyung Kim first_node = false; 1659a61a22f6SNamhyung Kim 1660a61a22f6SNamhyung Kim first_col = true; 1661a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1662a61a22f6SNamhyung Kim char *start; 1663a61a22f6SNamhyung Kim 1664a61a22f6SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 1665a61a22f6SNamhyung Kim continue; 1666a61a22f6SNamhyung Kim 1667a61a22f6SNamhyung Kim if (!first_col) { 1668a61a22f6SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+"); 1669a61a22f6SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1670a61a22f6SNamhyung Kim break; 1671a61a22f6SNamhyung Kim } 1672a61a22f6SNamhyung Kim first_col = false; 1673d8b92400SNamhyung Kim 167429659ab4SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL); 1675d8b92400SNamhyung Kim dummy_hpp.buf[ret] = '\0'; 1676d8b92400SNamhyung Kim 16777d6a7e78SJiri Olsa start = trim(dummy_hpp.buf); 1678cb1fab91SNamhyung Kim ret = strlen(start); 1679cb1fab91SNamhyung Kim 1680cb1fab91SNamhyung Kim if (start != dummy_hpp.buf) 1681cb1fab91SNamhyung Kim memmove(dummy_hpp.buf, start, ret + 1); 1682cb1fab91SNamhyung Kim 1683d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1684d8b92400SNamhyung Kim break; 1685d8b92400SNamhyung Kim } 1686a61a22f6SNamhyung Kim } 1687d8b92400SNamhyung Kim 1688d8b92400SNamhyung Kim return ret; 1689d8b92400SNamhyung Kim } 1690d8b92400SNamhyung Kim 169101b4770dSJiri Olsa static void hists_browser__hierarchy_headers(struct hist_browser *browser) 1692025bf7eaSArnaldo Carvalho de Melo { 169381a888feSJiri Olsa char headers[1024]; 169481a888feSJiri Olsa 1695d8b92400SNamhyung Kim hists_browser__scnprintf_hierarchy_headers(browser, headers, 1696d8b92400SNamhyung Kim sizeof(headers)); 169701b4770dSJiri Olsa 1698025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, 0, 0); 1699025bf7eaSArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 170026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 1701025bf7eaSArnaldo Carvalho de Melo } 1702025bf7eaSArnaldo Carvalho de Melo 170301b4770dSJiri Olsa static void hists_browser__headers(struct hist_browser *browser) 170401b4770dSJiri Olsa { 170569705b35SJiri Olsa struct hists *hists = browser->hists; 170669705b35SJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 170769705b35SJiri Olsa 170869705b35SJiri Olsa int line; 170969705b35SJiri Olsa 171069705b35SJiri Olsa for (line = 0; line < hpp_list->nr_header_lines; line++) { 171101b4770dSJiri Olsa char headers[1024]; 171201b4770dSJiri Olsa 171301b4770dSJiri Olsa hists_browser__scnprintf_headers(browser, headers, 171469705b35SJiri Olsa sizeof(headers), line); 171501b4770dSJiri Olsa 171669705b35SJiri Olsa ui_browser__gotorc(&browser->b, line, 0); 171701b4770dSJiri Olsa ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 171801b4770dSJiri Olsa ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 171901b4770dSJiri Olsa } 172069705b35SJiri Olsa } 172101b4770dSJiri Olsa 172201b4770dSJiri Olsa static void hist_browser__show_headers(struct hist_browser *browser) 172301b4770dSJiri Olsa { 172401b4770dSJiri Olsa if (symbol_conf.report_hierarchy) 172501b4770dSJiri Olsa hists_browser__hierarchy_headers(browser); 172601b4770dSJiri Olsa else 172701b4770dSJiri Olsa hists_browser__headers(browser); 172801b4770dSJiri Olsa } 172901b4770dSJiri Olsa 1730aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 1731aca7a94dSNamhyung Kim { 1732aca7a94dSNamhyung Kim if (browser->top == NULL) { 1733aca7a94dSNamhyung Kim struct hist_browser *hb; 1734aca7a94dSNamhyung Kim 1735aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1736aca7a94dSNamhyung Kim browser->top = rb_first(&hb->hists->entries); 1737aca7a94dSNamhyung Kim } 1738aca7a94dSNamhyung Kim } 1739aca7a94dSNamhyung Kim 174005e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 1741aca7a94dSNamhyung Kim { 1742aca7a94dSNamhyung Kim unsigned row = 0; 1743025bf7eaSArnaldo Carvalho de Melo u16 header_offset = 0; 1744aca7a94dSNamhyung Kim struct rb_node *nd; 174505e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 1746f8e6710dSJiri Olsa struct hists *hists = hb->hists; 1747aca7a94dSNamhyung Kim 1748025bf7eaSArnaldo Carvalho de Melo if (hb->show_headers) { 1749f8e6710dSJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 1750f8e6710dSJiri Olsa 1751025bf7eaSArnaldo Carvalho de Melo hist_browser__show_headers(hb); 1752f8e6710dSJiri Olsa header_offset = hpp_list->nr_header_lines; 1753025bf7eaSArnaldo Carvalho de Melo } 1754025bf7eaSArnaldo Carvalho de Melo 175505e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1756979d2cacSWang Nan hb->he_selection = NULL; 1757979d2cacSWang Nan hb->selection = NULL; 1758aca7a94dSNamhyung Kim 1759d0506edbSNamhyung Kim for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) { 1760aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 176114135663SNamhyung Kim float percent; 1762aca7a94dSNamhyung Kim 1763d0506edbSNamhyung Kim if (h->filtered) { 1764d0506edbSNamhyung Kim /* let it move to sibling */ 1765d0506edbSNamhyung Kim h->unfolded = false; 1766aca7a94dSNamhyung Kim continue; 1767d0506edbSNamhyung Kim } 1768aca7a94dSNamhyung Kim 176914135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 1770064f1981SNamhyung Kim if (percent < hb->min_pcnt) 1771064f1981SNamhyung Kim continue; 1772064f1981SNamhyung Kim 1773d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 1774d0506edbSNamhyung Kim row += hist_browser__show_hierarchy_entry(hb, h, row, 17752dbbe9f2SNamhyung Kim h->depth); 177679dded87SNamhyung Kim if (row == browser->rows) 177779dded87SNamhyung Kim break; 177879dded87SNamhyung Kim 177979dded87SNamhyung Kim if (h->has_no_entry) { 1780a61a22f6SNamhyung Kim hist_browser__show_no_entry(hb, row, h->depth + 1); 178179dded87SNamhyung Kim row++; 178279dded87SNamhyung Kim } 1783d0506edbSNamhyung Kim } else { 1784aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 1785d0506edbSNamhyung Kim } 1786d0506edbSNamhyung Kim 178762c95ae3SArnaldo Carvalho de Melo if (row == browser->rows) 1788aca7a94dSNamhyung Kim break; 1789aca7a94dSNamhyung Kim } 1790aca7a94dSNamhyung Kim 1791025bf7eaSArnaldo Carvalho de Melo return row + header_offset; 1792aca7a94dSNamhyung Kim } 1793aca7a94dSNamhyung Kim 1794064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 1795064f1981SNamhyung Kim float min_pcnt) 1796aca7a94dSNamhyung Kim { 1797aca7a94dSNamhyung Kim while (nd != NULL) { 1798aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 179914135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1800064f1981SNamhyung Kim 1801c0f1527bSNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1802aca7a94dSNamhyung Kim return nd; 1803aca7a94dSNamhyung Kim 1804d0506edbSNamhyung Kim /* 1805d0506edbSNamhyung Kim * If it's filtered, its all children also were filtered. 1806d0506edbSNamhyung Kim * So move to sibling node. 1807d0506edbSNamhyung Kim */ 1808d0506edbSNamhyung Kim if (rb_next(nd)) 1809aca7a94dSNamhyung Kim nd = rb_next(nd); 1810d0506edbSNamhyung Kim else 1811d0506edbSNamhyung Kim nd = rb_hierarchy_next(nd); 1812aca7a94dSNamhyung Kim } 1813aca7a94dSNamhyung Kim 1814aca7a94dSNamhyung Kim return NULL; 1815aca7a94dSNamhyung Kim } 1816aca7a94dSNamhyung Kim 1817064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 1818064f1981SNamhyung Kim float min_pcnt) 1819aca7a94dSNamhyung Kim { 1820aca7a94dSNamhyung Kim while (nd != NULL) { 1821aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 182214135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1823064f1981SNamhyung Kim 1824064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1825aca7a94dSNamhyung Kim return nd; 1826aca7a94dSNamhyung Kim 1827d0506edbSNamhyung Kim nd = rb_hierarchy_prev(nd); 1828aca7a94dSNamhyung Kim } 1829aca7a94dSNamhyung Kim 1830aca7a94dSNamhyung Kim return NULL; 1831aca7a94dSNamhyung Kim } 1832aca7a94dSNamhyung Kim 183305e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 1834aca7a94dSNamhyung Kim off_t offset, int whence) 1835aca7a94dSNamhyung Kim { 1836aca7a94dSNamhyung Kim struct hist_entry *h; 1837aca7a94dSNamhyung Kim struct rb_node *nd; 1838aca7a94dSNamhyung Kim bool first = true; 1839064f1981SNamhyung Kim struct hist_browser *hb; 1840064f1981SNamhyung Kim 1841064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1842aca7a94dSNamhyung Kim 184305e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 1844aca7a94dSNamhyung Kim return; 1845aca7a94dSNamhyung Kim 184605e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1847aca7a94dSNamhyung Kim 1848aca7a94dSNamhyung Kim switch (whence) { 1849aca7a94dSNamhyung Kim case SEEK_SET: 1850064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 185114135663SNamhyung Kim hb->min_pcnt); 1852aca7a94dSNamhyung Kim break; 1853aca7a94dSNamhyung Kim case SEEK_CUR: 185405e8b080SArnaldo Carvalho de Melo nd = browser->top; 1855aca7a94dSNamhyung Kim goto do_offset; 1856aca7a94dSNamhyung Kim case SEEK_END: 1857d0506edbSNamhyung Kim nd = rb_hierarchy_last(rb_last(browser->entries)); 1858d0506edbSNamhyung Kim nd = hists__filter_prev_entries(nd, hb->min_pcnt); 1859aca7a94dSNamhyung Kim first = false; 1860aca7a94dSNamhyung Kim break; 1861aca7a94dSNamhyung Kim default: 1862aca7a94dSNamhyung Kim return; 1863aca7a94dSNamhyung Kim } 1864aca7a94dSNamhyung Kim 1865aca7a94dSNamhyung Kim /* 1866aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 1867aca7a94dSNamhyung Kim * row_offset: 1868aca7a94dSNamhyung Kim */ 186905e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 1870aca7a94dSNamhyung Kim h->row_offset = 0; 1871aca7a94dSNamhyung Kim 1872aca7a94dSNamhyung Kim /* 1873aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 1874aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 1875aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 1876aca7a94dSNamhyung Kim * 1877aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 1878aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 1879aca7a94dSNamhyung Kim * 1880aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 1881aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 1882aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 1883aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 1884aca7a94dSNamhyung Kim */ 1885aca7a94dSNamhyung Kim do_offset: 1886837eeb75SWang Nan if (!nd) 1887837eeb75SWang Nan return; 1888837eeb75SWang Nan 1889aca7a94dSNamhyung Kim if (offset > 0) { 1890aca7a94dSNamhyung Kim do { 1891aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1892d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1893aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 1894aca7a94dSNamhyung Kim if (offset > remaining) { 1895aca7a94dSNamhyung Kim offset -= remaining; 1896aca7a94dSNamhyung Kim h->row_offset = 0; 1897aca7a94dSNamhyung Kim } else { 1898aca7a94dSNamhyung Kim h->row_offset += offset; 1899aca7a94dSNamhyung Kim offset = 0; 190005e8b080SArnaldo Carvalho de Melo browser->top = nd; 1901aca7a94dSNamhyung Kim break; 1902aca7a94dSNamhyung Kim } 1903aca7a94dSNamhyung Kim } 1904d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 1905d0506edbSNamhyung Kim hb->min_pcnt); 1906aca7a94dSNamhyung Kim if (nd == NULL) 1907aca7a94dSNamhyung Kim break; 1908aca7a94dSNamhyung Kim --offset; 190905e8b080SArnaldo Carvalho de Melo browser->top = nd; 1910aca7a94dSNamhyung Kim } while (offset != 0); 1911aca7a94dSNamhyung Kim } else if (offset < 0) { 1912aca7a94dSNamhyung Kim while (1) { 1913aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1914d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1915aca7a94dSNamhyung Kim if (first) { 1916aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 1917aca7a94dSNamhyung Kim offset += h->row_offset; 1918aca7a94dSNamhyung Kim h->row_offset = 0; 1919aca7a94dSNamhyung Kim } else { 1920aca7a94dSNamhyung Kim h->row_offset += offset; 1921aca7a94dSNamhyung Kim offset = 0; 192205e8b080SArnaldo Carvalho de Melo browser->top = nd; 1923aca7a94dSNamhyung Kim break; 1924aca7a94dSNamhyung Kim } 1925aca7a94dSNamhyung Kim } else { 1926aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 1927aca7a94dSNamhyung Kim offset += h->nr_rows; 1928aca7a94dSNamhyung Kim h->row_offset = 0; 1929aca7a94dSNamhyung Kim } else { 1930aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 1931aca7a94dSNamhyung Kim offset = 0; 193205e8b080SArnaldo Carvalho de Melo browser->top = nd; 1933aca7a94dSNamhyung Kim break; 1934aca7a94dSNamhyung Kim } 1935aca7a94dSNamhyung Kim } 1936aca7a94dSNamhyung Kim } 1937aca7a94dSNamhyung Kim 1938d0506edbSNamhyung Kim nd = hists__filter_prev_entries(rb_hierarchy_prev(nd), 1939064f1981SNamhyung Kim hb->min_pcnt); 1940aca7a94dSNamhyung Kim if (nd == NULL) 1941aca7a94dSNamhyung Kim break; 1942aca7a94dSNamhyung Kim ++offset; 194305e8b080SArnaldo Carvalho de Melo browser->top = nd; 1944aca7a94dSNamhyung Kim if (offset == 0) { 1945aca7a94dSNamhyung Kim /* 1946aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 1947aca7a94dSNamhyung Kim * unfolded, if it is then we should have 1948aca7a94dSNamhyung Kim * row_offset at its last entry. 1949aca7a94dSNamhyung Kim */ 1950aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1951d0506edbSNamhyung Kim if (h->unfolded && h->leaf) 1952aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 1953aca7a94dSNamhyung Kim break; 1954aca7a94dSNamhyung Kim } 1955aca7a94dSNamhyung Kim first = false; 1956aca7a94dSNamhyung Kim } 1957aca7a94dSNamhyung Kim } else { 195805e8b080SArnaldo Carvalho de Melo browser->top = nd; 1959aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1960aca7a94dSNamhyung Kim h->row_offset = 0; 1961aca7a94dSNamhyung Kim } 1962aca7a94dSNamhyung Kim } 1963aca7a94dSNamhyung Kim 1964aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1965d0506edbSNamhyung Kim struct hist_entry *he, FILE *fp, 1966d0506edbSNamhyung Kim int level) 1967aff3f3f6SArnaldo Carvalho de Melo { 196839ee533fSNamhyung Kim struct callchain_print_arg arg = { 196939ee533fSNamhyung Kim .fp = fp, 197039ee533fSNamhyung Kim }; 1971aff3f3f6SArnaldo Carvalho de Melo 1972d0506edbSNamhyung Kim hist_browser__show_callchain(browser, he, level, 0, 197339ee533fSNamhyung Kim hist_browser__fprintf_callchain_entry, &arg, 197439ee533fSNamhyung Kim hist_browser__check_dump_full); 197539ee533fSNamhyung Kim return arg.printed; 1976aff3f3f6SArnaldo Carvalho de Melo } 1977aff3f3f6SArnaldo Carvalho de Melo 1978aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 1979aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 1980aff3f3f6SArnaldo Carvalho de Melo { 1981aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 1982aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1983aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 198426d8b338SNamhyung Kim struct perf_hpp hpp = { 198526d8b338SNamhyung Kim .buf = s, 198626d8b338SNamhyung Kim .size = sizeof(s), 198726d8b338SNamhyung Kim }; 198826d8b338SNamhyung Kim struct perf_hpp_fmt *fmt; 198926d8b338SNamhyung Kim bool first = true; 199026d8b338SNamhyung Kim int ret; 1991aff3f3f6SArnaldo Carvalho de Melo 19921b6b678eSArnaldo Carvalho de Melo if (symbol_conf.use_callchain) { 1993aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 1994aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 19951b6b678eSArnaldo Carvalho de Melo } 1996aff3f3f6SArnaldo Carvalho de Melo 1997f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 1998361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, he->hists)) 1999e67d49a7SNamhyung Kim continue; 2000e67d49a7SNamhyung Kim 200126d8b338SNamhyung Kim if (!first) { 200226d8b338SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 200326d8b338SNamhyung Kim advance_hpp(&hpp, ret); 200426d8b338SNamhyung Kim } else 200526d8b338SNamhyung Kim first = false; 2006aff3f3f6SArnaldo Carvalho de Melo 200726d8b338SNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 200889fee709SArnaldo Carvalho de Melo ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret); 200926d8b338SNamhyung Kim advance_hpp(&hpp, ret); 201026d8b338SNamhyung Kim } 201189fee709SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", s); 2012aff3f3f6SArnaldo Carvalho de Melo 2013aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 2014d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 1); 2015d0506edbSNamhyung Kim 2016d0506edbSNamhyung Kim return printed; 2017d0506edbSNamhyung Kim } 2018d0506edbSNamhyung Kim 2019d0506edbSNamhyung Kim 2020d0506edbSNamhyung Kim static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser, 2021d0506edbSNamhyung Kim struct hist_entry *he, 2022325a6283SNamhyung Kim FILE *fp, int level) 2023d0506edbSNamhyung Kim { 2024d0506edbSNamhyung Kim char s[8192]; 2025d0506edbSNamhyung Kim int printed = 0; 2026d0506edbSNamhyung Kim char folded_sign = ' '; 2027d0506edbSNamhyung Kim struct perf_hpp hpp = { 2028d0506edbSNamhyung Kim .buf = s, 2029d0506edbSNamhyung Kim .size = sizeof(s), 2030d0506edbSNamhyung Kim }; 2031d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 2032325a6283SNamhyung Kim struct perf_hpp_list_node *fmt_node; 2033d0506edbSNamhyung Kim bool first = true; 2034d0506edbSNamhyung Kim int ret; 2035325a6283SNamhyung Kim int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 2036d0506edbSNamhyung Kim 2037d0506edbSNamhyung Kim printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, ""); 2038d0506edbSNamhyung Kim 2039d0506edbSNamhyung Kim folded_sign = hist_entry__folded(he); 2040d0506edbSNamhyung Kim printed += fprintf(fp, "%c", folded_sign); 2041d0506edbSNamhyung Kim 2042325a6283SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 2043325a6283SNamhyung Kim fmt_node = list_first_entry(&he->hists->hpp_formats, 2044325a6283SNamhyung Kim struct perf_hpp_list_node, list); 2045325a6283SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 2046d0506edbSNamhyung Kim if (!first) { 2047d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 2048d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 2049d0506edbSNamhyung Kim } else 2050d0506edbSNamhyung Kim first = false; 2051d0506edbSNamhyung Kim 2052d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 2053d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 2054d0506edbSNamhyung Kim } 2055d0506edbSNamhyung Kim 2056d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, ""); 2057d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 2058d0506edbSNamhyung Kim 20591b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(he->hpp_list, fmt) { 20601b2dbbf4SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 20611b2dbbf4SNamhyung Kim advance_hpp(&hpp, ret); 20621b2dbbf4SNamhyung Kim 2063d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 2064d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 20651b2dbbf4SNamhyung Kim } 2066d0506edbSNamhyung Kim 2067d0506edbSNamhyung Kim printed += fprintf(fp, "%s\n", rtrim(s)); 2068d0506edbSNamhyung Kim 2069d0506edbSNamhyung Kim if (he->leaf && folded_sign == '-') { 2070d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 2071d0506edbSNamhyung Kim he->depth + 1); 2072d0506edbSNamhyung Kim } 2073aff3f3f6SArnaldo Carvalho de Melo 2074aff3f3f6SArnaldo Carvalho de Melo return printed; 2075aff3f3f6SArnaldo Carvalho de Melo } 2076aff3f3f6SArnaldo Carvalho de Melo 2077aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 2078aff3f3f6SArnaldo Carvalho de Melo { 2079064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 2080064f1981SNamhyung Kim browser->min_pcnt); 2081aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 2082aff3f3f6SArnaldo Carvalho de Melo 2083aff3f3f6SArnaldo Carvalho de Melo while (nd) { 2084aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 2085aff3f3f6SArnaldo Carvalho de Melo 2086d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 2087d0506edbSNamhyung Kim printed += hist_browser__fprintf_hierarchy_entry(browser, 2088d0506edbSNamhyung Kim h, fp, 2089325a6283SNamhyung Kim h->depth); 2090d0506edbSNamhyung Kim } else { 2091aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 2092d0506edbSNamhyung Kim } 2093d0506edbSNamhyung Kim 2094d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 2095d0506edbSNamhyung Kim browser->min_pcnt); 2096aff3f3f6SArnaldo Carvalho de Melo } 2097aff3f3f6SArnaldo Carvalho de Melo 2098aff3f3f6SArnaldo Carvalho de Melo return printed; 2099aff3f3f6SArnaldo Carvalho de Melo } 2100aff3f3f6SArnaldo Carvalho de Melo 2101aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 2102aff3f3f6SArnaldo Carvalho de Melo { 2103aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 2104aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 2105aff3f3f6SArnaldo Carvalho de Melo 2106aff3f3f6SArnaldo Carvalho de Melo while (1) { 2107aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 2108aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 2109aff3f3f6SArnaldo Carvalho de Melo break; 2110aff3f3f6SArnaldo Carvalho de Melo /* 2111aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 2112aff3f3f6SArnaldo Carvalho de Melo */ 2113aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 2114aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 2115aff3f3f6SArnaldo Carvalho de Melo return -1; 2116aff3f3f6SArnaldo Carvalho de Melo } 2117aff3f3f6SArnaldo Carvalho de Melo } 2118aff3f3f6SArnaldo Carvalho de Melo 2119aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 2120aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 2121aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 2122c8b5f2c9SArnaldo Carvalho de Melo const char *err = str_error_r(errno, bf, sizeof(bf)); 21234cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 2124aff3f3f6SArnaldo Carvalho de Melo return -1; 2125aff3f3f6SArnaldo Carvalho de Melo } 2126aff3f3f6SArnaldo Carvalho de Melo 2127aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 2128aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 2129aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 2130aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 2131aff3f3f6SArnaldo Carvalho de Melo 2132aff3f3f6SArnaldo Carvalho de Melo return 0; 2133aff3f3f6SArnaldo Carvalho de Melo } 2134aff3f3f6SArnaldo Carvalho de Melo 2135fcd86426SJiri Olsa void hist_browser__init(struct hist_browser *browser, 2136fcd86426SJiri Olsa struct hists *hists) 2137aca7a94dSNamhyung Kim { 2138b1c7a8f7SJiri Olsa struct perf_hpp_fmt *fmt; 2139b1c7a8f7SJiri Olsa 214005e8b080SArnaldo Carvalho de Melo browser->hists = hists; 214105e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 2142357cfff1SArnaldo Carvalho de Melo browser->b.refresh_dimensions = hist_browser__refresh_dimensions; 214305e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 214405e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 2145c8302367SJiri Olsa browser->show_headers = symbol_conf.show_hist_headers; 2146b1c7a8f7SJiri Olsa 21478a06b0beSNamhyung Kim if (symbol_conf.report_hierarchy) { 21488a06b0beSNamhyung Kim struct perf_hpp_list_node *fmt_node; 21498a06b0beSNamhyung Kim 21508a06b0beSNamhyung Kim /* count overhead columns (in the first node) */ 21518a06b0beSNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 21528a06b0beSNamhyung Kim struct perf_hpp_list_node, list); 21538a06b0beSNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) 21548a06b0beSNamhyung Kim ++browser->b.columns; 21558a06b0beSNamhyung Kim 21568a06b0beSNamhyung Kim /* add a single column for whole hierarchy sort keys*/ 21578a06b0beSNamhyung Kim ++browser->b.columns; 21588a06b0beSNamhyung Kim } else { 2159e3b60bc9SNamhyung Kim hists__for_each_format(hists, fmt) 2160b1c7a8f7SJiri Olsa ++browser->b.columns; 21618a06b0beSNamhyung Kim } 2162e3b60bc9SNamhyung Kim 2163e3b60bc9SNamhyung Kim hists__reset_column_width(hists); 2164aca7a94dSNamhyung Kim } 2165aca7a94dSNamhyung Kim 2166fcd86426SJiri Olsa struct hist_browser *hist_browser__new(struct hists *hists) 2167fcd86426SJiri Olsa { 2168fcd86426SJiri Olsa struct hist_browser *browser = zalloc(sizeof(*browser)); 2169fcd86426SJiri Olsa 2170fcd86426SJiri Olsa if (browser) 2171fcd86426SJiri Olsa hist_browser__init(browser, hists); 2172fcd86426SJiri Olsa 217305e8b080SArnaldo Carvalho de Melo return browser; 2174aca7a94dSNamhyung Kim } 2175aca7a94dSNamhyung Kim 2176a6ec894dSJiri Olsa static struct hist_browser * 2177a6ec894dSJiri Olsa perf_evsel_browser__new(struct perf_evsel *evsel, 2178a6ec894dSJiri Olsa struct hist_browser_timer *hbt, 2179a6ec894dSJiri Olsa struct perf_env *env) 2180a6ec894dSJiri Olsa { 2181a6ec894dSJiri Olsa struct hist_browser *browser = hist_browser__new(evsel__hists(evsel)); 2182a6ec894dSJiri Olsa 2183a6ec894dSJiri Olsa if (browser) { 2184a6ec894dSJiri Olsa browser->hbt = hbt; 2185a6ec894dSJiri Olsa browser->env = env; 2186a6ec894dSJiri Olsa browser->title = perf_evsel_browser_title; 2187a6ec894dSJiri Olsa } 2188a6ec894dSJiri Olsa return browser; 2189a6ec894dSJiri Olsa } 2190a6ec894dSJiri Olsa 2191dabd2012SJiri Olsa void hist_browser__delete(struct hist_browser *browser) 2192aca7a94dSNamhyung Kim { 219305e8b080SArnaldo Carvalho de Melo free(browser); 2194aca7a94dSNamhyung Kim } 2195aca7a94dSNamhyung Kim 219605e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 2197aca7a94dSNamhyung Kim { 219805e8b080SArnaldo Carvalho de Melo return browser->he_selection; 2199aca7a94dSNamhyung Kim } 2200aca7a94dSNamhyung Kim 220105e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 2202aca7a94dSNamhyung Kim { 220305e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 2204aca7a94dSNamhyung Kim } 2205aca7a94dSNamhyung Kim 22061e378ebdSTaeung Song /* Check whether the browser is for 'top' or 'report' */ 22071e378ebdSTaeung Song static inline bool is_report_browser(void *timer) 22081e378ebdSTaeung Song { 22091e378ebdSTaeung Song return timer == NULL; 22101e378ebdSTaeung Song } 22111e378ebdSTaeung Song 22125b91a86fSJiri Olsa static int perf_evsel_browser_title(struct hist_browser *browser, 22131e378ebdSTaeung Song char *bf, size_t size) 2214aca7a94dSNamhyung Kim { 22155b91a86fSJiri Olsa struct hist_browser_timer *hbt = browser->hbt; 22165b91a86fSJiri Olsa struct hists *hists = browser->hists; 2217aca7a94dSNamhyung Kim char unit; 2218aca7a94dSNamhyung Kim int printed; 221905e8b080SArnaldo Carvalho de Melo const struct dso *dso = hists->dso_filter; 222005e8b080SArnaldo Carvalho de Melo const struct thread *thread = hists->thread_filter; 222184734b06SKan Liang int socket_id = hists->socket_filter; 222205e8b080SArnaldo Carvalho de Melo unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 222305e8b080SArnaldo Carvalho de Melo u64 nr_events = hists->stats.total_period; 2224717e263fSNamhyung Kim struct perf_evsel *evsel = hists_to_evsel(hists); 2225dd00d486SJiri Olsa const char *ev_name = perf_evsel__name(evsel); 2226717e263fSNamhyung Kim char buf[512]; 2227717e263fSNamhyung Kim size_t buflen = sizeof(buf); 22289e207ddfSKan Liang char ref[30] = " show reference callgraph, "; 22299e207ddfSKan Liang bool enable_ref = false; 2230717e263fSNamhyung Kim 2231f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 2232f2148330SNamhyung Kim nr_samples = hists->stats.nr_non_filtered_samples; 2233f2148330SNamhyung Kim nr_events = hists->stats.total_non_filtered_period; 2234f2148330SNamhyung Kim } 2235f2148330SNamhyung Kim 2236759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 2237717e263fSNamhyung Kim struct perf_evsel *pos; 2238717e263fSNamhyung Kim 2239717e263fSNamhyung Kim perf_evsel__group_desc(evsel, buf, buflen); 2240717e263fSNamhyung Kim ev_name = buf; 2241717e263fSNamhyung Kim 2242717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 22434ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 22444ea062edSArnaldo Carvalho de Melo 2245f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 22464ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_non_filtered_samples; 22474ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_non_filtered_period; 2248f2148330SNamhyung Kim } else { 22494ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 22504ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_period; 2251717e263fSNamhyung Kim } 2252717e263fSNamhyung Kim } 2253f2148330SNamhyung Kim } 2254aca7a94dSNamhyung Kim 22559e207ddfSKan Liang if (symbol_conf.show_ref_callgraph && 22569e207ddfSKan Liang strstr(ev_name, "call-graph=no")) 22579e207ddfSKan Liang enable_ref = true; 2258aca7a94dSNamhyung Kim nr_samples = convert_unit(nr_samples, &unit); 2259aca7a94dSNamhyung Kim printed = scnprintf(bf, size, 22609e207ddfSKan Liang "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64, 22619e207ddfSKan Liang nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events); 2262aca7a94dSNamhyung Kim 2263aca7a94dSNamhyung Kim 226405e8b080SArnaldo Carvalho de Melo if (hists->uid_filter_str) 2265aca7a94dSNamhyung Kim printed += snprintf(bf + printed, size - printed, 226605e8b080SArnaldo Carvalho de Melo ", UID: %s", hists->uid_filter_str); 22676962ccb3SNamhyung Kim if (thread) { 2268fa82911aSJiri Olsa if (hists__has(hists, thread)) { 2269aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 2270aca7a94dSNamhyung Kim ", Thread: %s(%d)", 2271b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 227238051234SAdrian Hunter thread->tid); 22736962ccb3SNamhyung Kim } else { 22746962ccb3SNamhyung Kim printed += scnprintf(bf + printed, size - printed, 22756962ccb3SNamhyung Kim ", Thread: %s", 22766962ccb3SNamhyung Kim (thread->comm_set ? thread__comm_str(thread) : "")); 22776962ccb3SNamhyung Kim } 22786962ccb3SNamhyung Kim } 2279aca7a94dSNamhyung Kim if (dso) 2280aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 2281aca7a94dSNamhyung Kim ", DSO: %s", dso->short_name); 228284734b06SKan Liang if (socket_id > -1) 228321394d94SKan Liang printed += scnprintf(bf + printed, size - printed, 228484734b06SKan Liang ", Processor Socket: %d", socket_id); 22851e378ebdSTaeung Song if (!is_report_browser(hbt)) { 22861e378ebdSTaeung Song struct perf_top *top = hbt->arg; 22871e378ebdSTaeung Song 22881e378ebdSTaeung Song if (top->zero) 22891e378ebdSTaeung Song printed += scnprintf(bf + printed, size - printed, " [z]"); 22901e378ebdSTaeung Song } 22911e378ebdSTaeung Song 2292aca7a94dSNamhyung Kim return printed; 2293aca7a94dSNamhyung Kim } 2294aca7a94dSNamhyung Kim 2295aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 2296aca7a94dSNamhyung Kim { 2297aca7a94dSNamhyung Kim int i; 2298aca7a94dSNamhyung Kim 229904662523SArnaldo Carvalho de Melo for (i = 0; i < n; ++i) 230004662523SArnaldo Carvalho de Melo zfree(&options[i]); 2301aca7a94dSNamhyung Kim } 2302aca7a94dSNamhyung Kim 2303341487abSFeng Tang /* 2304341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 2305341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 2306341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 2307341487abSFeng Tang */ 2308341487abSFeng Tang static bool is_input_name_malloced = false; 2309341487abSFeng Tang 2310341487abSFeng Tang static int switch_data_file(void) 2311341487abSFeng Tang { 2312341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 2313341487abSFeng Tang DIR *pwd_dir; 2314341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 2315341487abSFeng Tang struct dirent *dent; 2316341487abSFeng Tang 2317341487abSFeng Tang pwd = getenv("PWD"); 2318341487abSFeng Tang if (!pwd) 2319341487abSFeng Tang return ret; 2320341487abSFeng Tang 2321341487abSFeng Tang pwd_dir = opendir(pwd); 2322341487abSFeng Tang if (!pwd_dir) 2323341487abSFeng Tang return ret; 2324341487abSFeng Tang 2325341487abSFeng Tang memset(options, 0, sizeof(options)); 23263ef5b402SChangbin Du memset(abs_path, 0, sizeof(abs_path)); 2327341487abSFeng Tang 2328341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 2329341487abSFeng Tang char path[PATH_MAX]; 2330341487abSFeng Tang u64 magic; 2331341487abSFeng Tang char *name = dent->d_name; 2332341487abSFeng Tang FILE *file; 2333341487abSFeng Tang 2334341487abSFeng Tang if (!(dent->d_type == DT_REG)) 2335341487abSFeng Tang continue; 2336341487abSFeng Tang 2337341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 2338341487abSFeng Tang 2339341487abSFeng Tang file = fopen(path, "r"); 2340341487abSFeng Tang if (!file) 2341341487abSFeng Tang continue; 2342341487abSFeng Tang 2343341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 2344341487abSFeng Tang goto close_file_and_continue; 2345341487abSFeng Tang 2346341487abSFeng Tang if (is_perf_magic(magic)) { 2347341487abSFeng Tang options[nr_options] = strdup(name); 2348341487abSFeng Tang if (!options[nr_options]) 2349341487abSFeng Tang goto close_file_and_continue; 2350341487abSFeng Tang 2351341487abSFeng Tang abs_path[nr_options] = strdup(path); 2352341487abSFeng Tang if (!abs_path[nr_options]) { 235374cf249dSArnaldo Carvalho de Melo zfree(&options[nr_options]); 2354341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 2355341487abSFeng Tang fclose(file); 2356341487abSFeng Tang break; 2357341487abSFeng Tang } 2358341487abSFeng Tang 2359341487abSFeng Tang nr_options++; 2360341487abSFeng Tang } 2361341487abSFeng Tang 2362341487abSFeng Tang close_file_and_continue: 2363341487abSFeng Tang fclose(file); 2364341487abSFeng Tang if (nr_options >= 32) { 2365341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 2366341487abSFeng Tang "Only the first 32 files will be listed.\n"); 2367341487abSFeng Tang break; 2368341487abSFeng Tang } 2369341487abSFeng Tang } 2370341487abSFeng Tang closedir(pwd_dir); 2371341487abSFeng Tang 2372341487abSFeng Tang if (nr_options) { 2373341487abSFeng Tang choice = ui__popup_menu(nr_options, options); 2374341487abSFeng Tang if (choice < nr_options && choice >= 0) { 2375341487abSFeng Tang tmp = strdup(abs_path[choice]); 2376341487abSFeng Tang if (tmp) { 2377341487abSFeng Tang if (is_input_name_malloced) 2378341487abSFeng Tang free((void *)input_name); 2379341487abSFeng Tang input_name = tmp; 2380341487abSFeng Tang is_input_name_malloced = true; 2381341487abSFeng Tang ret = 0; 2382341487abSFeng Tang } else 2383341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 2384341487abSFeng Tang } 2385341487abSFeng Tang } 2386341487abSFeng Tang 2387341487abSFeng Tang free_popup_options(options, nr_options); 2388341487abSFeng Tang free_popup_options(abs_path, nr_options); 2389341487abSFeng Tang return ret; 2390341487abSFeng Tang } 2391341487abSFeng Tang 2392ea7cd592SNamhyung Kim struct popup_action { 2393ea7cd592SNamhyung Kim struct thread *thread; 2394ea7cd592SNamhyung Kim struct map_symbol ms; 239584734b06SKan Liang int socket; 2396ea7cd592SNamhyung Kim 2397ea7cd592SNamhyung Kim int (*fn)(struct hist_browser *browser, struct popup_action *act); 2398ea7cd592SNamhyung Kim }; 2399ea7cd592SNamhyung Kim 2400bc7cad42SNamhyung Kim static int 2401ea7cd592SNamhyung Kim do_annotate(struct hist_browser *browser, struct popup_action *act) 2402bc7cad42SNamhyung Kim { 2403bc7cad42SNamhyung Kim struct perf_evsel *evsel; 2404bc7cad42SNamhyung Kim struct annotation *notes; 2405bc7cad42SNamhyung Kim struct hist_entry *he; 2406bc7cad42SNamhyung Kim int err; 2407bc7cad42SNamhyung Kim 2408eebd0bfcSArnaldo Carvalho de Melo if (!objdump_path && perf_env__lookup_objdump(browser->env)) 2409bc7cad42SNamhyung Kim return 0; 2410bc7cad42SNamhyung Kim 2411ea7cd592SNamhyung Kim notes = symbol__annotation(act->ms.sym); 2412bc7cad42SNamhyung Kim if (!notes->src) 2413bc7cad42SNamhyung Kim return 0; 2414bc7cad42SNamhyung Kim 2415bc7cad42SNamhyung Kim evsel = hists_to_evsel(browser->hists); 2416ea7cd592SNamhyung Kim err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); 2417bc7cad42SNamhyung Kim he = hist_browser__selected_entry(browser); 2418bc7cad42SNamhyung Kim /* 2419bc7cad42SNamhyung Kim * offer option to annotate the other branch source or target 2420bc7cad42SNamhyung Kim * (if they exists) when returning from annotate 2421bc7cad42SNamhyung Kim */ 2422bc7cad42SNamhyung Kim if ((err == 'q' || err == CTRL('c')) && he->branch_info) 2423bc7cad42SNamhyung Kim return 1; 2424bc7cad42SNamhyung Kim 2425bc7cad42SNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 2426bc7cad42SNamhyung Kim if (err) 2427bc7cad42SNamhyung Kim ui_browser__handle_resize(&browser->b); 2428bc7cad42SNamhyung Kim return 0; 2429bc7cad42SNamhyung Kim } 2430bc7cad42SNamhyung Kim 2431bc7cad42SNamhyung Kim static int 2432ea7cd592SNamhyung Kim add_annotate_opt(struct hist_browser *browser __maybe_unused, 2433ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 2434ea7cd592SNamhyung Kim struct map *map, struct symbol *sym) 2435bc7cad42SNamhyung Kim { 2436ea7cd592SNamhyung Kim if (sym == NULL || map->dso->annotate_warned) 2437ea7cd592SNamhyung Kim return 0; 2438ea7cd592SNamhyung Kim 2439ea7cd592SNamhyung Kim if (asprintf(optstr, "Annotate %s", sym->name) < 0) 2440ea7cd592SNamhyung Kim return 0; 2441ea7cd592SNamhyung Kim 2442ea7cd592SNamhyung Kim act->ms.map = map; 2443ea7cd592SNamhyung Kim act->ms.sym = sym; 2444ea7cd592SNamhyung Kim act->fn = do_annotate; 2445ea7cd592SNamhyung Kim return 1; 2446ea7cd592SNamhyung Kim } 2447ea7cd592SNamhyung Kim 2448ea7cd592SNamhyung Kim static int 2449ea7cd592SNamhyung Kim do_zoom_thread(struct hist_browser *browser, struct popup_action *act) 2450ea7cd592SNamhyung Kim { 2451ea7cd592SNamhyung Kim struct thread *thread = act->thread; 2452ea7cd592SNamhyung Kim 24537cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 24547cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2455599a2f38SNamhyung Kim return 0; 2456599a2f38SNamhyung Kim 2457bc7cad42SNamhyung Kim if (browser->hists->thread_filter) { 2458bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->thread_filter); 2459bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2460bc7cad42SNamhyung Kim thread__zput(browser->hists->thread_filter); 2461bc7cad42SNamhyung Kim ui_helpline__pop(); 2462bc7cad42SNamhyung Kim } else { 2463fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 24647727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 2465bc7cad42SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 2466bc7cad42SNamhyung Kim thread->tid); 24676962ccb3SNamhyung Kim } else { 24686962ccb3SNamhyung Kim ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"", 24696962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 24706962ccb3SNamhyung Kim } 24716962ccb3SNamhyung Kim 2472bc7cad42SNamhyung Kim browser->hists->thread_filter = thread__get(thread); 2473bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2474bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->thread_filter); 2475bc7cad42SNamhyung Kim } 2476bc7cad42SNamhyung Kim 2477bc7cad42SNamhyung Kim hists__filter_by_thread(browser->hists); 2478bc7cad42SNamhyung Kim hist_browser__reset(browser); 2479bc7cad42SNamhyung Kim return 0; 2480bc7cad42SNamhyung Kim } 2481bc7cad42SNamhyung Kim 2482bc7cad42SNamhyung Kim static int 2483ea7cd592SNamhyung Kim add_thread_opt(struct hist_browser *browser, struct popup_action *act, 2484ea7cd592SNamhyung Kim char **optstr, struct thread *thread) 2485bc7cad42SNamhyung Kim { 24866962ccb3SNamhyung Kim int ret; 24876962ccb3SNamhyung Kim 24887cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 24897cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2490ea7cd592SNamhyung Kim return 0; 2491ea7cd592SNamhyung Kim 2492fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 24936962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s(%d) thread", 2494ea7cd592SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 2495ea7cd592SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 24966962ccb3SNamhyung Kim thread->tid); 24976962ccb3SNamhyung Kim } else { 24986962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s thread", 24996962ccb3SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 25006962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 25016962ccb3SNamhyung Kim } 25026962ccb3SNamhyung Kim if (ret < 0) 2503ea7cd592SNamhyung Kim return 0; 2504ea7cd592SNamhyung Kim 2505ea7cd592SNamhyung Kim act->thread = thread; 2506ea7cd592SNamhyung Kim act->fn = do_zoom_thread; 2507ea7cd592SNamhyung Kim return 1; 2508ea7cd592SNamhyung Kim } 2509ea7cd592SNamhyung Kim 2510ea7cd592SNamhyung Kim static int 2511ea7cd592SNamhyung Kim do_zoom_dso(struct hist_browser *browser, struct popup_action *act) 2512ea7cd592SNamhyung Kim { 2513045b80ddSArnaldo Carvalho de Melo struct map *map = act->ms.map; 2514ea7cd592SNamhyung Kim 251569849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2516599a2f38SNamhyung Kim return 0; 2517599a2f38SNamhyung Kim 2518bc7cad42SNamhyung Kim if (browser->hists->dso_filter) { 2519bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->dso_filter); 2520bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, false); 2521bc7cad42SNamhyung Kim browser->hists->dso_filter = NULL; 2522bc7cad42SNamhyung Kim ui_helpline__pop(); 2523bc7cad42SNamhyung Kim } else { 25247727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", 2525045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); 2526045b80ddSArnaldo Carvalho de Melo browser->hists->dso_filter = map->dso; 2527bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, true); 2528bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->dso_filter); 2529bc7cad42SNamhyung Kim } 2530bc7cad42SNamhyung Kim 2531bc7cad42SNamhyung Kim hists__filter_by_dso(browser->hists); 2532bc7cad42SNamhyung Kim hist_browser__reset(browser); 2533bc7cad42SNamhyung Kim return 0; 2534bc7cad42SNamhyung Kim } 2535bc7cad42SNamhyung Kim 2536bc7cad42SNamhyung Kim static int 2537ea7cd592SNamhyung Kim add_dso_opt(struct hist_browser *browser, struct popup_action *act, 2538045b80ddSArnaldo Carvalho de Melo char **optstr, struct map *map) 2539bc7cad42SNamhyung Kim { 254069849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2541ea7cd592SNamhyung Kim return 0; 2542ea7cd592SNamhyung Kim 2543ea7cd592SNamhyung Kim if (asprintf(optstr, "Zoom %s %s DSO", 2544ea7cd592SNamhyung Kim browser->hists->dso_filter ? "out of" : "into", 2545045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) 2546ea7cd592SNamhyung Kim return 0; 2547ea7cd592SNamhyung Kim 2548045b80ddSArnaldo Carvalho de Melo act->ms.map = map; 2549ea7cd592SNamhyung Kim act->fn = do_zoom_dso; 2550ea7cd592SNamhyung Kim return 1; 2551ea7cd592SNamhyung Kim } 2552ea7cd592SNamhyung Kim 2553ea7cd592SNamhyung Kim static int 2554ea7cd592SNamhyung Kim do_browse_map(struct hist_browser *browser __maybe_unused, 2555ea7cd592SNamhyung Kim struct popup_action *act) 2556ea7cd592SNamhyung Kim { 2557ea7cd592SNamhyung Kim map__browse(act->ms.map); 2558bc7cad42SNamhyung Kim return 0; 2559bc7cad42SNamhyung Kim } 2560bc7cad42SNamhyung Kim 2561bc7cad42SNamhyung Kim static int 256269849fc5SJiri Olsa add_map_opt(struct hist_browser *browser, 2563ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, struct map *map) 2564ea7cd592SNamhyung Kim { 256569849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2566ea7cd592SNamhyung Kim return 0; 2567ea7cd592SNamhyung Kim 2568ea7cd592SNamhyung Kim if (asprintf(optstr, "Browse map details") < 0) 2569ea7cd592SNamhyung Kim return 0; 2570ea7cd592SNamhyung Kim 2571ea7cd592SNamhyung Kim act->ms.map = map; 2572ea7cd592SNamhyung Kim act->fn = do_browse_map; 2573ea7cd592SNamhyung Kim return 1; 2574ea7cd592SNamhyung Kim } 2575ea7cd592SNamhyung Kim 2576ea7cd592SNamhyung Kim static int 2577bc7cad42SNamhyung Kim do_run_script(struct hist_browser *browser __maybe_unused, 2578ea7cd592SNamhyung Kim struct popup_action *act) 2579bc7cad42SNamhyung Kim { 2580bc7cad42SNamhyung Kim char script_opt[64]; 2581bc7cad42SNamhyung Kim memset(script_opt, 0, sizeof(script_opt)); 2582bc7cad42SNamhyung Kim 2583ea7cd592SNamhyung Kim if (act->thread) { 2584bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -c %s ", 2585ea7cd592SNamhyung Kim thread__comm_str(act->thread)); 2586ea7cd592SNamhyung Kim } else if (act->ms.sym) { 2587bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -S %s ", 2588ea7cd592SNamhyung Kim act->ms.sym->name); 2589bc7cad42SNamhyung Kim } 2590bc7cad42SNamhyung Kim 2591bc7cad42SNamhyung Kim script_browse(script_opt); 2592bc7cad42SNamhyung Kim return 0; 2593bc7cad42SNamhyung Kim } 2594bc7cad42SNamhyung Kim 2595bc7cad42SNamhyung Kim static int 2596ea7cd592SNamhyung Kim add_script_opt(struct hist_browser *browser __maybe_unused, 2597ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 2598ea7cd592SNamhyung Kim struct thread *thread, struct symbol *sym) 2599ea7cd592SNamhyung Kim { 2600ea7cd592SNamhyung Kim if (thread) { 2601ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of thread [%s]", 2602ea7cd592SNamhyung Kim thread__comm_str(thread)) < 0) 2603ea7cd592SNamhyung Kim return 0; 2604ea7cd592SNamhyung Kim } else if (sym) { 2605ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of symbol [%s]", 2606ea7cd592SNamhyung Kim sym->name) < 0) 2607ea7cd592SNamhyung Kim return 0; 2608ea7cd592SNamhyung Kim } else { 2609ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for all samples") < 0) 2610ea7cd592SNamhyung Kim return 0; 2611ea7cd592SNamhyung Kim } 2612ea7cd592SNamhyung Kim 2613ea7cd592SNamhyung Kim act->thread = thread; 2614ea7cd592SNamhyung Kim act->ms.sym = sym; 2615ea7cd592SNamhyung Kim act->fn = do_run_script; 2616ea7cd592SNamhyung Kim return 1; 2617ea7cd592SNamhyung Kim } 2618ea7cd592SNamhyung Kim 2619ea7cd592SNamhyung Kim static int 2620ea7cd592SNamhyung Kim do_switch_data(struct hist_browser *browser __maybe_unused, 2621ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2622bc7cad42SNamhyung Kim { 2623bc7cad42SNamhyung Kim if (switch_data_file()) { 2624bc7cad42SNamhyung Kim ui__warning("Won't switch the data files due to\n" 2625bc7cad42SNamhyung Kim "no valid data file get selected!\n"); 2626ea7cd592SNamhyung Kim return 0; 2627bc7cad42SNamhyung Kim } 2628bc7cad42SNamhyung Kim 2629bc7cad42SNamhyung Kim return K_SWITCH_INPUT_DATA; 2630bc7cad42SNamhyung Kim } 2631bc7cad42SNamhyung Kim 2632ea7cd592SNamhyung Kim static int 2633ea7cd592SNamhyung Kim add_switch_opt(struct hist_browser *browser, 2634ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2635ea7cd592SNamhyung Kim { 2636ea7cd592SNamhyung Kim if (!is_report_browser(browser->hbt)) 2637ea7cd592SNamhyung Kim return 0; 2638ea7cd592SNamhyung Kim 2639ea7cd592SNamhyung Kim if (asprintf(optstr, "Switch to another data file in PWD") < 0) 2640ea7cd592SNamhyung Kim return 0; 2641ea7cd592SNamhyung Kim 2642ea7cd592SNamhyung Kim act->fn = do_switch_data; 2643ea7cd592SNamhyung Kim return 1; 2644ea7cd592SNamhyung Kim } 2645ea7cd592SNamhyung Kim 2646ea7cd592SNamhyung Kim static int 2647ea7cd592SNamhyung Kim do_exit_browser(struct hist_browser *browser __maybe_unused, 2648ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2649ea7cd592SNamhyung Kim { 2650ea7cd592SNamhyung Kim return 0; 2651ea7cd592SNamhyung Kim } 2652ea7cd592SNamhyung Kim 2653ea7cd592SNamhyung Kim static int 2654ea7cd592SNamhyung Kim add_exit_opt(struct hist_browser *browser __maybe_unused, 2655ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2656ea7cd592SNamhyung Kim { 2657ea7cd592SNamhyung Kim if (asprintf(optstr, "Exit") < 0) 2658ea7cd592SNamhyung Kim return 0; 2659ea7cd592SNamhyung Kim 2660ea7cd592SNamhyung Kim act->fn = do_exit_browser; 2661ea7cd592SNamhyung Kim return 1; 2662ea7cd592SNamhyung Kim } 2663ea7cd592SNamhyung Kim 266484734b06SKan Liang static int 266584734b06SKan Liang do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 266684734b06SKan Liang { 266735a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || act->socket < 0) 2668599a2f38SNamhyung Kim return 0; 2669599a2f38SNamhyung Kim 267084734b06SKan Liang if (browser->hists->socket_filter > -1) { 267184734b06SKan Liang pstack__remove(browser->pstack, &browser->hists->socket_filter); 267284734b06SKan Liang browser->hists->socket_filter = -1; 267384734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, false); 267484734b06SKan Liang } else { 267584734b06SKan Liang browser->hists->socket_filter = act->socket; 267684734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, true); 267784734b06SKan Liang pstack__push(browser->pstack, &browser->hists->socket_filter); 267884734b06SKan Liang } 267984734b06SKan Liang 268084734b06SKan Liang hists__filter_by_socket(browser->hists); 268184734b06SKan Liang hist_browser__reset(browser); 268284734b06SKan Liang return 0; 268384734b06SKan Liang } 268484734b06SKan Liang 268584734b06SKan Liang static int 268684734b06SKan Liang add_socket_opt(struct hist_browser *browser, struct popup_action *act, 268784734b06SKan Liang char **optstr, int socket_id) 268884734b06SKan Liang { 268935a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || socket_id < 0) 269084734b06SKan Liang return 0; 269184734b06SKan Liang 269284734b06SKan Liang if (asprintf(optstr, "Zoom %s Processor Socket %d", 269384734b06SKan Liang (browser->hists->socket_filter > -1) ? "out of" : "into", 269484734b06SKan Liang socket_id) < 0) 269584734b06SKan Liang return 0; 269684734b06SKan Liang 269784734b06SKan Liang act->socket = socket_id; 269884734b06SKan Liang act->fn = do_zoom_socket; 269984734b06SKan Liang return 1; 270084734b06SKan Liang } 270184734b06SKan Liang 2702112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb) 2703064f1981SNamhyung Kim { 2704064f1981SNamhyung Kim u64 nr_entries = 0; 2705064f1981SNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 2706064f1981SNamhyung Kim 2707f5b763feSNamhyung Kim if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) { 2708268397cbSNamhyung Kim hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 2709268397cbSNamhyung Kim return; 2710268397cbSNamhyung Kim } 2711268397cbSNamhyung Kim 271214135663SNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2713064f1981SNamhyung Kim nr_entries++; 2714f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd); 2715064f1981SNamhyung Kim } 2716064f1981SNamhyung Kim 2717112f761fSNamhyung Kim hb->nr_non_filtered_entries = nr_entries; 2718f5b763feSNamhyung Kim hb->nr_hierarchy_entries = nr_entries; 2719064f1981SNamhyung Kim } 2720341487abSFeng Tang 2721b62e8dfcSNamhyung Kim static void hist_browser__update_percent_limit(struct hist_browser *hb, 2722b62e8dfcSNamhyung Kim double percent) 2723b62e8dfcSNamhyung Kim { 2724b62e8dfcSNamhyung Kim struct hist_entry *he; 2725b62e8dfcSNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 2726b62e8dfcSNamhyung Kim u64 total = hists__total_period(hb->hists); 2727b62e8dfcSNamhyung Kim u64 min_callchain_hits = total * (percent / 100); 2728b62e8dfcSNamhyung Kim 2729b62e8dfcSNamhyung Kim hb->min_pcnt = callchain_param.min_percent = percent; 2730b62e8dfcSNamhyung Kim 2731b62e8dfcSNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2732b62e8dfcSNamhyung Kim he = rb_entry(nd, struct hist_entry, rb_node); 2733b62e8dfcSNamhyung Kim 273479dded87SNamhyung Kim if (he->has_no_entry) { 273579dded87SNamhyung Kim he->has_no_entry = false; 273679dded87SNamhyung Kim he->nr_rows = 0; 273779dded87SNamhyung Kim } 273879dded87SNamhyung Kim 2739d0506edbSNamhyung Kim if (!he->leaf || !symbol_conf.use_callchain) 2740d0506edbSNamhyung Kim goto next; 2741d0506edbSNamhyung Kim 2742b62e8dfcSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) { 2743b62e8dfcSNamhyung Kim total = he->stat.period; 2744b62e8dfcSNamhyung Kim 2745b62e8dfcSNamhyung Kim if (symbol_conf.cumulate_callchain) 2746b62e8dfcSNamhyung Kim total = he->stat_acc->period; 2747b62e8dfcSNamhyung Kim 2748b62e8dfcSNamhyung Kim min_callchain_hits = total * (percent / 100); 2749b62e8dfcSNamhyung Kim } 2750b62e8dfcSNamhyung Kim 2751b62e8dfcSNamhyung Kim callchain_param.sort(&he->sorted_chain, he->callchain, 2752b62e8dfcSNamhyung Kim min_callchain_hits, &callchain_param); 2753b62e8dfcSNamhyung Kim 2754d0506edbSNamhyung Kim next: 2755201fde73SNamhyung Kim nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 2756d0506edbSNamhyung Kim 2757b62e8dfcSNamhyung Kim /* force to re-evaluate folding state of callchains */ 2758b62e8dfcSNamhyung Kim he->init_have_children = false; 2759492b1010SNamhyung Kim hist_entry__set_folding(he, hb, false); 2760b62e8dfcSNamhyung Kim } 2761b62e8dfcSNamhyung Kim } 2762b62e8dfcSNamhyung Kim 2763aca7a94dSNamhyung Kim static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 2764dd00d486SJiri Olsa const char *helpline, 2765aca7a94dSNamhyung Kim bool left_exits, 276668d80758SNamhyung Kim struct hist_browser_timer *hbt, 2767064f1981SNamhyung Kim float min_pcnt, 2768*06cc1a47SKan Liang struct perf_env *env, 2769*06cc1a47SKan Liang bool warn_lost_event) 2770aca7a94dSNamhyung Kim { 27714ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 2772a6ec894dSJiri Olsa struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); 2773aca7a94dSNamhyung Kim struct branch_info *bi; 2774f2b487dbSNamhyung Kim #define MAX_OPTIONS 16 2775f2b487dbSNamhyung Kim char *options[MAX_OPTIONS]; 2776ea7cd592SNamhyung Kim struct popup_action actions[MAX_OPTIONS]; 2777aca7a94dSNamhyung Kim int nr_options = 0; 2778aca7a94dSNamhyung Kim int key = -1; 2779aca7a94dSNamhyung Kim char buf[64]; 27809783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 2781aca7a94dSNamhyung Kim 2782e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 2783e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 2784e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 2785e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 2786e8e684a5SNamhyung Kim "q/ESC/CTRL+C Exit browser\n\n" \ 2787e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 2788e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 2789e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 27907727a925SArnaldo Carvalho de Melo "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \ 27917727a925SArnaldo Carvalho de Melo "ESC Zoom out\n" \ 2792e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 2793e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 2794e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 2795e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 2796105eb30fSNamhyung Kim "F Toggle percentage of filtered entries\n" \ 2797025bf7eaSArnaldo Carvalho de Melo "H Display column headers\n" \ 2798b62e8dfcSNamhyung Kim "L Change percent limit\n" \ 279931eb4360SNamhyung Kim "m Display context menu\n" \ 280084734b06SKan Liang "S Zoom into current Processor Socket\n" \ 2801e8e684a5SNamhyung Kim 2802e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 2803e8e684a5SNamhyung Kim const char report_help[] = HIST_BROWSER_HELP_COMMON 28046dd60135SNamhyung Kim "i Show header information\n" 2805e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2806e8e684a5SNamhyung Kim "r Run available scripts\n" 2807e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 2808e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2809e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 2810e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2811e8e684a5SNamhyung Kim const char top_help[] = HIST_BROWSER_HELP_COMMON 2812e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2813e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2814e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 281542337a22SNamhyung Kim "z Toggle zeroing of samples\n" 2816fbb7997eSArnaldo Carvalho de Melo "f Enable/Disable events\n" 2817e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2818e8e684a5SNamhyung Kim 2819aca7a94dSNamhyung Kim if (browser == NULL) 2820aca7a94dSNamhyung Kim return -1; 2821aca7a94dSNamhyung Kim 2822ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 2823ed426915SNamhyung Kim SLang_reset_tty(); 2824ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 2825ed426915SNamhyung Kim 282603905048SNamhyung Kim if (min_pcnt) 2827064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 2828112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 2829064f1981SNamhyung Kim 283084734b06SKan Liang browser->pstack = pstack__new(3); 283101f00a1cSNamhyung Kim if (browser->pstack == NULL) 2832aca7a94dSNamhyung Kim goto out; 2833aca7a94dSNamhyung Kim 2834aca7a94dSNamhyung Kim ui_helpline__push(helpline); 2835aca7a94dSNamhyung Kim 2836aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 2837ea7cd592SNamhyung Kim memset(actions, 0, sizeof(actions)); 2838aca7a94dSNamhyung Kim 28395b591669SNamhyung Kim if (symbol_conf.col_width_list_str) 28405b591669SNamhyung Kim perf_hpp__set_user_width(symbol_conf.col_width_list_str); 28415b591669SNamhyung Kim 2842aca7a94dSNamhyung Kim while (1) { 2843f3b623b8SArnaldo Carvalho de Melo struct thread *thread = NULL; 2844045b80ddSArnaldo Carvalho de Melo struct map *map = NULL; 2845ea7cd592SNamhyung Kim int choice = 0; 284684734b06SKan Liang int socked_id = -1; 2847aca7a94dSNamhyung Kim 2848aca7a94dSNamhyung Kim nr_options = 0; 2849aca7a94dSNamhyung Kim 2850*06cc1a47SKan Liang key = hist_browser__run(browser, helpline, 2851*06cc1a47SKan Liang warn_lost_event); 2852aca7a94dSNamhyung Kim 2853aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 2854aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 2855045b80ddSArnaldo Carvalho de Melo map = browser->selection->map; 285684734b06SKan Liang socked_id = browser->he_selection->socket; 2857aca7a94dSNamhyung Kim } 2858aca7a94dSNamhyung Kim switch (key) { 2859aca7a94dSNamhyung Kim case K_TAB: 2860aca7a94dSNamhyung Kim case K_UNTAB: 2861aca7a94dSNamhyung Kim if (nr_events == 1) 2862aca7a94dSNamhyung Kim continue; 2863aca7a94dSNamhyung Kim /* 2864aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 2865aca7a94dSNamhyung Kim * go to the next or previous 2866aca7a94dSNamhyung Kim */ 2867aca7a94dSNamhyung Kim goto out_free_stack; 2868aca7a94dSNamhyung Kim case 'a': 28692e0453afSJiri Olsa if (!hists__has(hists, sym)) { 2870aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 2871aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 2872aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 2873aca7a94dSNamhyung Kim continue; 2874aca7a94dSNamhyung Kim } 2875aca7a94dSNamhyung Kim 2876aca7a94dSNamhyung Kim if (browser->selection == NULL || 2877aca7a94dSNamhyung Kim browser->selection->sym == NULL || 2878aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 2879aca7a94dSNamhyung Kim continue; 2880bc7cad42SNamhyung Kim 2881ea7cd592SNamhyung Kim actions->ms.map = browser->selection->map; 2882ea7cd592SNamhyung Kim actions->ms.sym = browser->selection->sym; 2883ea7cd592SNamhyung Kim do_annotate(browser, actions); 2884bc7cad42SNamhyung Kim continue; 2885aff3f3f6SArnaldo Carvalho de Melo case 'P': 2886aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 2887aff3f3f6SArnaldo Carvalho de Melo continue; 2888aca7a94dSNamhyung Kim case 'd': 2889fae00650SArnaldo Carvalho de Melo actions->ms.map = map; 2890ea7cd592SNamhyung Kim do_zoom_dso(browser, actions); 2891bc7cad42SNamhyung Kim continue; 2892a7cb8863SArnaldo Carvalho de Melo case 'V': 289321e8c810SAlexis Berlemont verbose = (verbose + 1) % 4; 289421e8c810SAlexis Berlemont browser->show_dso = verbose > 0; 289521e8c810SAlexis Berlemont ui_helpline__fpush("Verbosity level set to %d\n", 289621e8c810SAlexis Berlemont verbose); 2897a7cb8863SArnaldo Carvalho de Melo continue; 2898aca7a94dSNamhyung Kim case 't': 2899ea7cd592SNamhyung Kim actions->thread = thread; 2900ea7cd592SNamhyung Kim do_zoom_thread(browser, actions); 2901bc7cad42SNamhyung Kim continue; 290284734b06SKan Liang case 'S': 290384734b06SKan Liang actions->socket = socked_id; 290484734b06SKan Liang do_zoom_socket(browser, actions); 290584734b06SKan Liang continue; 29065a5626b1SArnaldo Carvalho de Melo case '/': 2907aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 29084aa8e454SArnaldo Carvalho de Melo "Please enter the name of symbol you want to see.\n" 29094aa8e454SArnaldo Carvalho de Melo "To remove the filter later, press / + ENTER.", 2910aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 2911aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 291205e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 291305e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 2914aca7a94dSNamhyung Kim hist_browser__reset(browser); 2915aca7a94dSNamhyung Kim } 2916aca7a94dSNamhyung Kim continue; 2917cdbab7c2SFeng Tang case 'r': 2918ea7cd592SNamhyung Kim if (is_report_browser(hbt)) { 2919ea7cd592SNamhyung Kim actions->thread = NULL; 2920ea7cd592SNamhyung Kim actions->ms.sym = NULL; 2921ea7cd592SNamhyung Kim do_run_script(browser, actions); 2922ea7cd592SNamhyung Kim } 2923c77d8d70SFeng Tang continue; 2924341487abSFeng Tang case 's': 2925bc7cad42SNamhyung Kim if (is_report_browser(hbt)) { 2926ea7cd592SNamhyung Kim key = do_switch_data(browser, actions); 2927bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 2928bc7cad42SNamhyung Kim goto out_free_stack; 2929bc7cad42SNamhyung Kim } 2930341487abSFeng Tang continue; 29316dd60135SNamhyung Kim case 'i': 29326dd60135SNamhyung Kim /* env->arch is NULL for live-mode (i.e. perf top) */ 29336dd60135SNamhyung Kim if (env->arch) 29346dd60135SNamhyung Kim tui__header_window(env); 29356dd60135SNamhyung Kim continue; 2936105eb30fSNamhyung Kim case 'F': 2937105eb30fSNamhyung Kim symbol_conf.filter_relative ^= 1; 2938105eb30fSNamhyung Kim continue; 293942337a22SNamhyung Kim case 'z': 294042337a22SNamhyung Kim if (!is_report_browser(hbt)) { 294142337a22SNamhyung Kim struct perf_top *top = hbt->arg; 294242337a22SNamhyung Kim 294342337a22SNamhyung Kim top->zero = !top->zero; 294442337a22SNamhyung Kim } 294542337a22SNamhyung Kim continue; 2946b62e8dfcSNamhyung Kim case 'L': 2947b62e8dfcSNamhyung Kim if (ui_browser__input_window("Percent Limit", 2948b62e8dfcSNamhyung Kim "Please enter the value you want to hide entries under that percent.", 2949b62e8dfcSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 2950b62e8dfcSNamhyung Kim delay_secs * 2) == K_ENTER) { 2951b62e8dfcSNamhyung Kim char *end; 2952b62e8dfcSNamhyung Kim double new_percent = strtod(buf, &end); 2953b62e8dfcSNamhyung Kim 2954b62e8dfcSNamhyung Kim if (new_percent < 0 || new_percent > 100) { 2955b62e8dfcSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 2956b62e8dfcSNamhyung Kim "Invalid percent: %.2f", new_percent); 2957b62e8dfcSNamhyung Kim continue; 2958b62e8dfcSNamhyung Kim } 2959b62e8dfcSNamhyung Kim 2960b62e8dfcSNamhyung Kim hist_browser__update_percent_limit(browser, new_percent); 2961b62e8dfcSNamhyung Kim hist_browser__reset(browser); 2962b62e8dfcSNamhyung Kim } 2963b62e8dfcSNamhyung Kim continue; 2964aca7a94dSNamhyung Kim case K_F1: 2965aca7a94dSNamhyung Kim case 'h': 2966aca7a94dSNamhyung Kim case '?': 2967aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 2968e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 2969aca7a94dSNamhyung Kim continue; 2970aca7a94dSNamhyung Kim case K_ENTER: 2971aca7a94dSNamhyung Kim case K_RIGHT: 297231eb4360SNamhyung Kim case 'm': 2973aca7a94dSNamhyung Kim /* menu */ 2974aca7a94dSNamhyung Kim break; 297563ab1749SArnaldo Carvalho de Melo case K_ESC: 2976aca7a94dSNamhyung Kim case K_LEFT: { 2977aca7a94dSNamhyung Kim const void *top; 2978aca7a94dSNamhyung Kim 297901f00a1cSNamhyung Kim if (pstack__empty(browser->pstack)) { 2980aca7a94dSNamhyung Kim /* 2981aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 2982aca7a94dSNamhyung Kim */ 2983aca7a94dSNamhyung Kim if (left_exits) 2984aca7a94dSNamhyung Kim goto out_free_stack; 298563ab1749SArnaldo Carvalho de Melo 298663ab1749SArnaldo Carvalho de Melo if (key == K_ESC && 298763ab1749SArnaldo Carvalho de Melo ui_browser__dialog_yesno(&browser->b, 298863ab1749SArnaldo Carvalho de Melo "Do you really want to exit?")) 298963ab1749SArnaldo Carvalho de Melo goto out_free_stack; 299063ab1749SArnaldo Carvalho de Melo 2991aca7a94dSNamhyung Kim continue; 2992aca7a94dSNamhyung Kim } 29936422184bSNamhyung Kim top = pstack__peek(browser->pstack); 2994bc7cad42SNamhyung Kim if (top == &browser->hists->dso_filter) { 29956422184bSNamhyung Kim /* 29966422184bSNamhyung Kim * No need to set actions->dso here since 29976422184bSNamhyung Kim * it's just to remove the current filter. 29986422184bSNamhyung Kim * Ditto for thread below. 29996422184bSNamhyung Kim */ 30006422184bSNamhyung Kim do_zoom_dso(browser, actions); 300184734b06SKan Liang } else if (top == &browser->hists->thread_filter) { 30026422184bSNamhyung Kim do_zoom_thread(browser, actions); 300384734b06SKan Liang } else if (top == &browser->hists->socket_filter) { 300484734b06SKan Liang do_zoom_socket(browser, actions); 300584734b06SKan Liang } 3006aca7a94dSNamhyung Kim continue; 3007aca7a94dSNamhyung Kim } 3008aca7a94dSNamhyung Kim case 'q': 3009aca7a94dSNamhyung Kim case CTRL('c'): 3010516e5368SArnaldo Carvalho de Melo goto out_free_stack; 3011fbb7997eSArnaldo Carvalho de Melo case 'f': 301213d1e536SNamhyung Kim if (!is_report_browser(hbt)) { 301313d1e536SNamhyung Kim struct perf_top *top = hbt->arg; 301413d1e536SNamhyung Kim 301513d1e536SNamhyung Kim perf_evlist__toggle_enable(top->evlist); 301613d1e536SNamhyung Kim /* 301713d1e536SNamhyung Kim * No need to refresh, resort/decay histogram 301813d1e536SNamhyung Kim * entries if we are not collecting samples: 301913d1e536SNamhyung Kim */ 302013d1e536SNamhyung Kim if (top->evlist->enabled) { 302113d1e536SNamhyung Kim helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; 302213d1e536SNamhyung Kim hbt->refresh = delay_secs; 302313d1e536SNamhyung Kim } else { 302413d1e536SNamhyung Kim helpline = "Press 'f' again to re-enable the events"; 302513d1e536SNamhyung Kim hbt->refresh = 0; 302613d1e536SNamhyung Kim } 302713d1e536SNamhyung Kim continue; 302813d1e536SNamhyung Kim } 30293e323dc0SArnaldo Carvalho de Melo /* Fall thru */ 3030aca7a94dSNamhyung Kim default: 30313e323dc0SArnaldo Carvalho de Melo helpline = "Press '?' for help on key bindings"; 3032aca7a94dSNamhyung Kim continue; 3033aca7a94dSNamhyung Kim } 3034aca7a94dSNamhyung Kim 30352e0453afSJiri Olsa if (!hists__has(hists, sym) || browser->selection == NULL) 30360ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 30370ba332f7SArnaldo Carvalho de Melo 303855369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 3039aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 30400ba332f7SArnaldo Carvalho de Melo 30410ba332f7SArnaldo Carvalho de Melo if (bi == NULL) 30420ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 30430ba332f7SArnaldo Carvalho de Melo 3044ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 3045ea7cd592SNamhyung Kim &actions[nr_options], 3046ea7cd592SNamhyung Kim &options[nr_options], 3047ea7cd592SNamhyung Kim bi->from.map, 3048ea7cd592SNamhyung Kim bi->from.sym); 3049ea7cd592SNamhyung Kim if (bi->to.sym != bi->from.sym) 3050ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 3051ea7cd592SNamhyung Kim &actions[nr_options], 3052ea7cd592SNamhyung Kim &options[nr_options], 3053ea7cd592SNamhyung Kim bi->to.map, 3054ea7cd592SNamhyung Kim bi->to.sym); 3055aca7a94dSNamhyung Kim } else { 3056ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 3057ea7cd592SNamhyung Kim &actions[nr_options], 3058ea7cd592SNamhyung Kim &options[nr_options], 3059ea7cd592SNamhyung Kim browser->selection->map, 3060ea7cd592SNamhyung Kim browser->selection->sym); 3061446fb96cSArnaldo Carvalho de Melo } 30620ba332f7SArnaldo Carvalho de Melo skip_annotation: 3063ea7cd592SNamhyung Kim nr_options += add_thread_opt(browser, &actions[nr_options], 3064ea7cd592SNamhyung Kim &options[nr_options], thread); 3065ea7cd592SNamhyung Kim nr_options += add_dso_opt(browser, &actions[nr_options], 3066045b80ddSArnaldo Carvalho de Melo &options[nr_options], map); 3067ea7cd592SNamhyung Kim nr_options += add_map_opt(browser, &actions[nr_options], 3068ea7cd592SNamhyung Kim &options[nr_options], 3069bd315aabSWang Nan browser->selection ? 3070bd315aabSWang Nan browser->selection->map : NULL); 307184734b06SKan Liang nr_options += add_socket_opt(browser, &actions[nr_options], 307284734b06SKan Liang &options[nr_options], 307384734b06SKan Liang socked_id); 3074cdbab7c2SFeng Tang /* perf script support */ 3075b1baae89SNamhyung Kim if (!is_report_browser(hbt)) 3076b1baae89SNamhyung Kim goto skip_scripting; 3077b1baae89SNamhyung Kim 3078cdbab7c2SFeng Tang if (browser->he_selection) { 3079fa82911aSJiri Olsa if (hists__has(hists, thread) && thread) { 3080ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 3081ea7cd592SNamhyung Kim &actions[nr_options], 3082ea7cd592SNamhyung Kim &options[nr_options], 3083ea7cd592SNamhyung Kim thread, NULL); 30842eafd410SNamhyung Kim } 3085bd315aabSWang Nan /* 3086bd315aabSWang Nan * Note that browser->selection != NULL 3087bd315aabSWang Nan * when browser->he_selection is not NULL, 3088bd315aabSWang Nan * so we don't need to check browser->selection 3089bd315aabSWang Nan * before fetching browser->selection->sym like what 3090bd315aabSWang Nan * we do before fetching browser->selection->map. 3091bd315aabSWang Nan * 3092bd315aabSWang Nan * See hist_browser__show_entry. 3093bd315aabSWang Nan */ 30942e0453afSJiri Olsa if (hists__has(hists, sym) && browser->selection->sym) { 3095ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 3096ea7cd592SNamhyung Kim &actions[nr_options], 3097ea7cd592SNamhyung Kim &options[nr_options], 3098ea7cd592SNamhyung Kim NULL, browser->selection->sym); 3099cdbab7c2SFeng Tang } 3100c221acb0SNamhyung Kim } 3101ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, &actions[nr_options], 3102ea7cd592SNamhyung Kim &options[nr_options], NULL, NULL); 3103ea7cd592SNamhyung Kim nr_options += add_switch_opt(browser, &actions[nr_options], 3104ea7cd592SNamhyung Kim &options[nr_options]); 3105b1baae89SNamhyung Kim skip_scripting: 3106ea7cd592SNamhyung Kim nr_options += add_exit_opt(browser, &actions[nr_options], 3107ea7cd592SNamhyung Kim &options[nr_options]); 3108aca7a94dSNamhyung Kim 3109ea7cd592SNamhyung Kim do { 3110ea7cd592SNamhyung Kim struct popup_action *act; 3111ea7cd592SNamhyung Kim 3112ea7cd592SNamhyung Kim choice = ui__popup_menu(nr_options, options); 3113ea7cd592SNamhyung Kim if (choice == -1 || choice >= nr_options) 3114aca7a94dSNamhyung Kim break; 3115aca7a94dSNamhyung Kim 3116ea7cd592SNamhyung Kim act = &actions[choice]; 3117ea7cd592SNamhyung Kim key = act->fn(browser, act); 3118ea7cd592SNamhyung Kim } while (key == 1); 3119aca7a94dSNamhyung Kim 3120bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 3121341487abSFeng Tang break; 3122341487abSFeng Tang } 3123aca7a94dSNamhyung Kim out_free_stack: 312401f00a1cSNamhyung Kim pstack__delete(browser->pstack); 3125aca7a94dSNamhyung Kim out: 3126aca7a94dSNamhyung Kim hist_browser__delete(browser); 3127f2b487dbSNamhyung Kim free_popup_options(options, MAX_OPTIONS); 3128aca7a94dSNamhyung Kim return key; 3129aca7a94dSNamhyung Kim } 3130aca7a94dSNamhyung Kim 3131aca7a94dSNamhyung Kim struct perf_evsel_menu { 3132aca7a94dSNamhyung Kim struct ui_browser b; 3133aca7a94dSNamhyung Kim struct perf_evsel *selection; 3134aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 3135064f1981SNamhyung Kim float min_pcnt; 3136ce80d3beSKan Liang struct perf_env *env; 3137aca7a94dSNamhyung Kim }; 3138aca7a94dSNamhyung Kim 3139aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 3140aca7a94dSNamhyung Kim void *entry, int row) 3141aca7a94dSNamhyung Kim { 3142aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 3143aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 3144aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 31454ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 3146aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 31474ea062edSArnaldo Carvalho de Melo unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 31487289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 3149aca7a94dSNamhyung Kim char bf[256], unit; 3150aca7a94dSNamhyung Kim const char *warn = " "; 3151aca7a94dSNamhyung Kim size_t printed; 3152aca7a94dSNamhyung Kim 3153aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 3154aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 3155aca7a94dSNamhyung Kim 3156759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 3157717e263fSNamhyung Kim struct perf_evsel *pos; 3158717e263fSNamhyung Kim 3159717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 3160717e263fSNamhyung Kim 3161717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 31624ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 31634ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 3164717e263fSNamhyung Kim } 3165717e263fSNamhyung Kim } 3166717e263fSNamhyung Kim 3167aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3168aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 3169aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 3170517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%s", bf); 3171aca7a94dSNamhyung Kim 31724ea062edSArnaldo Carvalho de Melo nr_events = hists->stats.nr_events[PERF_RECORD_LOST]; 3173aca7a94dSNamhyung Kim if (nr_events != 0) { 3174aca7a94dSNamhyung Kim menu->lost_events = true; 3175aca7a94dSNamhyung Kim if (!current_entry) 3176aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 3177aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3178aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 3179aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 3180aca7a94dSNamhyung Kim warn = bf; 3181aca7a94dSNamhyung Kim } 3182aca7a94dSNamhyung Kim 318326270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, warn, browser->width - printed); 3184aca7a94dSNamhyung Kim 3185aca7a94dSNamhyung Kim if (current_entry) 3186aca7a94dSNamhyung Kim menu->selection = evsel; 3187aca7a94dSNamhyung Kim } 3188aca7a94dSNamhyung Kim 3189aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 3190aca7a94dSNamhyung Kim int nr_events, const char *help, 3191*06cc1a47SKan Liang struct hist_browser_timer *hbt, 3192*06cc1a47SKan Liang bool warn_lost_event) 3193aca7a94dSNamhyung Kim { 3194aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 3195aca7a94dSNamhyung Kim struct perf_evsel *pos; 3196dd00d486SJiri Olsa const char *title = "Available samples"; 31979783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 3198aca7a94dSNamhyung Kim int key; 3199aca7a94dSNamhyung Kim 3200aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 3201aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 3202aca7a94dSNamhyung Kim return -1; 3203aca7a94dSNamhyung Kim 3204aca7a94dSNamhyung Kim while (1) { 3205aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 3206aca7a94dSNamhyung Kim 3207aca7a94dSNamhyung Kim switch (key) { 3208aca7a94dSNamhyung Kim case K_TIMER: 32099783adf7SNamhyung Kim hbt->timer(hbt->arg); 3210aca7a94dSNamhyung Kim 3211*06cc1a47SKan Liang if (!menu->lost_events_warned && 3212*06cc1a47SKan Liang menu->lost_events && 3213*06cc1a47SKan Liang warn_lost_event) { 3214aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 3215aca7a94dSNamhyung Kim menu->lost_events_warned = true; 3216aca7a94dSNamhyung Kim } 3217aca7a94dSNamhyung Kim continue; 3218aca7a94dSNamhyung Kim case K_RIGHT: 3219aca7a94dSNamhyung Kim case K_ENTER: 3220aca7a94dSNamhyung Kim if (!menu->selection) 3221aca7a94dSNamhyung Kim continue; 3222aca7a94dSNamhyung Kim pos = menu->selection; 3223aca7a94dSNamhyung Kim browse_hists: 3224aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 3225aca7a94dSNamhyung Kim /* 3226aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 3227aca7a94dSNamhyung Kim * default evsel resorted hists tree. 3228aca7a94dSNamhyung Kim */ 32299783adf7SNamhyung Kim if (hbt) 32309783adf7SNamhyung Kim hbt->timer(hbt->arg); 3231aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 3232dd00d486SJiri Olsa true, hbt, 3233064f1981SNamhyung Kim menu->min_pcnt, 3234*06cc1a47SKan Liang menu->env, 3235*06cc1a47SKan Liang warn_lost_event); 3236aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 3237aca7a94dSNamhyung Kim switch (key) { 3238aca7a94dSNamhyung Kim case K_TAB: 3239aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 32409a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__first(evlist); 3241aca7a94dSNamhyung Kim else 32429a354cdcSArnaldo Carvalho de Melo pos = perf_evsel__next(pos); 3243aca7a94dSNamhyung Kim goto browse_hists; 3244aca7a94dSNamhyung Kim case K_UNTAB: 3245aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 32469a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__last(evlist); 3247aca7a94dSNamhyung Kim else 3248d87fcb4aSArnaldo Carvalho de Melo pos = perf_evsel__prev(pos); 3249aca7a94dSNamhyung Kim goto browse_hists; 3250341487abSFeng Tang case K_SWITCH_INPUT_DATA: 3251aca7a94dSNamhyung Kim case 'q': 3252aca7a94dSNamhyung Kim case CTRL('c'): 3253aca7a94dSNamhyung Kim goto out; 325463ab1749SArnaldo Carvalho de Melo case K_ESC: 3255aca7a94dSNamhyung Kim default: 3256aca7a94dSNamhyung Kim continue; 3257aca7a94dSNamhyung Kim } 3258aca7a94dSNamhyung Kim case K_LEFT: 3259aca7a94dSNamhyung Kim continue; 3260aca7a94dSNamhyung Kim case K_ESC: 3261aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 3262aca7a94dSNamhyung Kim "Do you really want to exit?")) 3263aca7a94dSNamhyung Kim continue; 3264aca7a94dSNamhyung Kim /* Fall thru */ 3265aca7a94dSNamhyung Kim case 'q': 3266aca7a94dSNamhyung Kim case CTRL('c'): 3267aca7a94dSNamhyung Kim goto out; 3268aca7a94dSNamhyung Kim default: 3269aca7a94dSNamhyung Kim continue; 3270aca7a94dSNamhyung Kim } 3271aca7a94dSNamhyung Kim } 3272aca7a94dSNamhyung Kim 3273aca7a94dSNamhyung Kim out: 3274aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 3275aca7a94dSNamhyung Kim return key; 3276aca7a94dSNamhyung Kim } 3277aca7a94dSNamhyung Kim 3278316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 3279fc24d7c2SNamhyung Kim void *entry) 3280fc24d7c2SNamhyung Kim { 3281fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 3282fc24d7c2SNamhyung Kim 3283fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 3284fc24d7c2SNamhyung Kim return true; 3285fc24d7c2SNamhyung Kim 3286fc24d7c2SNamhyung Kim return false; 3287fc24d7c2SNamhyung Kim } 3288fc24d7c2SNamhyung Kim 3289aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 3290fc24d7c2SNamhyung Kim int nr_entries, const char *help, 329168d80758SNamhyung Kim struct hist_browser_timer *hbt, 3292064f1981SNamhyung Kim float min_pcnt, 3293*06cc1a47SKan Liang struct perf_env *env, 3294*06cc1a47SKan Liang bool warn_lost_event) 3295aca7a94dSNamhyung Kim { 3296aca7a94dSNamhyung Kim struct perf_evsel *pos; 3297aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 3298aca7a94dSNamhyung Kim .b = { 3299aca7a94dSNamhyung Kim .entries = &evlist->entries, 3300aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 3301aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 3302aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 3303fc24d7c2SNamhyung Kim .filter = filter_group_entries, 3304fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 3305aca7a94dSNamhyung Kim .priv = evlist, 3306aca7a94dSNamhyung Kim }, 3307064f1981SNamhyung Kim .min_pcnt = min_pcnt, 330868d80758SNamhyung Kim .env = env, 3309aca7a94dSNamhyung Kim }; 3310aca7a94dSNamhyung Kim 3311aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 3312aca7a94dSNamhyung Kim 3313e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, pos) { 33147289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 3315aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 3316aca7a94dSNamhyung Kim 3317aca7a94dSNamhyung Kim if (menu.b.width < line_len) 3318aca7a94dSNamhyung Kim menu.b.width = line_len; 3319aca7a94dSNamhyung Kim } 3320aca7a94dSNamhyung Kim 3321*06cc1a47SKan Liang return perf_evsel_menu__run(&menu, nr_entries, help, 3322*06cc1a47SKan Liang hbt, warn_lost_event); 3323aca7a94dSNamhyung Kim } 3324aca7a94dSNamhyung Kim 3325aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 332668d80758SNamhyung Kim struct hist_browser_timer *hbt, 3327064f1981SNamhyung Kim float min_pcnt, 3328*06cc1a47SKan Liang struct perf_env *env, 3329*06cc1a47SKan Liang bool warn_lost_event) 3330aca7a94dSNamhyung Kim { 3331fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 3332fc24d7c2SNamhyung Kim 3333fc24d7c2SNamhyung Kim single_entry: 3334fc24d7c2SNamhyung Kim if (nr_entries == 1) { 33359a354cdcSArnaldo Carvalho de Melo struct perf_evsel *first = perf_evlist__first(evlist); 3336fc24d7c2SNamhyung Kim 3337fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 3338dd00d486SJiri Olsa false, hbt, min_pcnt, 3339*06cc1a47SKan Liang env, warn_lost_event); 3340aca7a94dSNamhyung Kim } 3341aca7a94dSNamhyung Kim 3342fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 3343fc24d7c2SNamhyung Kim struct perf_evsel *pos; 3344fc24d7c2SNamhyung Kim 3345fc24d7c2SNamhyung Kim nr_entries = 0; 3346e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, pos) { 3347fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 3348fc24d7c2SNamhyung Kim nr_entries++; 33490050f7aaSArnaldo Carvalho de Melo } 3350fc24d7c2SNamhyung Kim 3351fc24d7c2SNamhyung Kim if (nr_entries == 1) 3352fc24d7c2SNamhyung Kim goto single_entry; 3353fc24d7c2SNamhyung Kim } 3354fc24d7c2SNamhyung Kim 3355fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 3356*06cc1a47SKan Liang hbt, min_pcnt, env, 3357*06cc1a47SKan Liang warn_lost_event); 3358aca7a94dSNamhyung Kim } 3359