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 35f016d24aSArnaldo Carvalho de Melo static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size); 36112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb); 37aca7a94dSNamhyung Kim 38c3b78952SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 39c3b78952SNamhyung Kim float min_pcnt); 40c3b78952SNamhyung Kim 41268397cbSNamhyung Kim static bool hist_browser__has_filter(struct hist_browser *hb) 42268397cbSNamhyung Kim { 435a1a99cdSJiri Olsa return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter; 44268397cbSNamhyung Kim } 45268397cbSNamhyung Kim 464fabf3d1SHe Kuang static int hist_browser__get_folding(struct hist_browser *browser) 474fabf3d1SHe Kuang { 484fabf3d1SHe Kuang struct rb_node *nd; 494fabf3d1SHe Kuang struct hists *hists = browser->hists; 504fabf3d1SHe Kuang int unfolded_rows = 0; 514fabf3d1SHe Kuang 524fabf3d1SHe Kuang for (nd = rb_first(&hists->entries); 534fabf3d1SHe Kuang (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 54f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd)) { 554fabf3d1SHe Kuang struct hist_entry *he = 564fabf3d1SHe Kuang rb_entry(nd, struct hist_entry, rb_node); 574fabf3d1SHe Kuang 58f5b763feSNamhyung Kim if (he->leaf && he->unfolded) 594fabf3d1SHe Kuang unfolded_rows += he->nr_rows; 604fabf3d1SHe Kuang } 614fabf3d1SHe Kuang return unfolded_rows; 624fabf3d1SHe Kuang } 634fabf3d1SHe Kuang 64ef9ff601SArnaldo Carvalho de Melo static void hist_browser__set_title_space(struct hist_browser *hb) 65ef9ff601SArnaldo Carvalho de Melo { 66ef9ff601SArnaldo Carvalho de Melo struct ui_browser *browser = &hb->b; 67ef9ff601SArnaldo Carvalho de Melo struct hists *hists = hb->hists; 68ef9ff601SArnaldo Carvalho de Melo struct perf_hpp_list *hpp_list = hists->hpp_list; 69ef9ff601SArnaldo Carvalho de Melo 70ef9ff601SArnaldo Carvalho de Melo browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0; 71ef9ff601SArnaldo Carvalho de Melo } 72ef9ff601SArnaldo Carvalho de Melo 73c3b78952SNamhyung Kim static u32 hist_browser__nr_entries(struct hist_browser *hb) 74c3b78952SNamhyung Kim { 75c3b78952SNamhyung Kim u32 nr_entries; 76c3b78952SNamhyung Kim 77f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 78f5b763feSNamhyung Kim nr_entries = hb->nr_hierarchy_entries; 79f5b763feSNamhyung Kim else if (hist_browser__has_filter(hb)) 80c3b78952SNamhyung Kim nr_entries = hb->nr_non_filtered_entries; 81c3b78952SNamhyung Kim else 82c3b78952SNamhyung Kim nr_entries = hb->hists->nr_entries; 83c3b78952SNamhyung Kim 844fabf3d1SHe Kuang hb->nr_callchain_rows = hist_browser__get_folding(hb); 85c3b78952SNamhyung Kim return nr_entries + hb->nr_callchain_rows; 86c3b78952SNamhyung Kim } 87c3b78952SNamhyung Kim 88025bf7eaSArnaldo Carvalho de Melo static void hist_browser__update_rows(struct hist_browser *hb) 89025bf7eaSArnaldo Carvalho de Melo { 90025bf7eaSArnaldo Carvalho de Melo struct ui_browser *browser = &hb->b; 91f8e6710dSJiri Olsa struct hists *hists = hb->hists; 92f8e6710dSJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 93ef9ff601SArnaldo Carvalho de Melo u16 index_row; 94025bf7eaSArnaldo Carvalho de Melo 95ef9ff601SArnaldo Carvalho de Melo if (!hb->show_headers) { 96ef9ff601SArnaldo Carvalho de Melo browser->rows += browser->extra_title_lines; 97ef9ff601SArnaldo Carvalho de Melo browser->extra_title_lines = 0; 98ef9ff601SArnaldo Carvalho de Melo return; 99ef9ff601SArnaldo Carvalho de Melo } 100ef9ff601SArnaldo Carvalho de Melo 101ef9ff601SArnaldo Carvalho de Melo browser->extra_title_lines = hpp_list->nr_header_lines; 102ef9ff601SArnaldo Carvalho de Melo browser->rows -= browser->extra_title_lines; 103025bf7eaSArnaldo Carvalho de Melo /* 104025bf7eaSArnaldo Carvalho de Melo * Verify if we were at the last line and that line isn't 105025bf7eaSArnaldo Carvalho de Melo * visibe because we now show the header line(s). 106025bf7eaSArnaldo Carvalho de Melo */ 107025bf7eaSArnaldo Carvalho de Melo index_row = browser->index - browser->top_idx; 108025bf7eaSArnaldo Carvalho de Melo if (index_row >= browser->rows) 109025bf7eaSArnaldo Carvalho de Melo browser->index -= index_row - browser->rows + 1; 110025bf7eaSArnaldo Carvalho de Melo } 111025bf7eaSArnaldo Carvalho de Melo 112357cfff1SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct ui_browser *browser) 113aca7a94dSNamhyung Kim { 114357cfff1SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 115357cfff1SArnaldo Carvalho de Melo 116aca7a94dSNamhyung Kim /* 3 == +/- toggle symbol before actual hist_entry rendering */ 117357cfff1SArnaldo Carvalho de Melo browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]")); 118357cfff1SArnaldo Carvalho de Melo /* 119357cfff1SArnaldo Carvalho de Melo * FIXME: Just keeping existing behaviour, but this really should be 120357cfff1SArnaldo Carvalho de Melo * before updating browser->width, as it will invalidate the 121357cfff1SArnaldo Carvalho de Melo * calculation above. Fix this and the fallout in another 122357cfff1SArnaldo Carvalho de Melo * changeset. 123357cfff1SArnaldo Carvalho de Melo */ 124357cfff1SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(browser); 125ca3ff33bSArnaldo Carvalho de Melo } 126ca3ff33bSArnaldo Carvalho de Melo 12705e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser) 128aca7a94dSNamhyung Kim { 129c3b78952SNamhyung Kim /* 130c3b78952SNamhyung Kim * The hists__remove_entry_filter() already folds non-filtered 131c3b78952SNamhyung Kim * entries so we can assume it has 0 callchain rows. 132c3b78952SNamhyung Kim */ 133c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 134c3b78952SNamhyung Kim 135268397cbSNamhyung Kim hist_browser__update_nr_entries(browser); 136c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 137357cfff1SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(&browser->b); 13805e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 139aca7a94dSNamhyung Kim } 140aca7a94dSNamhyung Kim 141aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded) 142aca7a94dSNamhyung Kim { 143aca7a94dSNamhyung Kim return unfolded ? '-' : '+'; 144aca7a94dSNamhyung Kim } 145aca7a94dSNamhyung Kim 14605e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he) 147aca7a94dSNamhyung Kim { 1483698dab1SNamhyung Kim return he->has_children ? tree__folded_sign(he->unfolded) : ' '; 149aca7a94dSNamhyung Kim } 150aca7a94dSNamhyung Kim 15105e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl) 152aca7a94dSNamhyung Kim { 1533698dab1SNamhyung Kim return cl->has_children ? tree__folded_sign(cl->unfolded) : ' '; 154aca7a94dSNamhyung Kim } 155aca7a94dSNamhyung Kim 1563698dab1SNamhyung Kim static void callchain_list__set_folding(struct callchain_list *cl, bool unfold) 157aca7a94dSNamhyung Kim { 1583698dab1SNamhyung Kim cl->unfolded = unfold ? cl->has_children : false; 159aca7a94dSNamhyung Kim } 160aca7a94dSNamhyung Kim 16105e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 162aca7a94dSNamhyung Kim { 1632a704fc8SMilian Wolff int n = 0; 164aca7a94dSNamhyung Kim struct rb_node *nd; 165aca7a94dSNamhyung Kim 16605e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 167aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 168aca7a94dSNamhyung Kim struct callchain_list *chain; 169aca7a94dSNamhyung Kim char folded_sign = ' '; /* No children */ 170aca7a94dSNamhyung Kim 171aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 172aca7a94dSNamhyung Kim ++n; 1730d3eb0b7SJin Yao 174aca7a94dSNamhyung Kim /* We need this because we may not have children */ 175aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 176aca7a94dSNamhyung Kim if (folded_sign == '+') 177aca7a94dSNamhyung Kim break; 178aca7a94dSNamhyung Kim } 179aca7a94dSNamhyung Kim 180aca7a94dSNamhyung Kim if (folded_sign == '-') /* Have children and they're unfolded */ 181aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(child); 182aca7a94dSNamhyung Kim } 183aca7a94dSNamhyung Kim 184aca7a94dSNamhyung Kim return n; 185aca7a94dSNamhyung Kim } 186aca7a94dSNamhyung Kim 1874b3a3212SNamhyung Kim static int callchain_node__count_flat_rows(struct callchain_node *node) 1884b3a3212SNamhyung Kim { 1894b3a3212SNamhyung Kim struct callchain_list *chain; 1904b3a3212SNamhyung Kim char folded_sign = 0; 1914b3a3212SNamhyung Kim int n = 0; 1924b3a3212SNamhyung Kim 1934b3a3212SNamhyung Kim list_for_each_entry(chain, &node->parent_val, list) { 1944b3a3212SNamhyung Kim if (!folded_sign) { 1954b3a3212SNamhyung Kim /* only check first chain list entry */ 1964b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 1974b3a3212SNamhyung Kim if (folded_sign == '+') 1984b3a3212SNamhyung Kim return 1; 1994b3a3212SNamhyung Kim } 2004b3a3212SNamhyung Kim n++; 2014b3a3212SNamhyung Kim } 2024b3a3212SNamhyung Kim 2034b3a3212SNamhyung Kim list_for_each_entry(chain, &node->val, list) { 2044b3a3212SNamhyung Kim if (!folded_sign) { 2054b3a3212SNamhyung Kim /* node->parent_val list might be empty */ 2064b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 2074b3a3212SNamhyung Kim if (folded_sign == '+') 2084b3a3212SNamhyung Kim return 1; 2094b3a3212SNamhyung Kim } 2104b3a3212SNamhyung Kim n++; 2114b3a3212SNamhyung Kim } 2124b3a3212SNamhyung Kim 2134b3a3212SNamhyung Kim return n; 2144b3a3212SNamhyung Kim } 2154b3a3212SNamhyung Kim 2168c430a34SNamhyung Kim static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused) 2178c430a34SNamhyung Kim { 2188c430a34SNamhyung Kim return 1; 2198c430a34SNamhyung Kim } 2208c430a34SNamhyung Kim 221aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 222aca7a94dSNamhyung Kim { 223aca7a94dSNamhyung Kim struct callchain_list *chain; 224aca7a94dSNamhyung Kim bool unfolded = false; 2252a704fc8SMilian Wolff int n = 0; 226aca7a94dSNamhyung Kim 2274b3a3212SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) 2284b3a3212SNamhyung Kim return callchain_node__count_flat_rows(node); 2298c430a34SNamhyung Kim else if (callchain_param.mode == CHAIN_FOLDED) 2308c430a34SNamhyung Kim return callchain_node__count_folded_rows(node); 2314b3a3212SNamhyung Kim 232aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 233aca7a94dSNamhyung Kim ++n; 2340d3eb0b7SJin Yao 2353698dab1SNamhyung Kim unfolded = chain->unfolded; 236aca7a94dSNamhyung Kim } 237aca7a94dSNamhyung Kim 238aca7a94dSNamhyung Kim if (unfolded) 239aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 240aca7a94dSNamhyung Kim 241aca7a94dSNamhyung Kim return n; 242aca7a94dSNamhyung Kim } 243aca7a94dSNamhyung Kim 244aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 245aca7a94dSNamhyung Kim { 246aca7a94dSNamhyung Kim struct rb_node *nd; 247aca7a94dSNamhyung Kim int n = 0; 248aca7a94dSNamhyung Kim 249aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 250aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 251aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 252aca7a94dSNamhyung Kim } 253aca7a94dSNamhyung Kim 254aca7a94dSNamhyung Kim return n; 255aca7a94dSNamhyung Kim } 256aca7a94dSNamhyung Kim 257f5b763feSNamhyung Kim static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he, 258f5b763feSNamhyung Kim bool include_children) 259f5b763feSNamhyung Kim { 260f5b763feSNamhyung Kim int count = 0; 261f5b763feSNamhyung Kim struct rb_node *node; 262f5b763feSNamhyung Kim struct hist_entry *child; 263f5b763feSNamhyung Kim 264f5b763feSNamhyung Kim if (he->leaf) 265f5b763feSNamhyung Kim return callchain__count_rows(&he->sorted_chain); 266f5b763feSNamhyung Kim 26779dded87SNamhyung Kim if (he->has_no_entry) 26879dded87SNamhyung Kim return 1; 26979dded87SNamhyung Kim 270f5b763feSNamhyung Kim node = rb_first(&he->hroot_out); 271f5b763feSNamhyung Kim while (node) { 272f5b763feSNamhyung Kim float percent; 273f5b763feSNamhyung Kim 274f5b763feSNamhyung Kim child = rb_entry(node, struct hist_entry, rb_node); 275f5b763feSNamhyung Kim percent = hist_entry__get_percent_limit(child); 276f5b763feSNamhyung Kim 277f5b763feSNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) { 278f5b763feSNamhyung Kim count++; 279f5b763feSNamhyung Kim 280f5b763feSNamhyung Kim if (include_children && child->unfolded) 281f5b763feSNamhyung Kim count += hierarchy_count_rows(hb, child, true); 282f5b763feSNamhyung Kim } 283f5b763feSNamhyung Kim 284f5b763feSNamhyung Kim node = rb_next(node); 285f5b763feSNamhyung Kim } 286f5b763feSNamhyung Kim return count; 287f5b763feSNamhyung Kim } 288f5b763feSNamhyung Kim 2893698dab1SNamhyung Kim static bool hist_entry__toggle_fold(struct hist_entry *he) 290aca7a94dSNamhyung Kim { 2913698dab1SNamhyung Kim if (!he) 292aca7a94dSNamhyung Kim return false; 293aca7a94dSNamhyung Kim 2943698dab1SNamhyung Kim if (!he->has_children) 295aca7a94dSNamhyung Kim return false; 296aca7a94dSNamhyung Kim 2973698dab1SNamhyung Kim he->unfolded = !he->unfolded; 2983698dab1SNamhyung Kim return true; 2993698dab1SNamhyung Kim } 3003698dab1SNamhyung Kim 3013698dab1SNamhyung Kim static bool callchain_list__toggle_fold(struct callchain_list *cl) 3023698dab1SNamhyung Kim { 3033698dab1SNamhyung Kim if (!cl) 3043698dab1SNamhyung Kim return false; 3053698dab1SNamhyung Kim 3063698dab1SNamhyung Kim if (!cl->has_children) 3073698dab1SNamhyung Kim return false; 3083698dab1SNamhyung Kim 3093698dab1SNamhyung Kim cl->unfolded = !cl->unfolded; 310aca7a94dSNamhyung Kim return true; 311aca7a94dSNamhyung Kim } 312aca7a94dSNamhyung Kim 31305e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 314aca7a94dSNamhyung Kim { 31505e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 316aca7a94dSNamhyung Kim 31705e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 318aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 319aca7a94dSNamhyung Kim struct callchain_list *chain; 320aca7a94dSNamhyung Kim bool first = true; 321aca7a94dSNamhyung Kim 322aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 323aca7a94dSNamhyung Kim if (first) { 324aca7a94dSNamhyung Kim first = false; 3253698dab1SNamhyung Kim chain->has_children = chain->list.next != &child->val || 326aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 327aca7a94dSNamhyung Kim } else 3283698dab1SNamhyung Kim chain->has_children = chain->list.next == &child->val && 329aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 330aca7a94dSNamhyung Kim } 331aca7a94dSNamhyung Kim 332aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 333aca7a94dSNamhyung Kim } 334aca7a94dSNamhyung Kim } 335aca7a94dSNamhyung Kim 336a7444af6SNamhyung Kim static void callchain_node__init_have_children(struct callchain_node *node, 337a7444af6SNamhyung Kim bool has_sibling) 338aca7a94dSNamhyung Kim { 339aca7a94dSNamhyung Kim struct callchain_list *chain; 340aca7a94dSNamhyung Kim 341a7444af6SNamhyung Kim chain = list_entry(node->val.next, struct callchain_list, list); 3423698dab1SNamhyung Kim chain->has_children = has_sibling; 343a7444af6SNamhyung Kim 34490989035SAndres Freund if (!list_empty(&node->val)) { 34582162b5aSNamhyung Kim chain = list_entry(node->val.prev, struct callchain_list, list); 3463698dab1SNamhyung Kim chain->has_children = !RB_EMPTY_ROOT(&node->rb_root); 34782162b5aSNamhyung Kim } 348aca7a94dSNamhyung Kim 34905e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 350aca7a94dSNamhyung Kim } 351aca7a94dSNamhyung Kim 35205e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 353aca7a94dSNamhyung Kim { 354a7444af6SNamhyung Kim struct rb_node *nd = rb_first(root); 355a7444af6SNamhyung Kim bool has_sibling = nd && rb_next(nd); 356aca7a94dSNamhyung Kim 35705e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 358aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 359a7444af6SNamhyung Kim callchain_node__init_have_children(node, has_sibling); 3608c430a34SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT || 3618c430a34SNamhyung Kim callchain_param.mode == CHAIN_FOLDED) 3624b3a3212SNamhyung Kim callchain_node__make_parent_list(node); 363aca7a94dSNamhyung Kim } 364aca7a94dSNamhyung Kim } 365aca7a94dSNamhyung Kim 36605e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 367aca7a94dSNamhyung Kim { 368f5b763feSNamhyung Kim if (he->init_have_children) 369f5b763feSNamhyung Kim return; 370f5b763feSNamhyung Kim 371f5b763feSNamhyung Kim if (he->leaf) { 3723698dab1SNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 37305e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 374f5b763feSNamhyung Kim } else { 375f5b763feSNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->hroot_out); 376aca7a94dSNamhyung Kim } 377f5b763feSNamhyung Kim 378f5b763feSNamhyung Kim he->init_have_children = true; 379aca7a94dSNamhyung Kim } 380aca7a94dSNamhyung Kim 38105e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 382aca7a94dSNamhyung Kim { 38305e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 3843698dab1SNamhyung Kim struct map_symbol *ms = browser->selection; 3853698dab1SNamhyung Kim struct callchain_list *cl = container_of(ms, struct callchain_list, ms); 3863698dab1SNamhyung Kim bool has_children; 387aca7a94dSNamhyung Kim 3884938cf0cSWang Nan if (!he || !ms) 3894938cf0cSWang Nan return false; 3904938cf0cSWang Nan 3913698dab1SNamhyung Kim if (ms == &he->ms) 3923698dab1SNamhyung Kim has_children = hist_entry__toggle_fold(he); 3933698dab1SNamhyung Kim else 3943698dab1SNamhyung Kim has_children = callchain_list__toggle_fold(cl); 3953698dab1SNamhyung Kim 3963698dab1SNamhyung Kim if (has_children) { 397f5b763feSNamhyung Kim int child_rows = 0; 398f5b763feSNamhyung Kim 399aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 400c3b78952SNamhyung Kim browser->b.nr_entries -= he->nr_rows; 401aca7a94dSNamhyung Kim 402f5b763feSNamhyung Kim if (he->leaf) 403f5b763feSNamhyung Kim browser->nr_callchain_rows -= he->nr_rows; 404f5b763feSNamhyung Kim else 405f5b763feSNamhyung Kim browser->nr_hierarchy_entries -= he->nr_rows; 406f5b763feSNamhyung Kim 407f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 408f5b763feSNamhyung Kim child_rows = hierarchy_count_rows(browser, he, true); 409f5b763feSNamhyung Kim 410f5b763feSNamhyung Kim if (he->unfolded) { 411f5b763feSNamhyung Kim if (he->leaf) 4120d3eb0b7SJin Yao he->nr_rows = callchain__count_rows( 4130d3eb0b7SJin Yao &he->sorted_chain); 414aca7a94dSNamhyung Kim else 415f5b763feSNamhyung Kim he->nr_rows = hierarchy_count_rows(browser, he, false); 416f5b763feSNamhyung Kim 417f5b763feSNamhyung Kim /* account grand children */ 418f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 419f5b763feSNamhyung Kim browser->b.nr_entries += child_rows - he->nr_rows; 42079dded87SNamhyung Kim 42179dded87SNamhyung Kim if (!he->leaf && he->nr_rows == 0) { 42279dded87SNamhyung Kim he->has_no_entry = true; 42379dded87SNamhyung Kim he->nr_rows = 1; 42479dded87SNamhyung Kim } 425f5b763feSNamhyung Kim } else { 426f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 427f5b763feSNamhyung Kim browser->b.nr_entries -= child_rows - he->nr_rows; 428f5b763feSNamhyung Kim 42979dded87SNamhyung Kim if (he->has_no_entry) 43079dded87SNamhyung Kim he->has_no_entry = false; 43179dded87SNamhyung Kim 432aca7a94dSNamhyung Kim he->nr_rows = 0; 433f5b763feSNamhyung Kim } 434c3b78952SNamhyung Kim 435c3b78952SNamhyung Kim browser->b.nr_entries += he->nr_rows; 436f5b763feSNamhyung Kim 437f5b763feSNamhyung Kim if (he->leaf) 438c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 439f5b763feSNamhyung Kim else 440f5b763feSNamhyung Kim browser->nr_hierarchy_entries += he->nr_rows; 441aca7a94dSNamhyung Kim 442aca7a94dSNamhyung Kim return true; 443aca7a94dSNamhyung Kim } 444aca7a94dSNamhyung Kim 445aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 446aca7a94dSNamhyung Kim return false; 447aca7a94dSNamhyung Kim } 448aca7a94dSNamhyung Kim 44905e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 450aca7a94dSNamhyung Kim { 451aca7a94dSNamhyung Kim int n = 0; 452aca7a94dSNamhyung Kim struct rb_node *nd; 453aca7a94dSNamhyung Kim 45405e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 455aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 456aca7a94dSNamhyung Kim struct callchain_list *chain; 457aca7a94dSNamhyung Kim bool has_children = false; 458aca7a94dSNamhyung Kim 459aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 460aca7a94dSNamhyung Kim ++n; 4613698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 4623698dab1SNamhyung Kim has_children = chain->has_children; 463aca7a94dSNamhyung Kim } 464aca7a94dSNamhyung Kim 465aca7a94dSNamhyung Kim if (has_children) 466aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 467aca7a94dSNamhyung Kim } 468aca7a94dSNamhyung Kim 469aca7a94dSNamhyung Kim return n; 470aca7a94dSNamhyung Kim } 471aca7a94dSNamhyung Kim 472aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 473aca7a94dSNamhyung Kim { 474aca7a94dSNamhyung Kim struct callchain_list *chain; 475aca7a94dSNamhyung Kim bool has_children = false; 476aca7a94dSNamhyung Kim int n = 0; 477aca7a94dSNamhyung Kim 478aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 479aca7a94dSNamhyung Kim ++n; 4803698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 4813698dab1SNamhyung Kim has_children = chain->has_children; 482aca7a94dSNamhyung Kim } 483aca7a94dSNamhyung Kim 484aca7a94dSNamhyung Kim if (has_children) 485aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 486aca7a94dSNamhyung Kim 487aca7a94dSNamhyung Kim return n; 488aca7a94dSNamhyung Kim } 489aca7a94dSNamhyung Kim 490aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 491aca7a94dSNamhyung Kim { 492aca7a94dSNamhyung Kim struct rb_node *nd; 493aca7a94dSNamhyung Kim int n = 0; 494aca7a94dSNamhyung Kim 495aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 496aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 497aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 498aca7a94dSNamhyung Kim } 499aca7a94dSNamhyung Kim 500aca7a94dSNamhyung Kim return n; 501aca7a94dSNamhyung Kim } 502aca7a94dSNamhyung Kim 503492b1010SNamhyung Kim static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he, 504492b1010SNamhyung Kim bool unfold __maybe_unused) 505492b1010SNamhyung Kim { 506492b1010SNamhyung Kim float percent; 507492b1010SNamhyung Kim struct rb_node *nd; 508492b1010SNamhyung Kim struct hist_entry *child; 509492b1010SNamhyung Kim int n = 0; 510492b1010SNamhyung Kim 511492b1010SNamhyung Kim for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) { 512492b1010SNamhyung Kim child = rb_entry(nd, struct hist_entry, rb_node); 513492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(child); 514492b1010SNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) 515492b1010SNamhyung Kim n++; 516492b1010SNamhyung Kim } 517492b1010SNamhyung Kim 518492b1010SNamhyung Kim return n; 519492b1010SNamhyung Kim } 520492b1010SNamhyung Kim 521b33f9226SJiri Olsa static void __hist_entry__set_folding(struct hist_entry *he, 522492b1010SNamhyung Kim struct hist_browser *hb, bool unfold) 523aca7a94dSNamhyung Kim { 52405e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 5253698dab1SNamhyung Kim he->unfolded = unfold ? he->has_children : false; 526aca7a94dSNamhyung Kim 5273698dab1SNamhyung Kim if (he->has_children) { 528492b1010SNamhyung Kim int n; 529492b1010SNamhyung Kim 530492b1010SNamhyung Kim if (he->leaf) 531492b1010SNamhyung Kim n = callchain__set_folding(&he->sorted_chain, unfold); 532492b1010SNamhyung Kim else 533492b1010SNamhyung Kim n = hierarchy_set_folding(hb, he, unfold); 534492b1010SNamhyung Kim 53505e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 536aca7a94dSNamhyung Kim } else 53705e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 538aca7a94dSNamhyung Kim } 539aca7a94dSNamhyung Kim 540b33f9226SJiri Olsa static void hist_entry__set_folding(struct hist_entry *he, 541b33f9226SJiri Olsa struct hist_browser *browser, bool unfold) 542aca7a94dSNamhyung Kim { 543492b1010SNamhyung Kim double percent; 544aca7a94dSNamhyung Kim 545492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(he); 546492b1010SNamhyung Kim if (he->filtered || percent < browser->min_pcnt) 547b33f9226SJiri Olsa return; 548b33f9226SJiri Olsa 549b33f9226SJiri Olsa __hist_entry__set_folding(he, browser, unfold); 550492b1010SNamhyung Kim 551492b1010SNamhyung Kim if (!he->depth || unfold) 552492b1010SNamhyung Kim browser->nr_hierarchy_entries++; 553492b1010SNamhyung Kim if (he->leaf) 554c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 55579dded87SNamhyung Kim else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) { 55679dded87SNamhyung Kim browser->nr_hierarchy_entries++; 55779dded87SNamhyung Kim he->has_no_entry = true; 55879dded87SNamhyung Kim he->nr_rows = 1; 55979dded87SNamhyung Kim } else 56079dded87SNamhyung Kim he->has_no_entry = false; 561aca7a94dSNamhyung Kim } 562b33f9226SJiri Olsa 563b33f9226SJiri Olsa static void 564b33f9226SJiri Olsa __hist_browser__set_folding(struct hist_browser *browser, bool unfold) 565b33f9226SJiri Olsa { 566b33f9226SJiri Olsa struct rb_node *nd; 567b33f9226SJiri Olsa struct hist_entry *he; 568b33f9226SJiri Olsa 569b33f9226SJiri Olsa nd = rb_first(&browser->hists->entries); 570b33f9226SJiri Olsa while (nd) { 571b33f9226SJiri Olsa he = rb_entry(nd, struct hist_entry, rb_node); 572b33f9226SJiri Olsa 573b33f9226SJiri Olsa /* set folding state even if it's currently folded */ 574b33f9226SJiri Olsa nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 575b33f9226SJiri Olsa 576b33f9226SJiri Olsa hist_entry__set_folding(he, browser, unfold); 577b33f9226SJiri Olsa } 578aca7a94dSNamhyung Kim } 579aca7a94dSNamhyung Kim 58005e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 581aca7a94dSNamhyung Kim { 582492b1010SNamhyung Kim browser->nr_hierarchy_entries = 0; 583c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 584c3b78952SNamhyung Kim __hist_browser__set_folding(browser, unfold); 585c3b78952SNamhyung Kim 586c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 587aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 58805e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 589aca7a94dSNamhyung Kim } 590aca7a94dSNamhyung Kim 5910e3fa7a7SJiri Olsa static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold) 5920e3fa7a7SJiri Olsa { 5930e3fa7a7SJiri Olsa if (!browser->he_selection) 5940e3fa7a7SJiri Olsa return; 5950e3fa7a7SJiri Olsa 5960e3fa7a7SJiri Olsa hist_entry__set_folding(browser->he_selection, browser, unfold); 5970e3fa7a7SJiri Olsa browser->b.nr_entries = hist_browser__nr_entries(browser); 5980e3fa7a7SJiri Olsa } 5990e3fa7a7SJiri Olsa 600aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 601aca7a94dSNamhyung Kim { 602aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 603aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 604aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 605aca7a94dSNamhyung Kim " perf top -r 80\n\n" 606aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 607aca7a94dSNamhyung Kim } 608aca7a94dSNamhyung Kim 6095b91a86fSJiri Olsa static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size) 6105b91a86fSJiri Olsa { 6115b91a86fSJiri Olsa return browser->title ? browser->title(browser, bf, size) : 0; 6125b91a86fSJiri Olsa } 6135b91a86fSJiri Olsa 61406cc1a47SKan Liang int hist_browser__run(struct hist_browser *browser, const char *help, 61506cc1a47SKan Liang bool warn_lost_event) 616aca7a94dSNamhyung Kim { 617aca7a94dSNamhyung Kim int key; 618aca7a94dSNamhyung Kim char title[160]; 619c2a51ab8SNamhyung Kim struct hist_browser_timer *hbt = browser->hbt; 6209783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 621aca7a94dSNamhyung Kim 62205e8b080SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 623c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 624aca7a94dSNamhyung Kim 6255b91a86fSJiri Olsa hist_browser__title(browser, title, sizeof(title)); 626aca7a94dSNamhyung Kim 627090cff3eSNamhyung Kim if (ui_browser__show(&browser->b, title, "%s", help) < 0) 628aca7a94dSNamhyung Kim return -1; 629aca7a94dSNamhyung Kim 630aca7a94dSNamhyung Kim while (1) { 63105e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 632aca7a94dSNamhyung Kim 633aca7a94dSNamhyung Kim switch (key) { 634fa5df943SNamhyung Kim case K_TIMER: { 635fa5df943SNamhyung Kim u64 nr_entries; 6369783adf7SNamhyung Kim hbt->timer(hbt->arg); 637fa5df943SNamhyung Kim 638c6111523SNamhyung Kim if (hist_browser__has_filter(browser) || 639c6111523SNamhyung Kim symbol_conf.report_hierarchy) 640112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 641fa5df943SNamhyung Kim 642c3b78952SNamhyung Kim nr_entries = hist_browser__nr_entries(browser); 643fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 644aca7a94dSNamhyung Kim 64506cc1a47SKan Liang if (warn_lost_event && 64606cc1a47SKan Liang (browser->hists->stats.nr_lost_warned != 64706cc1a47SKan Liang browser->hists->stats.nr_events[PERF_RECORD_LOST])) { 64805e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 64905e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 65005e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 651aca7a94dSNamhyung Kim } 652aca7a94dSNamhyung Kim 6535b91a86fSJiri Olsa hist_browser__title(browser, title, sizeof(title)); 65405e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 655aca7a94dSNamhyung Kim continue; 656fa5df943SNamhyung Kim } 657aca7a94dSNamhyung Kim case 'D': { /* Debug */ 658aca7a94dSNamhyung Kim static int seq; 65905e8b080SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, 660aca7a94dSNamhyung Kim struct hist_entry, rb_node); 661aca7a94dSNamhyung Kim ui_helpline__pop(); 662fdae6400SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 66305e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 66405e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries, 665fdae6400SArnaldo Carvalho de Melo browser->b.extra_title_lines, 66662c95ae3SArnaldo Carvalho de Melo browser->b.rows, 66705e8b080SArnaldo Carvalho de Melo browser->b.index, 66805e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 669aca7a94dSNamhyung Kim h->row_offset, h->nr_rows); 670aca7a94dSNamhyung Kim } 671aca7a94dSNamhyung Kim break; 672aca7a94dSNamhyung Kim case 'C': 673aca7a94dSNamhyung Kim /* Collapse the whole world. */ 67405e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 675aca7a94dSNamhyung Kim break; 6760e3fa7a7SJiri Olsa case 'c': 6770e3fa7a7SJiri Olsa /* Collapse the selected entry. */ 6780e3fa7a7SJiri Olsa hist_browser__set_folding_selected(browser, false); 6790e3fa7a7SJiri Olsa break; 680aca7a94dSNamhyung Kim case 'E': 681aca7a94dSNamhyung Kim /* Expand the whole world. */ 68205e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 683aca7a94dSNamhyung Kim break; 6840e3fa7a7SJiri Olsa case 'e': 6850e3fa7a7SJiri Olsa /* Expand the selected entry. */ 6860e3fa7a7SJiri Olsa hist_browser__set_folding_selected(browser, true); 6870e3fa7a7SJiri Olsa break; 688025bf7eaSArnaldo Carvalho de Melo case 'H': 689025bf7eaSArnaldo Carvalho de Melo browser->show_headers = !browser->show_headers; 690025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(browser); 691025bf7eaSArnaldo Carvalho de Melo break; 692aca7a94dSNamhyung Kim case K_ENTER: 69305e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 694aca7a94dSNamhyung Kim break; 695aca7a94dSNamhyung Kim /* fall thru */ 696aca7a94dSNamhyung Kim default: 697aca7a94dSNamhyung Kim goto out; 698aca7a94dSNamhyung Kim } 699aca7a94dSNamhyung Kim } 700aca7a94dSNamhyung Kim out: 70105e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 702aca7a94dSNamhyung Kim return key; 703aca7a94dSNamhyung Kim } 704aca7a94dSNamhyung Kim 70539ee533fSNamhyung Kim struct callchain_print_arg { 70639ee533fSNamhyung Kim /* for hists browser */ 70739ee533fSNamhyung Kim off_t row_offset; 70839ee533fSNamhyung Kim bool is_current_entry; 70939ee533fSNamhyung Kim 71039ee533fSNamhyung Kim /* for file dump */ 71139ee533fSNamhyung Kim FILE *fp; 71239ee533fSNamhyung Kim int printed; 71339ee533fSNamhyung Kim }; 71439ee533fSNamhyung Kim 71539ee533fSNamhyung Kim typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, 71639ee533fSNamhyung Kim struct callchain_list *chain, 71739ee533fSNamhyung Kim const char *str, int offset, 71839ee533fSNamhyung Kim unsigned short row, 71939ee533fSNamhyung Kim struct callchain_print_arg *arg); 72039ee533fSNamhyung Kim 721f4536dddSNamhyung Kim static void hist_browser__show_callchain_entry(struct hist_browser *browser, 722f4536dddSNamhyung Kim struct callchain_list *chain, 72339ee533fSNamhyung Kim const char *str, int offset, 72439ee533fSNamhyung Kim unsigned short row, 72539ee533fSNamhyung Kim struct callchain_print_arg *arg) 726f4536dddSNamhyung Kim { 727f4536dddSNamhyung Kim int color, width; 72839ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 72970e97278SArnaldo Carvalho de Melo bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src; 730f4536dddSNamhyung Kim 731f4536dddSNamhyung Kim color = HE_COLORSET_NORMAL; 732f4536dddSNamhyung Kim width = browser->b.width - (offset + 2); 733f4536dddSNamhyung Kim if (ui_browser__is_current_entry(&browser->b, row)) { 734f4536dddSNamhyung Kim browser->selection = &chain->ms; 735f4536dddSNamhyung Kim color = HE_COLORSET_SELECTED; 73639ee533fSNamhyung Kim arg->is_current_entry = true; 737f4536dddSNamhyung Kim } 738f4536dddSNamhyung Kim 739f4536dddSNamhyung Kim ui_browser__set_color(&browser->b, color); 740ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 74126270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, " ", offset); 742517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c", folded_sign); 74370e97278SArnaldo Carvalho de Melo ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); 74426270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, str, width); 745f4536dddSNamhyung Kim } 746f4536dddSNamhyung Kim 74739ee533fSNamhyung Kim static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, 74839ee533fSNamhyung Kim struct callchain_list *chain, 74939ee533fSNamhyung Kim const char *str, int offset, 75039ee533fSNamhyung Kim unsigned short row __maybe_unused, 75139ee533fSNamhyung Kim struct callchain_print_arg *arg) 75239ee533fSNamhyung Kim { 75339ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 75439ee533fSNamhyung Kim 75539ee533fSNamhyung Kim arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", 75639ee533fSNamhyung Kim folded_sign, str); 75739ee533fSNamhyung Kim } 75839ee533fSNamhyung Kim 75939ee533fSNamhyung Kim typedef bool (*check_output_full_fn)(struct hist_browser *browser, 76039ee533fSNamhyung Kim unsigned short row); 76139ee533fSNamhyung Kim 76239ee533fSNamhyung Kim static bool hist_browser__check_output_full(struct hist_browser *browser, 76339ee533fSNamhyung Kim unsigned short row) 76439ee533fSNamhyung Kim { 76539ee533fSNamhyung Kim return browser->b.rows == row; 76639ee533fSNamhyung Kim } 76739ee533fSNamhyung Kim 76839ee533fSNamhyung Kim static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, 76939ee533fSNamhyung Kim unsigned short row __maybe_unused) 77039ee533fSNamhyung Kim { 77139ee533fSNamhyung Kim return false; 77239ee533fSNamhyung Kim } 77339ee533fSNamhyung Kim 774aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 775aca7a94dSNamhyung Kim 77618bb8381SNamhyung Kim static int hist_browser__show_callchain_list(struct hist_browser *browser, 77718bb8381SNamhyung Kim struct callchain_node *node, 77818bb8381SNamhyung Kim struct callchain_list *chain, 77918bb8381SNamhyung Kim unsigned short row, u64 total, 78018bb8381SNamhyung Kim bool need_percent, int offset, 78118bb8381SNamhyung Kim print_callchain_entry_fn print, 78218bb8381SNamhyung Kim struct callchain_print_arg *arg) 78318bb8381SNamhyung Kim { 78418bb8381SNamhyung Kim char bf[1024], *alloc_str; 785fef51ecdSJin Yao char buf[64], *alloc_str2; 78618bb8381SNamhyung Kim const char *str; 7872a704fc8SMilian Wolff int ret = 1; 78818bb8381SNamhyung Kim 78918bb8381SNamhyung Kim if (arg->row_offset != 0) { 79018bb8381SNamhyung Kim arg->row_offset--; 79118bb8381SNamhyung Kim return 0; 79218bb8381SNamhyung Kim } 79318bb8381SNamhyung Kim 79418bb8381SNamhyung Kim alloc_str = NULL; 795fef51ecdSJin Yao alloc_str2 = NULL; 796fef51ecdSJin Yao 79718bb8381SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 79818bb8381SNamhyung Kim browser->show_dso); 79918bb8381SNamhyung Kim 800fef51ecdSJin Yao if (symbol_conf.show_branchflag_count) { 801c4ee0625SJin Yao callchain_list_counts__printf_value(chain, NULL, 802fef51ecdSJin Yao buf, sizeof(buf)); 80318bb8381SNamhyung Kim 804fef51ecdSJin Yao if (asprintf(&alloc_str2, "%s%s", str, buf) < 0) 805fef51ecdSJin Yao str = "Not enough memory!"; 806fef51ecdSJin Yao else 807fef51ecdSJin Yao str = alloc_str2; 808fef51ecdSJin Yao } 809fef51ecdSJin Yao 810fef51ecdSJin Yao if (need_percent) { 81118bb8381SNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), 81218bb8381SNamhyung Kim total); 81318bb8381SNamhyung Kim 81418bb8381SNamhyung Kim if (asprintf(&alloc_str, "%s %s", buf, str) < 0) 81518bb8381SNamhyung Kim str = "Not enough memory!"; 81618bb8381SNamhyung Kim else 81718bb8381SNamhyung Kim str = alloc_str; 81818bb8381SNamhyung Kim } 81918bb8381SNamhyung Kim 82018bb8381SNamhyung Kim print(browser, chain, str, offset, row, arg); 82118bb8381SNamhyung Kim free(alloc_str); 822fef51ecdSJin Yao free(alloc_str2); 8230d3eb0b7SJin Yao 8242a704fc8SMilian Wolff return ret; 82518bb8381SNamhyung Kim } 82618bb8381SNamhyung Kim 82759c624e2SNamhyung Kim static bool check_percent_display(struct rb_node *node, u64 parent_total) 82859c624e2SNamhyung Kim { 82959c624e2SNamhyung Kim struct callchain_node *child; 83059c624e2SNamhyung Kim 83159c624e2SNamhyung Kim if (node == NULL) 83259c624e2SNamhyung Kim return false; 83359c624e2SNamhyung Kim 83459c624e2SNamhyung Kim if (rb_next(node)) 83559c624e2SNamhyung Kim return true; 83659c624e2SNamhyung Kim 83759c624e2SNamhyung Kim child = rb_entry(node, struct callchain_node, rb_node); 83859c624e2SNamhyung Kim return callchain_cumul_hits(child) != parent_total; 83959c624e2SNamhyung Kim } 84059c624e2SNamhyung Kim 8414b3a3212SNamhyung Kim static int hist_browser__show_callchain_flat(struct hist_browser *browser, 8424b3a3212SNamhyung Kim struct rb_root *root, 8434b3a3212SNamhyung Kim unsigned short row, u64 total, 84459c624e2SNamhyung Kim u64 parent_total, 8454b3a3212SNamhyung Kim print_callchain_entry_fn print, 8464b3a3212SNamhyung Kim struct callchain_print_arg *arg, 8474b3a3212SNamhyung Kim check_output_full_fn is_output_full) 8484b3a3212SNamhyung Kim { 8494b3a3212SNamhyung Kim struct rb_node *node; 8504b3a3212SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 8514b3a3212SNamhyung Kim bool need_percent; 8524b3a3212SNamhyung Kim 8534b3a3212SNamhyung Kim node = rb_first(root); 85459c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 8554b3a3212SNamhyung Kim 8564b3a3212SNamhyung Kim while (node) { 8574b3a3212SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 8584b3a3212SNamhyung Kim struct rb_node *next = rb_next(node); 8594b3a3212SNamhyung Kim struct callchain_list *chain; 8604b3a3212SNamhyung Kim char folded_sign = ' '; 8614b3a3212SNamhyung Kim int first = true; 8624b3a3212SNamhyung Kim int extra_offset = 0; 8634b3a3212SNamhyung Kim 8644b3a3212SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 8654b3a3212SNamhyung Kim bool was_first = first; 8664b3a3212SNamhyung Kim 8674b3a3212SNamhyung Kim if (first) 8684b3a3212SNamhyung Kim first = false; 8694b3a3212SNamhyung Kim else if (need_percent) 8704b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 8714b3a3212SNamhyung Kim 8724b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 8734b3a3212SNamhyung Kim 8744b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 8754b3a3212SNamhyung Kim chain, row, total, 8764b3a3212SNamhyung Kim was_first && need_percent, 8774b3a3212SNamhyung Kim offset + extra_offset, 8784b3a3212SNamhyung Kim print, arg); 8794b3a3212SNamhyung Kim 8804b3a3212SNamhyung Kim if (is_output_full(browser, row)) 8814b3a3212SNamhyung Kim goto out; 8824b3a3212SNamhyung Kim 8834b3a3212SNamhyung Kim if (folded_sign == '+') 8844b3a3212SNamhyung Kim goto next; 8854b3a3212SNamhyung Kim } 8864b3a3212SNamhyung Kim 8874b3a3212SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 8884b3a3212SNamhyung Kim bool was_first = first; 8894b3a3212SNamhyung Kim 8904b3a3212SNamhyung Kim if (first) 8914b3a3212SNamhyung Kim first = false; 8924b3a3212SNamhyung Kim else if (need_percent) 8934b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 8944b3a3212SNamhyung Kim 8954b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 8964b3a3212SNamhyung Kim 8974b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 8984b3a3212SNamhyung Kim chain, row, total, 8994b3a3212SNamhyung Kim was_first && need_percent, 9004b3a3212SNamhyung Kim offset + extra_offset, 9014b3a3212SNamhyung Kim print, arg); 9024b3a3212SNamhyung Kim 9034b3a3212SNamhyung Kim if (is_output_full(browser, row)) 9044b3a3212SNamhyung Kim goto out; 9054b3a3212SNamhyung Kim 9064b3a3212SNamhyung Kim if (folded_sign == '+') 9074b3a3212SNamhyung Kim break; 9084b3a3212SNamhyung Kim } 9094b3a3212SNamhyung Kim 9104b3a3212SNamhyung Kim next: 9114b3a3212SNamhyung Kim if (is_output_full(browser, row)) 9124b3a3212SNamhyung Kim break; 9134b3a3212SNamhyung Kim node = next; 9144b3a3212SNamhyung Kim } 9154b3a3212SNamhyung Kim out: 9164b3a3212SNamhyung Kim return row - first_row; 9174b3a3212SNamhyung Kim } 9184b3a3212SNamhyung Kim 9198c430a34SNamhyung Kim static char *hist_browser__folded_callchain_str(struct hist_browser *browser, 9208c430a34SNamhyung Kim struct callchain_list *chain, 9218c430a34SNamhyung Kim char *value_str, char *old_str) 9228c430a34SNamhyung Kim { 9238c430a34SNamhyung Kim char bf[1024]; 9248c430a34SNamhyung Kim const char *str; 9258c430a34SNamhyung Kim char *new; 9268c430a34SNamhyung Kim 9278c430a34SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 9288c430a34SNamhyung Kim browser->show_dso); 9298c430a34SNamhyung Kim if (old_str) { 9308c430a34SNamhyung Kim if (asprintf(&new, "%s%s%s", old_str, 9318c430a34SNamhyung Kim symbol_conf.field_sep ?: ";", str) < 0) 9328c430a34SNamhyung Kim new = NULL; 9338c430a34SNamhyung Kim } else { 9348c430a34SNamhyung Kim if (value_str) { 9358c430a34SNamhyung Kim if (asprintf(&new, "%s %s", value_str, str) < 0) 9368c430a34SNamhyung Kim new = NULL; 9378c430a34SNamhyung Kim } else { 9388c430a34SNamhyung Kim if (asprintf(&new, "%s", str) < 0) 9398c430a34SNamhyung Kim new = NULL; 9408c430a34SNamhyung Kim } 9418c430a34SNamhyung Kim } 9428c430a34SNamhyung Kim return new; 9438c430a34SNamhyung Kim } 9448c430a34SNamhyung Kim 9458c430a34SNamhyung Kim static int hist_browser__show_callchain_folded(struct hist_browser *browser, 9468c430a34SNamhyung Kim struct rb_root *root, 9478c430a34SNamhyung Kim unsigned short row, u64 total, 94859c624e2SNamhyung Kim u64 parent_total, 9498c430a34SNamhyung Kim print_callchain_entry_fn print, 9508c430a34SNamhyung Kim struct callchain_print_arg *arg, 9518c430a34SNamhyung Kim check_output_full_fn is_output_full) 9528c430a34SNamhyung Kim { 9538c430a34SNamhyung Kim struct rb_node *node; 9548c430a34SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 9558c430a34SNamhyung Kim bool need_percent; 9568c430a34SNamhyung Kim 9578c430a34SNamhyung Kim node = rb_first(root); 95859c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 9598c430a34SNamhyung Kim 9608c430a34SNamhyung Kim while (node) { 9618c430a34SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 9628c430a34SNamhyung Kim struct rb_node *next = rb_next(node); 9638c430a34SNamhyung Kim struct callchain_list *chain, *first_chain = NULL; 9648c430a34SNamhyung Kim int first = true; 9658c430a34SNamhyung Kim char *value_str = NULL, *value_str_alloc = NULL; 9668c430a34SNamhyung Kim char *chain_str = NULL, *chain_str_alloc = NULL; 9678c430a34SNamhyung Kim 9688c430a34SNamhyung Kim if (arg->row_offset != 0) { 9698c430a34SNamhyung Kim arg->row_offset--; 9708c430a34SNamhyung Kim goto next; 9718c430a34SNamhyung Kim } 9728c430a34SNamhyung Kim 9738c430a34SNamhyung Kim if (need_percent) { 9748c430a34SNamhyung Kim char buf[64]; 9758c430a34SNamhyung Kim 9768c430a34SNamhyung Kim callchain_node__scnprintf_value(child, buf, sizeof(buf), total); 9778c430a34SNamhyung Kim if (asprintf(&value_str, "%s", buf) < 0) { 9788c430a34SNamhyung Kim value_str = (char *)"<...>"; 9798c430a34SNamhyung Kim goto do_print; 9808c430a34SNamhyung Kim } 9818c430a34SNamhyung Kim value_str_alloc = value_str; 9828c430a34SNamhyung Kim } 9838c430a34SNamhyung Kim 9848c430a34SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 9858c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 9868c430a34SNamhyung Kim chain, value_str, chain_str); 9878c430a34SNamhyung Kim if (first) { 9888c430a34SNamhyung Kim first = false; 9898c430a34SNamhyung Kim first_chain = chain; 9908c430a34SNamhyung Kim } 9918c430a34SNamhyung Kim 9928c430a34SNamhyung Kim if (chain_str == NULL) { 9938c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 9948c430a34SNamhyung Kim goto do_print; 9958c430a34SNamhyung Kim } 9968c430a34SNamhyung Kim 9978c430a34SNamhyung Kim chain_str_alloc = chain_str; 9988c430a34SNamhyung Kim } 9998c430a34SNamhyung Kim 10008c430a34SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 10018c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 10028c430a34SNamhyung Kim chain, value_str, chain_str); 10038c430a34SNamhyung Kim if (first) { 10048c430a34SNamhyung Kim first = false; 10058c430a34SNamhyung Kim first_chain = chain; 10068c430a34SNamhyung Kim } 10078c430a34SNamhyung Kim 10088c430a34SNamhyung Kim if (chain_str == NULL) { 10098c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 10108c430a34SNamhyung Kim goto do_print; 10118c430a34SNamhyung Kim } 10128c430a34SNamhyung Kim 10138c430a34SNamhyung Kim chain_str_alloc = chain_str; 10148c430a34SNamhyung Kim } 10158c430a34SNamhyung Kim 10168c430a34SNamhyung Kim do_print: 10178c430a34SNamhyung Kim print(browser, first_chain, chain_str, offset, row++, arg); 10188c430a34SNamhyung Kim free(value_str_alloc); 10198c430a34SNamhyung Kim free(chain_str_alloc); 10208c430a34SNamhyung Kim 10218c430a34SNamhyung Kim next: 10228c430a34SNamhyung Kim if (is_output_full(browser, row)) 10238c430a34SNamhyung Kim break; 10248c430a34SNamhyung Kim node = next; 10258c430a34SNamhyung Kim } 10268c430a34SNamhyung Kim 10278c430a34SNamhyung Kim return row - first_row; 10288c430a34SNamhyung Kim } 10298c430a34SNamhyung Kim 10300c841c6cSNamhyung Kim static int hist_browser__show_callchain_graph(struct hist_browser *browser, 1031c09a7e75SNamhyung Kim struct rb_root *root, int level, 103239ee533fSNamhyung Kim unsigned short row, u64 total, 10335eca104eSNamhyung Kim u64 parent_total, 103439ee533fSNamhyung Kim print_callchain_entry_fn print, 103539ee533fSNamhyung Kim struct callchain_print_arg *arg, 103639ee533fSNamhyung Kim check_output_full_fn is_output_full) 1037aca7a94dSNamhyung Kim { 1038aca7a94dSNamhyung Kim struct rb_node *node; 1039f4536dddSNamhyung Kim int first_row = row, offset = level * LEVEL_OFFSET_STEP; 10404087d11cSNamhyung Kim bool need_percent; 10415eca104eSNamhyung Kim u64 percent_total = total; 10425eca104eSNamhyung Kim 10435eca104eSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 10445eca104eSNamhyung Kim percent_total = parent_total; 1045aca7a94dSNamhyung Kim 1046c09a7e75SNamhyung Kim node = rb_first(root); 104759c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 10484087d11cSNamhyung Kim 1049aca7a94dSNamhyung Kim while (node) { 1050aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 1051aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 1052aca7a94dSNamhyung Kim struct callchain_list *chain; 1053aca7a94dSNamhyung Kim char folded_sign = ' '; 1054aca7a94dSNamhyung Kim int first = true; 1055aca7a94dSNamhyung Kim int extra_offset = 0; 1056aca7a94dSNamhyung Kim 1057aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 1058aca7a94dSNamhyung Kim bool was_first = first; 1059aca7a94dSNamhyung Kim 1060aca7a94dSNamhyung Kim if (first) 1061aca7a94dSNamhyung Kim first = false; 10624087d11cSNamhyung Kim else if (need_percent) 1063aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 1064aca7a94dSNamhyung Kim 1065aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 1066aca7a94dSNamhyung Kim 106718bb8381SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 10685eca104eSNamhyung Kim chain, row, percent_total, 106918bb8381SNamhyung Kim was_first && need_percent, 107018bb8381SNamhyung Kim offset + extra_offset, 107118bb8381SNamhyung Kim print, arg); 1072c09a7e75SNamhyung Kim 107318bb8381SNamhyung Kim if (is_output_full(browser, row)) 1074aca7a94dSNamhyung Kim goto out; 107518bb8381SNamhyung Kim 1076aca7a94dSNamhyung Kim if (folded_sign == '+') 1077aca7a94dSNamhyung Kim break; 1078aca7a94dSNamhyung Kim } 1079aca7a94dSNamhyung Kim 1080aca7a94dSNamhyung Kim if (folded_sign == '-') { 1081aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 1082c09a7e75SNamhyung Kim 10830c841c6cSNamhyung Kim row += hist_browser__show_callchain_graph(browser, &child->rb_root, 10845eca104eSNamhyung Kim new_level, row, total, 10855eca104eSNamhyung Kim child->children_hit, 108639ee533fSNamhyung Kim print, arg, is_output_full); 1087aca7a94dSNamhyung Kim } 108839ee533fSNamhyung Kim if (is_output_full(browser, row)) 1089c09a7e75SNamhyung Kim break; 1090aca7a94dSNamhyung Kim node = next; 1091aca7a94dSNamhyung Kim } 1092aca7a94dSNamhyung Kim out: 1093aca7a94dSNamhyung Kim return row - first_row; 1094aca7a94dSNamhyung Kim } 1095aca7a94dSNamhyung Kim 10960c841c6cSNamhyung Kim static int hist_browser__show_callchain(struct hist_browser *browser, 10970c841c6cSNamhyung Kim struct hist_entry *entry, int level, 10980c841c6cSNamhyung Kim unsigned short row, 10990c841c6cSNamhyung Kim print_callchain_entry_fn print, 11000c841c6cSNamhyung Kim struct callchain_print_arg *arg, 11010c841c6cSNamhyung Kim check_output_full_fn is_output_full) 11020c841c6cSNamhyung Kim { 11030c841c6cSNamhyung Kim u64 total = hists__total_period(entry->hists); 11045eca104eSNamhyung Kim u64 parent_total; 11050c841c6cSNamhyung Kim int printed; 11060c841c6cSNamhyung Kim 11070c841c6cSNamhyung Kim if (symbol_conf.cumulate_callchain) 11085eca104eSNamhyung Kim parent_total = entry->stat_acc->period; 11090c841c6cSNamhyung Kim else 11105eca104eSNamhyung Kim parent_total = entry->stat.period; 11110c841c6cSNamhyung Kim 11120c841c6cSNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) { 11130c841c6cSNamhyung Kim printed = hist_browser__show_callchain_flat(browser, 11145eca104eSNamhyung Kim &entry->sorted_chain, row, 11155eca104eSNamhyung Kim total, parent_total, print, arg, 11165eca104eSNamhyung Kim is_output_full); 11170c841c6cSNamhyung Kim } else if (callchain_param.mode == CHAIN_FOLDED) { 11180c841c6cSNamhyung Kim printed = hist_browser__show_callchain_folded(browser, 11195eca104eSNamhyung Kim &entry->sorted_chain, row, 11205eca104eSNamhyung Kim total, parent_total, print, arg, 11215eca104eSNamhyung Kim is_output_full); 11220c841c6cSNamhyung Kim } else { 11230c841c6cSNamhyung Kim printed = hist_browser__show_callchain_graph(browser, 11245eca104eSNamhyung Kim &entry->sorted_chain, level, row, 11255eca104eSNamhyung Kim total, parent_total, print, arg, 11265eca104eSNamhyung Kim is_output_full); 11270c841c6cSNamhyung Kim } 11280c841c6cSNamhyung Kim 11290c841c6cSNamhyung Kim if (arg->is_current_entry) 11300c841c6cSNamhyung Kim browser->he_selection = entry; 11310c841c6cSNamhyung Kim 11320c841c6cSNamhyung Kim return printed; 11330c841c6cSNamhyung Kim } 11340c841c6cSNamhyung Kim 113589701460SNamhyung Kim struct hpp_arg { 113689701460SNamhyung Kim struct ui_browser *b; 113789701460SNamhyung Kim char folded_sign; 113889701460SNamhyung Kim bool current_entry; 113989701460SNamhyung Kim }; 114089701460SNamhyung Kim 114198ba1609SJiri Olsa int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 11422f6d9009SNamhyung Kim { 11432f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 1144d675107cSNamhyung Kim int ret, len; 11452f6d9009SNamhyung Kim va_list args; 11462f6d9009SNamhyung Kim double percent; 11472f6d9009SNamhyung Kim 11482f6d9009SNamhyung Kim va_start(args, fmt); 1149d675107cSNamhyung Kim len = va_arg(args, int); 11502f6d9009SNamhyung Kim percent = va_arg(args, double); 11512f6d9009SNamhyung Kim va_end(args); 11525aed9d24SNamhyung Kim 115389701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 11545aed9d24SNamhyung Kim 1155d675107cSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); 1156517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); 115789701460SNamhyung Kim 11585aed9d24SNamhyung Kim return ret; 1159f5951d56SNamhyung Kim } 1160f5951d56SNamhyung Kim 1161fb821c9eSNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field) \ 11625aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 11635aed9d24SNamhyung Kim { \ 11645aed9d24SNamhyung Kim return he->stat._field; \ 11655aed9d24SNamhyung Kim } \ 11665aed9d24SNamhyung Kim \ 11672c5d4b4aSJiri Olsa static int \ 11685b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 11692c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 11705aed9d24SNamhyung Kim struct hist_entry *he) \ 11715aed9d24SNamhyung Kim { \ 11725b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \ 11732f6d9009SNamhyung Kim __hpp__slsmg_color_printf, true); \ 11745aed9d24SNamhyung Kim } 1175f5951d56SNamhyung Kim 11760434ddd2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 11770434ddd2SNamhyung Kim static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ 11780434ddd2SNamhyung Kim { \ 11790434ddd2SNamhyung Kim return he->stat_acc->_field; \ 11800434ddd2SNamhyung Kim } \ 11810434ddd2SNamhyung Kim \ 11820434ddd2SNamhyung Kim static int \ 11835b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 11840434ddd2SNamhyung Kim struct perf_hpp *hpp, \ 11850434ddd2SNamhyung Kim struct hist_entry *he) \ 11860434ddd2SNamhyung Kim { \ 11870434ddd2SNamhyung Kim if (!symbol_conf.cumulate_callchain) { \ 1188517dfdb3SArnaldo Carvalho de Melo struct hpp_arg *arg = hpp->ptr; \ 11895b591669SNamhyung Kim int len = fmt->user_len ?: fmt->len; \ 1190d675107cSNamhyung Kim int ret = scnprintf(hpp->buf, hpp->size, \ 11915b591669SNamhyung Kim "%*s", len, "N/A"); \ 1192517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); \ 11930434ddd2SNamhyung Kim \ 11940434ddd2SNamhyung Kim return ret; \ 11950434ddd2SNamhyung Kim } \ 11965b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \ 11975b591669SNamhyung Kim " %*.2f%%", __hpp__slsmg_color_printf, true); \ 11980434ddd2SNamhyung Kim } 11990434ddd2SNamhyung Kim 1200fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period) 1201fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 1202fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us) 1203fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 1204fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 12050434ddd2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period) 12065aed9d24SNamhyung Kim 12075aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 12080434ddd2SNamhyung Kim #undef __HPP_COLOR_ACC_PERCENT_FN 1209f5951d56SNamhyung Kim 1210f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 1211f5951d56SNamhyung Kim { 1212f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 1213f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 1214f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 1215f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 1216f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 1217f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 1218f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 1219f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 1220f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 1221f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 12220434ddd2SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = 12230434ddd2SNamhyung Kim hist_browser__hpp_color_overhead_acc; 1224f5951d56SNamhyung Kim } 1225f5951d56SNamhyung Kim 122605e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 1227aca7a94dSNamhyung Kim struct hist_entry *entry, 1228aca7a94dSNamhyung Kim unsigned short row) 1229aca7a94dSNamhyung Kim { 12301240005eSJiri Olsa int printed = 0; 123167d25916SNamhyung Kim int width = browser->b.width; 1232aca7a94dSNamhyung Kim char folded_sign = ' '; 123305e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1234aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 123563a1a3d8SNamhyung Kim bool first = true; 12361240005eSJiri Olsa struct perf_hpp_fmt *fmt; 1237aca7a94dSNamhyung Kim 1238aca7a94dSNamhyung Kim if (current_entry) { 123905e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 124005e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 1241aca7a94dSNamhyung Kim } 1242aca7a94dSNamhyung Kim 1243aca7a94dSNamhyung Kim if (symbol_conf.use_callchain) { 1244aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 1245aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 1246aca7a94dSNamhyung Kim } 1247aca7a94dSNamhyung Kim 1248aca7a94dSNamhyung Kim if (row_offset == 0) { 124989701460SNamhyung Kim struct hpp_arg arg = { 125089701460SNamhyung Kim .b = &browser->b, 125189701460SNamhyung Kim .folded_sign = folded_sign, 125289701460SNamhyung Kim .current_entry = current_entry, 125389701460SNamhyung Kim }; 1254c6c3c02dSArnaldo Carvalho de Melo int column = 0; 1255f5951d56SNamhyung Kim 1256ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 1257f5951d56SNamhyung Kim 1258f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 125989fee709SArnaldo Carvalho de Melo char s[2048]; 126089fee709SArnaldo Carvalho de Melo struct perf_hpp hpp = { 126189fee709SArnaldo Carvalho de Melo .buf = s, 126289fee709SArnaldo Carvalho de Melo .size = sizeof(s), 126389fee709SArnaldo Carvalho de Melo .ptr = &arg, 126489fee709SArnaldo Carvalho de Melo }; 126589fee709SArnaldo Carvalho de Melo 1266361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1267361459f1SNamhyung Kim column++ < browser->b.horiz_scroll) 1268e67d49a7SNamhyung Kim continue; 1269e67d49a7SNamhyung Kim 1270fb821c9eSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1271fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1272fb821c9eSNamhyung Kim HE_COLORSET_SELECTED); 1273fb821c9eSNamhyung Kim } else { 1274fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1275fb821c9eSNamhyung Kim HE_COLORSET_NORMAL); 1276fb821c9eSNamhyung Kim } 1277fb821c9eSNamhyung Kim 1278fb821c9eSNamhyung Kim if (first) { 12792a704fc8SMilian Wolff if (symbol_conf.use_callchain) { 1280517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c ", folded_sign); 1281f5951d56SNamhyung Kim width -= 2; 1282f5951d56SNamhyung Kim } 128363a1a3d8SNamhyung Kim first = false; 1284fb821c9eSNamhyung Kim } else { 1285517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, " "); 1286fb821c9eSNamhyung Kim width -= 2; 1287fb821c9eSNamhyung Kim } 1288f5951d56SNamhyung Kim 12891240005eSJiri Olsa if (fmt->color) { 129089fee709SArnaldo Carvalho de Melo int ret = fmt->color(fmt, &hpp, entry); 129189fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 129289fee709SArnaldo Carvalho de Melo /* 129389fee709SArnaldo Carvalho de Melo * fmt->color() already used ui_browser to 129489fee709SArnaldo Carvalho de Melo * print the non alignment bits, skip it (+ret): 129589fee709SArnaldo Carvalho de Melo */ 129689fee709SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s + ret); 1297f5951d56SNamhyung Kim } else { 129889fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry)); 1299517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s); 1300f5951d56SNamhyung Kim } 130189fee709SArnaldo Carvalho de Melo width -= hpp.buf - s; 1302f5951d56SNamhyung Kim } 1303aca7a94dSNamhyung Kim 1304aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 130505e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 1306aca7a94dSNamhyung Kim width += 1; 1307aca7a94dSNamhyung Kim 130826270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, "", width); 130926d8b338SNamhyung Kim 1310aca7a94dSNamhyung Kim ++row; 1311aca7a94dSNamhyung Kim ++printed; 1312aca7a94dSNamhyung Kim } else 1313aca7a94dSNamhyung Kim --row_offset; 1314aca7a94dSNamhyung Kim 131562c95ae3SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.rows) { 131639ee533fSNamhyung Kim struct callchain_print_arg arg = { 131739ee533fSNamhyung Kim .row_offset = row_offset, 131839ee533fSNamhyung Kim .is_current_entry = current_entry, 131939ee533fSNamhyung Kim }; 1320c09a7e75SNamhyung Kim 13210d3eb0b7SJin Yao printed += hist_browser__show_callchain(browser, 13220d3eb0b7SJin Yao entry, 1, row, 13230d3eb0b7SJin Yao hist_browser__show_callchain_entry, 13240d3eb0b7SJin Yao &arg, 13254b3a3212SNamhyung Kim hist_browser__check_output_full); 1326aca7a94dSNamhyung Kim } 1327aca7a94dSNamhyung Kim 1328aca7a94dSNamhyung Kim return printed; 1329aca7a94dSNamhyung Kim } 1330aca7a94dSNamhyung Kim 1331d0506edbSNamhyung Kim static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, 1332d0506edbSNamhyung Kim struct hist_entry *entry, 1333d0506edbSNamhyung Kim unsigned short row, 13342dbbe9f2SNamhyung Kim int level) 1335d0506edbSNamhyung Kim { 1336d0506edbSNamhyung Kim int printed = 0; 1337d0506edbSNamhyung Kim int width = browser->b.width; 1338d0506edbSNamhyung Kim char folded_sign = ' '; 1339d0506edbSNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1340d0506edbSNamhyung Kim off_t row_offset = entry->row_offset; 1341d0506edbSNamhyung Kim bool first = true; 1342d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 1343a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1344d0506edbSNamhyung Kim struct hpp_arg arg = { 1345d0506edbSNamhyung Kim .b = &browser->b, 1346d0506edbSNamhyung Kim .current_entry = current_entry, 1347d0506edbSNamhyung Kim }; 1348d0506edbSNamhyung Kim int column = 0; 13492dbbe9f2SNamhyung Kim int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 1350d0506edbSNamhyung Kim 1351d0506edbSNamhyung Kim if (current_entry) { 1352d0506edbSNamhyung Kim browser->he_selection = entry; 1353d0506edbSNamhyung Kim browser->selection = &entry->ms; 1354d0506edbSNamhyung Kim } 1355d0506edbSNamhyung Kim 1356d0506edbSNamhyung Kim hist_entry__init_have_children(entry); 1357d0506edbSNamhyung Kim folded_sign = hist_entry__folded(entry); 1358d0506edbSNamhyung Kim arg.folded_sign = folded_sign; 1359d0506edbSNamhyung Kim 1360d0506edbSNamhyung Kim if (entry->leaf && row_offset) { 1361d0506edbSNamhyung Kim row_offset--; 1362d0506edbSNamhyung Kim goto show_callchain; 1363d0506edbSNamhyung Kim } 1364d0506edbSNamhyung Kim 1365ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 1366d0506edbSNamhyung Kim 1367d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) 1368d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 1369d0506edbSNamhyung Kim else 1370d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 1371d0506edbSNamhyung Kim 1372d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 1373d0506edbSNamhyung Kim width -= level * HIERARCHY_INDENT; 1374d0506edbSNamhyung Kim 1375a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1376a61a22f6SNamhyung Kim fmt_node = list_first_entry(&entry->hists->hpp_formats, 1377a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1378a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1379d0506edbSNamhyung Kim char s[2048]; 1380d0506edbSNamhyung Kim struct perf_hpp hpp = { 1381d0506edbSNamhyung Kim .buf = s, 1382d0506edbSNamhyung Kim .size = sizeof(s), 1383d0506edbSNamhyung Kim .ptr = &arg, 1384d0506edbSNamhyung Kim }; 1385d0506edbSNamhyung Kim 1386d0506edbSNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1387d0506edbSNamhyung Kim column++ < browser->b.horiz_scroll) 1388d0506edbSNamhyung Kim continue; 1389d0506edbSNamhyung Kim 1390d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1391d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1392d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1393d0506edbSNamhyung Kim } else { 1394d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1395d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1396d0506edbSNamhyung Kim } 1397d0506edbSNamhyung Kim 1398d0506edbSNamhyung Kim if (first) { 1399d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%c ", folded_sign); 14003d9f4683SNamhyung Kim width -= 2; 1401d0506edbSNamhyung Kim first = false; 1402d0506edbSNamhyung Kim } else { 1403d0506edbSNamhyung Kim ui_browser__printf(&browser->b, " "); 1404d0506edbSNamhyung Kim width -= 2; 1405d0506edbSNamhyung Kim } 1406d0506edbSNamhyung Kim 1407d0506edbSNamhyung Kim if (fmt->color) { 1408d0506edbSNamhyung Kim int ret = fmt->color(fmt, &hpp, entry); 1409d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1410d0506edbSNamhyung Kim /* 1411d0506edbSNamhyung Kim * fmt->color() already used ui_browser to 1412d0506edbSNamhyung Kim * print the non alignment bits, skip it (+ret): 1413d0506edbSNamhyung Kim */ 1414d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s + ret); 1415d0506edbSNamhyung Kim } else { 1416d0506edbSNamhyung Kim int ret = fmt->entry(fmt, &hpp, entry); 1417d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1418d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s); 1419d0506edbSNamhyung Kim } 1420d0506edbSNamhyung Kim width -= hpp.buf - s; 1421d0506edbSNamhyung Kim } 1422d0506edbSNamhyung Kim 1423b9bf911eSNamhyung Kim if (!first) { 1424d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", hierarchy_indent); 1425d0506edbSNamhyung Kim width -= hierarchy_indent; 1426b9bf911eSNamhyung Kim } 1427d0506edbSNamhyung Kim 1428d0506edbSNamhyung Kim if (column >= browser->b.horiz_scroll) { 1429d0506edbSNamhyung Kim char s[2048]; 1430d0506edbSNamhyung Kim struct perf_hpp hpp = { 1431d0506edbSNamhyung Kim .buf = s, 1432d0506edbSNamhyung Kim .size = sizeof(s), 1433d0506edbSNamhyung Kim .ptr = &arg, 1434d0506edbSNamhyung Kim }; 1435d0506edbSNamhyung Kim 1436d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1437d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1438d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1439d0506edbSNamhyung Kim } else { 1440d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1441d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1442d0506edbSNamhyung Kim } 1443d0506edbSNamhyung Kim 14441b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(entry->hpp_list, fmt) { 1445131d51ebSNamhyung Kim if (first) { 1446131d51ebSNamhyung Kim ui_browser__printf(&browser->b, "%c ", folded_sign); 1447131d51ebSNamhyung Kim first = false; 1448131d51ebSNamhyung Kim } else { 1449d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", 2); 1450131d51ebSNamhyung Kim } 1451131d51ebSNamhyung Kim 1452d0506edbSNamhyung Kim width -= 2; 1453d0506edbSNamhyung Kim 1454d0506edbSNamhyung Kim /* 1455d0506edbSNamhyung Kim * No need to call hist_entry__snprintf_alignment() 1456d0506edbSNamhyung Kim * since this fmt is always the last column in the 1457d0506edbSNamhyung Kim * hierarchy mode. 1458d0506edbSNamhyung Kim */ 1459d0506edbSNamhyung Kim if (fmt->color) { 1460d0506edbSNamhyung Kim width -= fmt->color(fmt, &hpp, entry); 1461d0506edbSNamhyung Kim } else { 1462cb1fab91SNamhyung Kim int i = 0; 1463cb1fab91SNamhyung Kim 1464d0506edbSNamhyung Kim width -= fmt->entry(fmt, &hpp, entry); 1465cb1fab91SNamhyung Kim ui_browser__printf(&browser->b, "%s", ltrim(s)); 1466cb1fab91SNamhyung Kim 1467cb1fab91SNamhyung Kim while (isspace(s[i++])) 1468cb1fab91SNamhyung Kim width++; 1469d0506edbSNamhyung Kim } 1470d0506edbSNamhyung Kim } 14711b2dbbf4SNamhyung Kim } 1472d0506edbSNamhyung Kim 1473d0506edbSNamhyung Kim /* The scroll bar isn't being used */ 1474d0506edbSNamhyung Kim if (!browser->b.navkeypressed) 1475d0506edbSNamhyung Kim width += 1; 1476d0506edbSNamhyung Kim 1477d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 1478d0506edbSNamhyung Kim 1479d0506edbSNamhyung Kim ++row; 1480d0506edbSNamhyung Kim ++printed; 1481d0506edbSNamhyung Kim 1482d0506edbSNamhyung Kim show_callchain: 1483d0506edbSNamhyung Kim if (entry->leaf && folded_sign == '-' && row != browser->b.rows) { 1484d0506edbSNamhyung Kim struct callchain_print_arg carg = { 1485d0506edbSNamhyung Kim .row_offset = row_offset, 1486d0506edbSNamhyung Kim }; 1487d0506edbSNamhyung Kim 1488d0506edbSNamhyung Kim printed += hist_browser__show_callchain(browser, entry, 1489d0506edbSNamhyung Kim level + 1, row, 1490d0506edbSNamhyung Kim hist_browser__show_callchain_entry, &carg, 1491d0506edbSNamhyung Kim hist_browser__check_output_full); 1492d0506edbSNamhyung Kim } 1493d0506edbSNamhyung Kim 1494d0506edbSNamhyung Kim return printed; 1495d0506edbSNamhyung Kim } 1496d0506edbSNamhyung Kim 149779dded87SNamhyung Kim static int hist_browser__show_no_entry(struct hist_browser *browser, 14982dbbe9f2SNamhyung Kim unsigned short row, int level) 149979dded87SNamhyung Kim { 150079dded87SNamhyung Kim int width = browser->b.width; 150179dded87SNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 150279dded87SNamhyung Kim bool first = true; 150379dded87SNamhyung Kim int column = 0; 150479dded87SNamhyung Kim int ret; 150579dded87SNamhyung Kim struct perf_hpp_fmt *fmt; 1506a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 15072dbbe9f2SNamhyung Kim int indent = browser->hists->nr_hpp_node - 2; 150879dded87SNamhyung Kim 150979dded87SNamhyung Kim if (current_entry) { 151079dded87SNamhyung Kim browser->he_selection = NULL; 151179dded87SNamhyung Kim browser->selection = NULL; 151279dded87SNamhyung Kim } 151379dded87SNamhyung Kim 1514ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 151579dded87SNamhyung Kim 151679dded87SNamhyung Kim if (current_entry && browser->b.navkeypressed) 151779dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 151879dded87SNamhyung Kim else 151979dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 152079dded87SNamhyung Kim 152179dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 152279dded87SNamhyung Kim width -= level * HIERARCHY_INDENT; 152379dded87SNamhyung Kim 1524a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1525a61a22f6SNamhyung Kim fmt_node = list_first_entry(&browser->hists->hpp_formats, 1526a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1527a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 152879dded87SNamhyung Kim if (perf_hpp__should_skip(fmt, browser->hists) || 152979dded87SNamhyung Kim column++ < browser->b.horiz_scroll) 153079dded87SNamhyung Kim continue; 153179dded87SNamhyung Kim 1532da1b0407SJiri Olsa ret = fmt->width(fmt, NULL, browser->hists); 153379dded87SNamhyung Kim 153479dded87SNamhyung Kim if (first) { 153579dded87SNamhyung Kim /* for folded sign */ 153679dded87SNamhyung Kim first = false; 153779dded87SNamhyung Kim ret++; 153879dded87SNamhyung Kim } else { 153979dded87SNamhyung Kim /* space between columns */ 154079dded87SNamhyung Kim ret += 2; 154179dded87SNamhyung Kim } 154279dded87SNamhyung Kim 154379dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", ret); 154479dded87SNamhyung Kim width -= ret; 154579dded87SNamhyung Kim } 154679dded87SNamhyung Kim 15472dbbe9f2SNamhyung Kim ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT); 15482dbbe9f2SNamhyung Kim width -= indent * HIERARCHY_INDENT; 154979dded87SNamhyung Kim 155079dded87SNamhyung Kim if (column >= browser->b.horiz_scroll) { 155179dded87SNamhyung Kim char buf[32]; 155279dded87SNamhyung Kim 155379dded87SNamhyung Kim ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt); 155479dded87SNamhyung Kim ui_browser__printf(&browser->b, " %s", buf); 155579dded87SNamhyung Kim width -= ret + 2; 155679dded87SNamhyung Kim } 155779dded87SNamhyung Kim 155879dded87SNamhyung Kim /* The scroll bar isn't being used */ 155979dded87SNamhyung Kim if (!browser->b.navkeypressed) 156079dded87SNamhyung Kim width += 1; 156179dded87SNamhyung Kim 156279dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 156379dded87SNamhyung Kim return 1; 156479dded87SNamhyung Kim } 156579dded87SNamhyung Kim 156681a888feSJiri Olsa static int advance_hpp_check(struct perf_hpp *hpp, int inc) 156781a888feSJiri Olsa { 156881a888feSJiri Olsa advance_hpp(hpp, inc); 156981a888feSJiri Olsa return hpp->size <= 0; 157081a888feSJiri Olsa } 157181a888feSJiri Olsa 157269705b35SJiri Olsa static int 157369705b35SJiri Olsa hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, 157469705b35SJiri Olsa size_t size, int line) 157581a888feSJiri Olsa { 1576c6c3c02dSArnaldo Carvalho de Melo struct hists *hists = browser->hists; 157781a888feSJiri Olsa struct perf_hpp dummy_hpp = { 157881a888feSJiri Olsa .buf = buf, 157981a888feSJiri Olsa .size = size, 158081a888feSJiri Olsa }; 158181a888feSJiri Olsa struct perf_hpp_fmt *fmt; 158281a888feSJiri Olsa size_t ret = 0; 1583c6c3c02dSArnaldo Carvalho de Melo int column = 0; 158429659ab4SJiri Olsa int span = 0; 158581a888feSJiri Olsa 158681a888feSJiri Olsa if (symbol_conf.use_callchain) { 158781a888feSJiri Olsa ret = scnprintf(buf, size, " "); 158881a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 158981a888feSJiri Olsa return ret; 159081a888feSJiri Olsa } 159181a888feSJiri Olsa 1592f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 1593361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) 159481a888feSJiri Olsa continue; 159581a888feSJiri Olsa 159629659ab4SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists, line, &span); 159781a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 159881a888feSJiri Olsa break; 159981a888feSJiri Olsa 160029659ab4SJiri Olsa if (span) 160129659ab4SJiri Olsa continue; 160229659ab4SJiri Olsa 160381a888feSJiri Olsa ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 160481a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 160581a888feSJiri Olsa break; 160681a888feSJiri Olsa } 160781a888feSJiri Olsa 160881a888feSJiri Olsa return ret; 160981a888feSJiri Olsa } 161081a888feSJiri Olsa 1611d8b92400SNamhyung Kim static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size) 1612d8b92400SNamhyung Kim { 1613d8b92400SNamhyung Kim struct hists *hists = browser->hists; 1614d8b92400SNamhyung Kim struct perf_hpp dummy_hpp = { 1615d8b92400SNamhyung Kim .buf = buf, 1616d8b92400SNamhyung Kim .size = size, 1617d8b92400SNamhyung Kim }; 1618d8b92400SNamhyung Kim struct perf_hpp_fmt *fmt; 1619a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1620d8b92400SNamhyung Kim size_t ret = 0; 1621d8b92400SNamhyung Kim int column = 0; 16222dbbe9f2SNamhyung Kim int indent = hists->nr_hpp_node - 2; 1623a61a22f6SNamhyung Kim bool first_node, first_col; 1624d8b92400SNamhyung Kim 1625d8b92400SNamhyung Kim ret = scnprintf(buf, size, " "); 1626d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1627d8b92400SNamhyung Kim return ret; 1628d8b92400SNamhyung Kim 1629b9bf911eSNamhyung Kim first_node = true; 1630a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1631a61a22f6SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 1632a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1633a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1634d8b92400SNamhyung Kim if (column++ < browser->b.horiz_scroll) 1635d8b92400SNamhyung Kim continue; 1636d8b92400SNamhyung Kim 163729659ab4SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL); 1638d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1639d8b92400SNamhyung Kim break; 1640d8b92400SNamhyung Kim 1641d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 1642d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1643d8b92400SNamhyung Kim break; 1644b9bf911eSNamhyung Kim 1645b9bf911eSNamhyung Kim first_node = false; 1646d8b92400SNamhyung Kim } 1647d8b92400SNamhyung Kim 1648b9bf911eSNamhyung Kim if (!first_node) { 1649d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s", 16502dbbe9f2SNamhyung Kim indent * HIERARCHY_INDENT, ""); 1651d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1652d8b92400SNamhyung Kim return ret; 1653b9bf911eSNamhyung Kim } 1654d8b92400SNamhyung Kim 1655a61a22f6SNamhyung Kim first_node = true; 1656a61a22f6SNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) { 1657a61a22f6SNamhyung Kim if (!first_node) { 1658d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / "); 1659d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1660d8b92400SNamhyung Kim break; 1661d8b92400SNamhyung Kim } 1662a61a22f6SNamhyung Kim first_node = false; 1663a61a22f6SNamhyung Kim 1664a61a22f6SNamhyung Kim first_col = true; 1665a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1666a61a22f6SNamhyung Kim char *start; 1667a61a22f6SNamhyung Kim 1668a61a22f6SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 1669a61a22f6SNamhyung Kim continue; 1670a61a22f6SNamhyung Kim 1671a61a22f6SNamhyung Kim if (!first_col) { 1672a61a22f6SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+"); 1673a61a22f6SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1674a61a22f6SNamhyung Kim break; 1675a61a22f6SNamhyung Kim } 1676a61a22f6SNamhyung Kim first_col = false; 1677d8b92400SNamhyung Kim 167829659ab4SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL); 1679d8b92400SNamhyung Kim dummy_hpp.buf[ret] = '\0'; 1680d8b92400SNamhyung Kim 16817d6a7e78SJiri Olsa start = trim(dummy_hpp.buf); 1682cb1fab91SNamhyung Kim ret = strlen(start); 1683cb1fab91SNamhyung Kim 1684cb1fab91SNamhyung Kim if (start != dummy_hpp.buf) 1685cb1fab91SNamhyung Kim memmove(dummy_hpp.buf, start, ret + 1); 1686cb1fab91SNamhyung Kim 1687d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1688d8b92400SNamhyung Kim break; 1689d8b92400SNamhyung Kim } 1690a61a22f6SNamhyung Kim } 1691d8b92400SNamhyung Kim 1692d8b92400SNamhyung Kim return ret; 1693d8b92400SNamhyung Kim } 1694d8b92400SNamhyung Kim 169501b4770dSJiri Olsa static void hists_browser__hierarchy_headers(struct hist_browser *browser) 1696025bf7eaSArnaldo Carvalho de Melo { 169781a888feSJiri Olsa char headers[1024]; 169881a888feSJiri Olsa 1699d8b92400SNamhyung Kim hists_browser__scnprintf_hierarchy_headers(browser, headers, 1700d8b92400SNamhyung Kim sizeof(headers)); 170101b4770dSJiri Olsa 1702025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, 0, 0); 1703025bf7eaSArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 170426270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 1705025bf7eaSArnaldo Carvalho de Melo } 1706025bf7eaSArnaldo Carvalho de Melo 170701b4770dSJiri Olsa static void hists_browser__headers(struct hist_browser *browser) 170801b4770dSJiri Olsa { 170969705b35SJiri Olsa struct hists *hists = browser->hists; 171069705b35SJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 171169705b35SJiri Olsa 171269705b35SJiri Olsa int line; 171369705b35SJiri Olsa 171469705b35SJiri Olsa for (line = 0; line < hpp_list->nr_header_lines; line++) { 171501b4770dSJiri Olsa char headers[1024]; 171601b4770dSJiri Olsa 171701b4770dSJiri Olsa hists_browser__scnprintf_headers(browser, headers, 171869705b35SJiri Olsa sizeof(headers), line); 171901b4770dSJiri Olsa 1720ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc_title(&browser->b, line, 0); 172101b4770dSJiri Olsa ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 172201b4770dSJiri Olsa ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 172301b4770dSJiri Olsa } 172469705b35SJiri Olsa } 172501b4770dSJiri Olsa 172601b4770dSJiri Olsa static void hist_browser__show_headers(struct hist_browser *browser) 172701b4770dSJiri Olsa { 172801b4770dSJiri Olsa if (symbol_conf.report_hierarchy) 172901b4770dSJiri Olsa hists_browser__hierarchy_headers(browser); 173001b4770dSJiri Olsa else 173101b4770dSJiri Olsa hists_browser__headers(browser); 173201b4770dSJiri Olsa } 173301b4770dSJiri Olsa 1734aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 1735aca7a94dSNamhyung Kim { 1736aca7a94dSNamhyung Kim if (browser->top == NULL) { 1737aca7a94dSNamhyung Kim struct hist_browser *hb; 1738aca7a94dSNamhyung Kim 1739aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1740aca7a94dSNamhyung Kim browser->top = rb_first(&hb->hists->entries); 1741aca7a94dSNamhyung Kim } 1742aca7a94dSNamhyung Kim } 1743aca7a94dSNamhyung Kim 174405e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 1745aca7a94dSNamhyung Kim { 1746aca7a94dSNamhyung Kim unsigned row = 0; 1747aca7a94dSNamhyung Kim struct rb_node *nd; 174805e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 1749aca7a94dSNamhyung Kim 175094e87a8bSArnaldo Carvalho de Melo if (hb->show_headers) 1751025bf7eaSArnaldo Carvalho de Melo hist_browser__show_headers(hb); 1752025bf7eaSArnaldo Carvalho de Melo 175305e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1754979d2cacSWang Nan hb->he_selection = NULL; 1755979d2cacSWang Nan hb->selection = NULL; 1756aca7a94dSNamhyung Kim 1757d0506edbSNamhyung Kim for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) { 1758aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 175914135663SNamhyung Kim float percent; 1760aca7a94dSNamhyung Kim 1761d0506edbSNamhyung Kim if (h->filtered) { 1762d0506edbSNamhyung Kim /* let it move to sibling */ 1763d0506edbSNamhyung Kim h->unfolded = false; 1764aca7a94dSNamhyung Kim continue; 1765d0506edbSNamhyung Kim } 1766aca7a94dSNamhyung Kim 176714135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 1768064f1981SNamhyung Kim if (percent < hb->min_pcnt) 1769064f1981SNamhyung Kim continue; 1770064f1981SNamhyung Kim 1771d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 1772d0506edbSNamhyung Kim row += hist_browser__show_hierarchy_entry(hb, h, row, 17732dbbe9f2SNamhyung Kim h->depth); 177479dded87SNamhyung Kim if (row == browser->rows) 177579dded87SNamhyung Kim break; 177679dded87SNamhyung Kim 177779dded87SNamhyung Kim if (h->has_no_entry) { 1778a61a22f6SNamhyung Kim hist_browser__show_no_entry(hb, row, h->depth + 1); 177979dded87SNamhyung Kim row++; 178079dded87SNamhyung Kim } 1781d0506edbSNamhyung Kim } else { 1782aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 1783d0506edbSNamhyung Kim } 1784d0506edbSNamhyung Kim 178562c95ae3SArnaldo Carvalho de Melo if (row == browser->rows) 1786aca7a94dSNamhyung Kim break; 1787aca7a94dSNamhyung Kim } 1788aca7a94dSNamhyung Kim 178994e87a8bSArnaldo Carvalho de Melo return row; 1790aca7a94dSNamhyung Kim } 1791aca7a94dSNamhyung Kim 1792064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 1793064f1981SNamhyung Kim float min_pcnt) 1794aca7a94dSNamhyung Kim { 1795aca7a94dSNamhyung Kim while (nd != NULL) { 1796aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 179714135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1798064f1981SNamhyung Kim 1799c0f1527bSNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1800aca7a94dSNamhyung Kim return nd; 1801aca7a94dSNamhyung Kim 1802d0506edbSNamhyung Kim /* 1803d0506edbSNamhyung Kim * If it's filtered, its all children also were filtered. 1804d0506edbSNamhyung Kim * So move to sibling node. 1805d0506edbSNamhyung Kim */ 1806d0506edbSNamhyung Kim if (rb_next(nd)) 1807aca7a94dSNamhyung Kim nd = rb_next(nd); 1808d0506edbSNamhyung Kim else 1809d0506edbSNamhyung Kim nd = rb_hierarchy_next(nd); 1810aca7a94dSNamhyung Kim } 1811aca7a94dSNamhyung Kim 1812aca7a94dSNamhyung Kim return NULL; 1813aca7a94dSNamhyung Kim } 1814aca7a94dSNamhyung Kim 1815064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 1816064f1981SNamhyung Kim float min_pcnt) 1817aca7a94dSNamhyung Kim { 1818aca7a94dSNamhyung Kim while (nd != NULL) { 1819aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 182014135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1821064f1981SNamhyung Kim 1822064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1823aca7a94dSNamhyung Kim return nd; 1824aca7a94dSNamhyung Kim 1825d0506edbSNamhyung Kim nd = rb_hierarchy_prev(nd); 1826aca7a94dSNamhyung Kim } 1827aca7a94dSNamhyung Kim 1828aca7a94dSNamhyung Kim return NULL; 1829aca7a94dSNamhyung Kim } 1830aca7a94dSNamhyung Kim 183105e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 1832aca7a94dSNamhyung Kim off_t offset, int whence) 1833aca7a94dSNamhyung Kim { 1834aca7a94dSNamhyung Kim struct hist_entry *h; 1835aca7a94dSNamhyung Kim struct rb_node *nd; 1836aca7a94dSNamhyung Kim bool first = true; 1837064f1981SNamhyung Kim struct hist_browser *hb; 1838064f1981SNamhyung Kim 1839064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1840aca7a94dSNamhyung Kim 184105e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 1842aca7a94dSNamhyung Kim return; 1843aca7a94dSNamhyung Kim 184405e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1845aca7a94dSNamhyung Kim 1846aca7a94dSNamhyung Kim switch (whence) { 1847aca7a94dSNamhyung Kim case SEEK_SET: 1848064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 184914135663SNamhyung Kim hb->min_pcnt); 1850aca7a94dSNamhyung Kim break; 1851aca7a94dSNamhyung Kim case SEEK_CUR: 185205e8b080SArnaldo Carvalho de Melo nd = browser->top; 1853aca7a94dSNamhyung Kim goto do_offset; 1854aca7a94dSNamhyung Kim case SEEK_END: 1855d0506edbSNamhyung Kim nd = rb_hierarchy_last(rb_last(browser->entries)); 1856d0506edbSNamhyung Kim nd = hists__filter_prev_entries(nd, hb->min_pcnt); 1857aca7a94dSNamhyung Kim first = false; 1858aca7a94dSNamhyung Kim break; 1859aca7a94dSNamhyung Kim default: 1860aca7a94dSNamhyung Kim return; 1861aca7a94dSNamhyung Kim } 1862aca7a94dSNamhyung Kim 1863aca7a94dSNamhyung Kim /* 1864aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 1865aca7a94dSNamhyung Kim * row_offset: 1866aca7a94dSNamhyung Kim */ 186705e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 1868aca7a94dSNamhyung Kim h->row_offset = 0; 1869aca7a94dSNamhyung Kim 1870aca7a94dSNamhyung Kim /* 1871aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 1872aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 1873aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 1874aca7a94dSNamhyung Kim * 1875aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 1876aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 1877aca7a94dSNamhyung Kim * 1878aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 1879aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 1880aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 1881aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 1882aca7a94dSNamhyung Kim */ 1883aca7a94dSNamhyung Kim do_offset: 1884837eeb75SWang Nan if (!nd) 1885837eeb75SWang Nan return; 1886837eeb75SWang Nan 1887aca7a94dSNamhyung Kim if (offset > 0) { 1888aca7a94dSNamhyung Kim do { 1889aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1890d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1891aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 1892aca7a94dSNamhyung Kim if (offset > remaining) { 1893aca7a94dSNamhyung Kim offset -= remaining; 1894aca7a94dSNamhyung Kim h->row_offset = 0; 1895aca7a94dSNamhyung Kim } else { 1896aca7a94dSNamhyung Kim h->row_offset += offset; 1897aca7a94dSNamhyung Kim offset = 0; 189805e8b080SArnaldo Carvalho de Melo browser->top = nd; 1899aca7a94dSNamhyung Kim break; 1900aca7a94dSNamhyung Kim } 1901aca7a94dSNamhyung Kim } 1902d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 1903d0506edbSNamhyung Kim hb->min_pcnt); 1904aca7a94dSNamhyung Kim if (nd == NULL) 1905aca7a94dSNamhyung Kim break; 1906aca7a94dSNamhyung Kim --offset; 190705e8b080SArnaldo Carvalho de Melo browser->top = nd; 1908aca7a94dSNamhyung Kim } while (offset != 0); 1909aca7a94dSNamhyung Kim } else if (offset < 0) { 1910aca7a94dSNamhyung Kim while (1) { 1911aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1912d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1913aca7a94dSNamhyung Kim if (first) { 1914aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 1915aca7a94dSNamhyung Kim offset += h->row_offset; 1916aca7a94dSNamhyung Kim h->row_offset = 0; 1917aca7a94dSNamhyung Kim } else { 1918aca7a94dSNamhyung Kim h->row_offset += offset; 1919aca7a94dSNamhyung Kim offset = 0; 192005e8b080SArnaldo Carvalho de Melo browser->top = nd; 1921aca7a94dSNamhyung Kim break; 1922aca7a94dSNamhyung Kim } 1923aca7a94dSNamhyung Kim } else { 1924aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 1925aca7a94dSNamhyung Kim offset += h->nr_rows; 1926aca7a94dSNamhyung Kim h->row_offset = 0; 1927aca7a94dSNamhyung Kim } else { 1928aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 1929aca7a94dSNamhyung Kim offset = 0; 193005e8b080SArnaldo Carvalho de Melo browser->top = nd; 1931aca7a94dSNamhyung Kim break; 1932aca7a94dSNamhyung Kim } 1933aca7a94dSNamhyung Kim } 1934aca7a94dSNamhyung Kim } 1935aca7a94dSNamhyung Kim 1936d0506edbSNamhyung Kim nd = hists__filter_prev_entries(rb_hierarchy_prev(nd), 1937064f1981SNamhyung Kim hb->min_pcnt); 1938aca7a94dSNamhyung Kim if (nd == NULL) 1939aca7a94dSNamhyung Kim break; 1940aca7a94dSNamhyung Kim ++offset; 194105e8b080SArnaldo Carvalho de Melo browser->top = nd; 1942aca7a94dSNamhyung Kim if (offset == 0) { 1943aca7a94dSNamhyung Kim /* 1944aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 1945aca7a94dSNamhyung Kim * unfolded, if it is then we should have 1946aca7a94dSNamhyung Kim * row_offset at its last entry. 1947aca7a94dSNamhyung Kim */ 1948aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1949d0506edbSNamhyung Kim if (h->unfolded && h->leaf) 1950aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 1951aca7a94dSNamhyung Kim break; 1952aca7a94dSNamhyung Kim } 1953aca7a94dSNamhyung Kim first = false; 1954aca7a94dSNamhyung Kim } 1955aca7a94dSNamhyung Kim } else { 195605e8b080SArnaldo Carvalho de Melo browser->top = nd; 1957aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1958aca7a94dSNamhyung Kim h->row_offset = 0; 1959aca7a94dSNamhyung Kim } 1960aca7a94dSNamhyung Kim } 1961aca7a94dSNamhyung Kim 1962aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1963d0506edbSNamhyung Kim struct hist_entry *he, FILE *fp, 1964d0506edbSNamhyung Kim int level) 1965aff3f3f6SArnaldo Carvalho de Melo { 196639ee533fSNamhyung Kim struct callchain_print_arg arg = { 196739ee533fSNamhyung Kim .fp = fp, 196839ee533fSNamhyung Kim }; 1969aff3f3f6SArnaldo Carvalho de Melo 1970d0506edbSNamhyung Kim hist_browser__show_callchain(browser, he, level, 0, 197139ee533fSNamhyung Kim hist_browser__fprintf_callchain_entry, &arg, 197239ee533fSNamhyung Kim hist_browser__check_dump_full); 197339ee533fSNamhyung Kim return arg.printed; 1974aff3f3f6SArnaldo Carvalho de Melo } 1975aff3f3f6SArnaldo Carvalho de Melo 1976aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 1977aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 1978aff3f3f6SArnaldo Carvalho de Melo { 1979aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 1980aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1981aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 198226d8b338SNamhyung Kim struct perf_hpp hpp = { 198326d8b338SNamhyung Kim .buf = s, 198426d8b338SNamhyung Kim .size = sizeof(s), 198526d8b338SNamhyung Kim }; 198626d8b338SNamhyung Kim struct perf_hpp_fmt *fmt; 198726d8b338SNamhyung Kim bool first = true; 198826d8b338SNamhyung Kim int ret; 1989aff3f3f6SArnaldo Carvalho de Melo 19901b6b678eSArnaldo Carvalho de Melo if (symbol_conf.use_callchain) { 1991aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 1992aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 19931b6b678eSArnaldo Carvalho de Melo } 1994aff3f3f6SArnaldo Carvalho de Melo 1995f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 1996361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, he->hists)) 1997e67d49a7SNamhyung Kim continue; 1998e67d49a7SNamhyung Kim 199926d8b338SNamhyung Kim if (!first) { 200026d8b338SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 200126d8b338SNamhyung Kim advance_hpp(&hpp, ret); 200226d8b338SNamhyung Kim } else 200326d8b338SNamhyung Kim first = false; 2004aff3f3f6SArnaldo Carvalho de Melo 200526d8b338SNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 200689fee709SArnaldo Carvalho de Melo ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret); 200726d8b338SNamhyung Kim advance_hpp(&hpp, ret); 200826d8b338SNamhyung Kim } 200989fee709SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", s); 2010aff3f3f6SArnaldo Carvalho de Melo 2011aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 2012d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 1); 2013d0506edbSNamhyung Kim 2014d0506edbSNamhyung Kim return printed; 2015d0506edbSNamhyung Kim } 2016d0506edbSNamhyung Kim 2017d0506edbSNamhyung Kim 2018d0506edbSNamhyung Kim static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser, 2019d0506edbSNamhyung Kim struct hist_entry *he, 2020325a6283SNamhyung Kim FILE *fp, int level) 2021d0506edbSNamhyung Kim { 2022d0506edbSNamhyung Kim char s[8192]; 2023d0506edbSNamhyung Kim int printed = 0; 2024d0506edbSNamhyung Kim char folded_sign = ' '; 2025d0506edbSNamhyung Kim struct perf_hpp hpp = { 2026d0506edbSNamhyung Kim .buf = s, 2027d0506edbSNamhyung Kim .size = sizeof(s), 2028d0506edbSNamhyung Kim }; 2029d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 2030325a6283SNamhyung Kim struct perf_hpp_list_node *fmt_node; 2031d0506edbSNamhyung Kim bool first = true; 2032d0506edbSNamhyung Kim int ret; 2033325a6283SNamhyung Kim int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 2034d0506edbSNamhyung Kim 2035d0506edbSNamhyung Kim printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, ""); 2036d0506edbSNamhyung Kim 2037d0506edbSNamhyung Kim folded_sign = hist_entry__folded(he); 2038d0506edbSNamhyung Kim printed += fprintf(fp, "%c", folded_sign); 2039d0506edbSNamhyung Kim 2040325a6283SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 2041325a6283SNamhyung Kim fmt_node = list_first_entry(&he->hists->hpp_formats, 2042325a6283SNamhyung Kim struct perf_hpp_list_node, list); 2043325a6283SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 2044d0506edbSNamhyung Kim if (!first) { 2045d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 2046d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 2047d0506edbSNamhyung Kim } else 2048d0506edbSNamhyung Kim first = false; 2049d0506edbSNamhyung Kim 2050d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 2051d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 2052d0506edbSNamhyung Kim } 2053d0506edbSNamhyung Kim 2054d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, ""); 2055d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 2056d0506edbSNamhyung Kim 20571b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(he->hpp_list, fmt) { 20581b2dbbf4SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 20591b2dbbf4SNamhyung Kim advance_hpp(&hpp, ret); 20601b2dbbf4SNamhyung Kim 2061d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 2062d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 20631b2dbbf4SNamhyung Kim } 2064d0506edbSNamhyung Kim 2065d0506edbSNamhyung Kim printed += fprintf(fp, "%s\n", rtrim(s)); 2066d0506edbSNamhyung Kim 2067d0506edbSNamhyung Kim if (he->leaf && folded_sign == '-') { 2068d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 2069d0506edbSNamhyung Kim he->depth + 1); 2070d0506edbSNamhyung Kim } 2071aff3f3f6SArnaldo Carvalho de Melo 2072aff3f3f6SArnaldo Carvalho de Melo return printed; 2073aff3f3f6SArnaldo Carvalho de Melo } 2074aff3f3f6SArnaldo Carvalho de Melo 2075aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 2076aff3f3f6SArnaldo Carvalho de Melo { 2077064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 2078064f1981SNamhyung Kim browser->min_pcnt); 2079aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 2080aff3f3f6SArnaldo Carvalho de Melo 2081aff3f3f6SArnaldo Carvalho de Melo while (nd) { 2082aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 2083aff3f3f6SArnaldo Carvalho de Melo 2084d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 2085d0506edbSNamhyung Kim printed += hist_browser__fprintf_hierarchy_entry(browser, 2086d0506edbSNamhyung Kim h, fp, 2087325a6283SNamhyung Kim h->depth); 2088d0506edbSNamhyung Kim } else { 2089aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 2090d0506edbSNamhyung Kim } 2091d0506edbSNamhyung Kim 2092d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 2093d0506edbSNamhyung Kim browser->min_pcnt); 2094aff3f3f6SArnaldo Carvalho de Melo } 2095aff3f3f6SArnaldo Carvalho de Melo 2096aff3f3f6SArnaldo Carvalho de Melo return printed; 2097aff3f3f6SArnaldo Carvalho de Melo } 2098aff3f3f6SArnaldo Carvalho de Melo 2099aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 2100aff3f3f6SArnaldo Carvalho de Melo { 2101aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 2102aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 2103aff3f3f6SArnaldo Carvalho de Melo 2104aff3f3f6SArnaldo Carvalho de Melo while (1) { 2105aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 2106aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 2107aff3f3f6SArnaldo Carvalho de Melo break; 2108aff3f3f6SArnaldo Carvalho de Melo /* 2109aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 2110aff3f3f6SArnaldo Carvalho de Melo */ 2111aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 2112aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 2113aff3f3f6SArnaldo Carvalho de Melo return -1; 2114aff3f3f6SArnaldo Carvalho de Melo } 2115aff3f3f6SArnaldo Carvalho de Melo } 2116aff3f3f6SArnaldo Carvalho de Melo 2117aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 2118aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 2119aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 2120c8b5f2c9SArnaldo Carvalho de Melo const char *err = str_error_r(errno, bf, sizeof(bf)); 21214cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 2122aff3f3f6SArnaldo Carvalho de Melo return -1; 2123aff3f3f6SArnaldo Carvalho de Melo } 2124aff3f3f6SArnaldo Carvalho de Melo 2125aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 2126aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 2127aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 2128aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 2129aff3f3f6SArnaldo Carvalho de Melo 2130aff3f3f6SArnaldo Carvalho de Melo return 0; 2131aff3f3f6SArnaldo Carvalho de Melo } 2132aff3f3f6SArnaldo Carvalho de Melo 2133fcd86426SJiri Olsa void hist_browser__init(struct hist_browser *browser, 2134fcd86426SJiri Olsa struct hists *hists) 2135aca7a94dSNamhyung Kim { 2136b1c7a8f7SJiri Olsa struct perf_hpp_fmt *fmt; 2137b1c7a8f7SJiri Olsa 213805e8b080SArnaldo Carvalho de Melo browser->hists = hists; 213905e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 2140357cfff1SArnaldo Carvalho de Melo browser->b.refresh_dimensions = hist_browser__refresh_dimensions; 214105e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 214205e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 2143c8302367SJiri Olsa browser->show_headers = symbol_conf.show_hist_headers; 2144ef9ff601SArnaldo Carvalho de Melo hist_browser__set_title_space(browser); 2145b1c7a8f7SJiri Olsa 21468a06b0beSNamhyung Kim if (symbol_conf.report_hierarchy) { 21478a06b0beSNamhyung Kim struct perf_hpp_list_node *fmt_node; 21488a06b0beSNamhyung Kim 21498a06b0beSNamhyung Kim /* count overhead columns (in the first node) */ 21508a06b0beSNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 21518a06b0beSNamhyung Kim struct perf_hpp_list_node, list); 21528a06b0beSNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) 21538a06b0beSNamhyung Kim ++browser->b.columns; 21548a06b0beSNamhyung Kim 21558a06b0beSNamhyung Kim /* add a single column for whole hierarchy sort keys*/ 21568a06b0beSNamhyung Kim ++browser->b.columns; 21578a06b0beSNamhyung Kim } else { 2158e3b60bc9SNamhyung Kim hists__for_each_format(hists, fmt) 2159b1c7a8f7SJiri Olsa ++browser->b.columns; 21608a06b0beSNamhyung Kim } 2161e3b60bc9SNamhyung Kim 2162e3b60bc9SNamhyung Kim hists__reset_column_width(hists); 2163aca7a94dSNamhyung Kim } 2164aca7a94dSNamhyung Kim 2165fcd86426SJiri Olsa struct hist_browser *hist_browser__new(struct hists *hists) 2166fcd86426SJiri Olsa { 2167fcd86426SJiri Olsa struct hist_browser *browser = zalloc(sizeof(*browser)); 2168fcd86426SJiri Olsa 2169fcd86426SJiri Olsa if (browser) 2170fcd86426SJiri Olsa hist_browser__init(browser, hists); 2171fcd86426SJiri Olsa 217205e8b080SArnaldo Carvalho de Melo return browser; 2173aca7a94dSNamhyung Kim } 2174aca7a94dSNamhyung Kim 2175a6ec894dSJiri Olsa static struct hist_browser * 2176a6ec894dSJiri Olsa perf_evsel_browser__new(struct perf_evsel *evsel, 2177a6ec894dSJiri Olsa struct hist_browser_timer *hbt, 2178cd0cccbaSArnaldo Carvalho de Melo struct perf_env *env, 2179cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *annotation_opts) 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; 2186f016d24aSArnaldo Carvalho de Melo browser->title = hists_browser__scnprintf_title; 2187cd0cccbaSArnaldo Carvalho de Melo browser->annotation_opts = annotation_opts; 2188a6ec894dSJiri Olsa } 2189a6ec894dSJiri Olsa return browser; 2190a6ec894dSJiri Olsa } 2191a6ec894dSJiri Olsa 2192dabd2012SJiri Olsa void hist_browser__delete(struct hist_browser *browser) 2193aca7a94dSNamhyung Kim { 219405e8b080SArnaldo Carvalho de Melo free(browser); 2195aca7a94dSNamhyung Kim } 2196aca7a94dSNamhyung Kim 219705e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 2198aca7a94dSNamhyung Kim { 219905e8b080SArnaldo Carvalho de Melo return browser->he_selection; 2200aca7a94dSNamhyung Kim } 2201aca7a94dSNamhyung Kim 220205e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 2203aca7a94dSNamhyung Kim { 220405e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 2205aca7a94dSNamhyung Kim } 2206aca7a94dSNamhyung Kim 22071e378ebdSTaeung Song /* Check whether the browser is for 'top' or 'report' */ 22081e378ebdSTaeung Song static inline bool is_report_browser(void *timer) 22091e378ebdSTaeung Song { 22101e378ebdSTaeung Song return timer == NULL; 22111e378ebdSTaeung Song } 22121e378ebdSTaeung Song 2213967a464aSArnaldo Carvalho de Melo static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size) 2214967a464aSArnaldo Carvalho de Melo { 2215967a464aSArnaldo Carvalho de Melo struct hist_browser_timer *hbt = browser->hbt; 2216967a464aSArnaldo Carvalho de Melo int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt)); 2217967a464aSArnaldo Carvalho de Melo 22181e378ebdSTaeung Song if (!is_report_browser(hbt)) { 22191e378ebdSTaeung Song struct perf_top *top = hbt->arg; 22201e378ebdSTaeung Song 22211e378ebdSTaeung Song if (top->zero) 22221e378ebdSTaeung Song printed += scnprintf(bf + printed, size - printed, " [z]"); 22231e378ebdSTaeung Song } 22241e378ebdSTaeung Song 2225aca7a94dSNamhyung Kim return printed; 2226aca7a94dSNamhyung Kim } 2227aca7a94dSNamhyung Kim 2228aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 2229aca7a94dSNamhyung Kim { 2230aca7a94dSNamhyung Kim int i; 2231aca7a94dSNamhyung Kim 223204662523SArnaldo Carvalho de Melo for (i = 0; i < n; ++i) 223304662523SArnaldo Carvalho de Melo zfree(&options[i]); 2234aca7a94dSNamhyung Kim } 2235aca7a94dSNamhyung Kim 2236341487abSFeng Tang /* 2237341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 2238341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 2239341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 2240341487abSFeng Tang */ 2241341487abSFeng Tang static bool is_input_name_malloced = false; 2242341487abSFeng Tang 2243341487abSFeng Tang static int switch_data_file(void) 2244341487abSFeng Tang { 2245341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 2246341487abSFeng Tang DIR *pwd_dir; 2247341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 2248341487abSFeng Tang struct dirent *dent; 2249341487abSFeng Tang 2250341487abSFeng Tang pwd = getenv("PWD"); 2251341487abSFeng Tang if (!pwd) 2252341487abSFeng Tang return ret; 2253341487abSFeng Tang 2254341487abSFeng Tang pwd_dir = opendir(pwd); 2255341487abSFeng Tang if (!pwd_dir) 2256341487abSFeng Tang return ret; 2257341487abSFeng Tang 2258341487abSFeng Tang memset(options, 0, sizeof(options)); 22593ef5b402SChangbin Du memset(abs_path, 0, sizeof(abs_path)); 2260341487abSFeng Tang 2261341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 2262341487abSFeng Tang char path[PATH_MAX]; 2263341487abSFeng Tang u64 magic; 2264341487abSFeng Tang char *name = dent->d_name; 2265341487abSFeng Tang FILE *file; 2266341487abSFeng Tang 2267341487abSFeng Tang if (!(dent->d_type == DT_REG)) 2268341487abSFeng Tang continue; 2269341487abSFeng Tang 2270341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 2271341487abSFeng Tang 2272341487abSFeng Tang file = fopen(path, "r"); 2273341487abSFeng Tang if (!file) 2274341487abSFeng Tang continue; 2275341487abSFeng Tang 2276341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 2277341487abSFeng Tang goto close_file_and_continue; 2278341487abSFeng Tang 2279341487abSFeng Tang if (is_perf_magic(magic)) { 2280341487abSFeng Tang options[nr_options] = strdup(name); 2281341487abSFeng Tang if (!options[nr_options]) 2282341487abSFeng Tang goto close_file_and_continue; 2283341487abSFeng Tang 2284341487abSFeng Tang abs_path[nr_options] = strdup(path); 2285341487abSFeng Tang if (!abs_path[nr_options]) { 228674cf249dSArnaldo Carvalho de Melo zfree(&options[nr_options]); 2287341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 2288341487abSFeng Tang fclose(file); 2289341487abSFeng Tang break; 2290341487abSFeng Tang } 2291341487abSFeng Tang 2292341487abSFeng Tang nr_options++; 2293341487abSFeng Tang } 2294341487abSFeng Tang 2295341487abSFeng Tang close_file_and_continue: 2296341487abSFeng Tang fclose(file); 2297341487abSFeng Tang if (nr_options >= 32) { 2298341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 2299341487abSFeng Tang "Only the first 32 files will be listed.\n"); 2300341487abSFeng Tang break; 2301341487abSFeng Tang } 2302341487abSFeng Tang } 2303341487abSFeng Tang closedir(pwd_dir); 2304341487abSFeng Tang 2305341487abSFeng Tang if (nr_options) { 2306341487abSFeng Tang choice = ui__popup_menu(nr_options, options); 2307341487abSFeng Tang if (choice < nr_options && choice >= 0) { 2308341487abSFeng Tang tmp = strdup(abs_path[choice]); 2309341487abSFeng Tang if (tmp) { 2310341487abSFeng Tang if (is_input_name_malloced) 2311341487abSFeng Tang free((void *)input_name); 2312341487abSFeng Tang input_name = tmp; 2313341487abSFeng Tang is_input_name_malloced = true; 2314341487abSFeng Tang ret = 0; 2315341487abSFeng Tang } else 2316341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 2317341487abSFeng Tang } 2318341487abSFeng Tang } 2319341487abSFeng Tang 2320341487abSFeng Tang free_popup_options(options, nr_options); 2321341487abSFeng Tang free_popup_options(abs_path, nr_options); 2322341487abSFeng Tang return ret; 2323341487abSFeng Tang } 2324341487abSFeng Tang 2325ea7cd592SNamhyung Kim struct popup_action { 2326ea7cd592SNamhyung Kim struct thread *thread; 2327ea7cd592SNamhyung Kim struct map_symbol ms; 232884734b06SKan Liang int socket; 2329ea7cd592SNamhyung Kim 2330ea7cd592SNamhyung Kim int (*fn)(struct hist_browser *browser, struct popup_action *act); 2331ea7cd592SNamhyung Kim }; 2332ea7cd592SNamhyung Kim 2333bc7cad42SNamhyung Kim static int 2334ea7cd592SNamhyung Kim do_annotate(struct hist_browser *browser, struct popup_action *act) 2335bc7cad42SNamhyung Kim { 2336bc7cad42SNamhyung Kim struct perf_evsel *evsel; 2337bc7cad42SNamhyung Kim struct annotation *notes; 2338bc7cad42SNamhyung Kim struct hist_entry *he; 2339bc7cad42SNamhyung Kim int err; 2340bc7cad42SNamhyung Kim 2341*f178fd2dSArnaldo Carvalho de Melo if (!browser->annotation_opts->objdump_path && 2342*f178fd2dSArnaldo Carvalho de Melo perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path)) 2343bc7cad42SNamhyung Kim return 0; 2344bc7cad42SNamhyung Kim 2345ea7cd592SNamhyung Kim notes = symbol__annotation(act->ms.sym); 2346bc7cad42SNamhyung Kim if (!notes->src) 2347bc7cad42SNamhyung Kim return 0; 2348bc7cad42SNamhyung Kim 2349bc7cad42SNamhyung Kim evsel = hists_to_evsel(browser->hists); 2350cd0cccbaSArnaldo Carvalho de Melo err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt, 2351cd0cccbaSArnaldo Carvalho de Melo browser->annotation_opts); 2352bc7cad42SNamhyung Kim he = hist_browser__selected_entry(browser); 2353bc7cad42SNamhyung Kim /* 2354bc7cad42SNamhyung Kim * offer option to annotate the other branch source or target 2355bc7cad42SNamhyung Kim * (if they exists) when returning from annotate 2356bc7cad42SNamhyung Kim */ 2357bc7cad42SNamhyung Kim if ((err == 'q' || err == CTRL('c')) && he->branch_info) 2358bc7cad42SNamhyung Kim return 1; 2359bc7cad42SNamhyung Kim 2360bc7cad42SNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 2361bc7cad42SNamhyung Kim if (err) 2362bc7cad42SNamhyung Kim ui_browser__handle_resize(&browser->b); 2363bc7cad42SNamhyung Kim return 0; 2364bc7cad42SNamhyung Kim } 2365bc7cad42SNamhyung Kim 2366bc7cad42SNamhyung Kim static int 2367ea7cd592SNamhyung Kim add_annotate_opt(struct hist_browser *browser __maybe_unused, 2368ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 2369ea7cd592SNamhyung Kim struct map *map, struct symbol *sym) 2370bc7cad42SNamhyung Kim { 2371ea7cd592SNamhyung Kim if (sym == NULL || map->dso->annotate_warned) 2372ea7cd592SNamhyung Kim return 0; 2373ea7cd592SNamhyung Kim 2374ea7cd592SNamhyung Kim if (asprintf(optstr, "Annotate %s", sym->name) < 0) 2375ea7cd592SNamhyung Kim return 0; 2376ea7cd592SNamhyung Kim 2377ea7cd592SNamhyung Kim act->ms.map = map; 2378ea7cd592SNamhyung Kim act->ms.sym = sym; 2379ea7cd592SNamhyung Kim act->fn = do_annotate; 2380ea7cd592SNamhyung Kim return 1; 2381ea7cd592SNamhyung Kim } 2382ea7cd592SNamhyung Kim 2383ea7cd592SNamhyung Kim static int 2384ea7cd592SNamhyung Kim do_zoom_thread(struct hist_browser *browser, struct popup_action *act) 2385ea7cd592SNamhyung Kim { 2386ea7cd592SNamhyung Kim struct thread *thread = act->thread; 2387ea7cd592SNamhyung Kim 23887cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 23897cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2390599a2f38SNamhyung Kim return 0; 2391599a2f38SNamhyung Kim 2392bc7cad42SNamhyung Kim if (browser->hists->thread_filter) { 2393bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->thread_filter); 2394bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2395bc7cad42SNamhyung Kim thread__zput(browser->hists->thread_filter); 2396bc7cad42SNamhyung Kim ui_helpline__pop(); 2397bc7cad42SNamhyung Kim } else { 2398fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 23997727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 2400bc7cad42SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 2401bc7cad42SNamhyung Kim thread->tid); 24026962ccb3SNamhyung Kim } else { 24036962ccb3SNamhyung Kim ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"", 24046962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 24056962ccb3SNamhyung Kim } 24066962ccb3SNamhyung Kim 2407bc7cad42SNamhyung Kim browser->hists->thread_filter = thread__get(thread); 2408bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2409bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->thread_filter); 2410bc7cad42SNamhyung Kim } 2411bc7cad42SNamhyung Kim 2412bc7cad42SNamhyung Kim hists__filter_by_thread(browser->hists); 2413bc7cad42SNamhyung Kim hist_browser__reset(browser); 2414bc7cad42SNamhyung Kim return 0; 2415bc7cad42SNamhyung Kim } 2416bc7cad42SNamhyung Kim 2417bc7cad42SNamhyung Kim static int 2418ea7cd592SNamhyung Kim add_thread_opt(struct hist_browser *browser, struct popup_action *act, 2419ea7cd592SNamhyung Kim char **optstr, struct thread *thread) 2420bc7cad42SNamhyung Kim { 24216962ccb3SNamhyung Kim int ret; 24226962ccb3SNamhyung Kim 24237cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 24247cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2425ea7cd592SNamhyung Kim return 0; 2426ea7cd592SNamhyung Kim 2427fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 24286962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s(%d) thread", 2429ea7cd592SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 2430ea7cd592SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 24316962ccb3SNamhyung Kim thread->tid); 24326962ccb3SNamhyung Kim } else { 24336962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s thread", 24346962ccb3SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 24356962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 24366962ccb3SNamhyung Kim } 24376962ccb3SNamhyung Kim if (ret < 0) 2438ea7cd592SNamhyung Kim return 0; 2439ea7cd592SNamhyung Kim 2440ea7cd592SNamhyung Kim act->thread = thread; 2441ea7cd592SNamhyung Kim act->fn = do_zoom_thread; 2442ea7cd592SNamhyung Kim return 1; 2443ea7cd592SNamhyung Kim } 2444ea7cd592SNamhyung Kim 2445ea7cd592SNamhyung Kim static int 2446ea7cd592SNamhyung Kim do_zoom_dso(struct hist_browser *browser, struct popup_action *act) 2447ea7cd592SNamhyung Kim { 2448045b80ddSArnaldo Carvalho de Melo struct map *map = act->ms.map; 2449ea7cd592SNamhyung Kim 245069849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2451599a2f38SNamhyung Kim return 0; 2452599a2f38SNamhyung Kim 2453bc7cad42SNamhyung Kim if (browser->hists->dso_filter) { 2454bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->dso_filter); 2455bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, false); 2456bc7cad42SNamhyung Kim browser->hists->dso_filter = NULL; 2457bc7cad42SNamhyung Kim ui_helpline__pop(); 2458bc7cad42SNamhyung Kim } else { 24597727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", 2460045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); 2461045b80ddSArnaldo Carvalho de Melo browser->hists->dso_filter = map->dso; 2462bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, true); 2463bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->dso_filter); 2464bc7cad42SNamhyung Kim } 2465bc7cad42SNamhyung Kim 2466bc7cad42SNamhyung Kim hists__filter_by_dso(browser->hists); 2467bc7cad42SNamhyung Kim hist_browser__reset(browser); 2468bc7cad42SNamhyung Kim return 0; 2469bc7cad42SNamhyung Kim } 2470bc7cad42SNamhyung Kim 2471bc7cad42SNamhyung Kim static int 2472ea7cd592SNamhyung Kim add_dso_opt(struct hist_browser *browser, struct popup_action *act, 2473045b80ddSArnaldo Carvalho de Melo char **optstr, struct map *map) 2474bc7cad42SNamhyung Kim { 247569849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2476ea7cd592SNamhyung Kim return 0; 2477ea7cd592SNamhyung Kim 2478ea7cd592SNamhyung Kim if (asprintf(optstr, "Zoom %s %s DSO", 2479ea7cd592SNamhyung Kim browser->hists->dso_filter ? "out of" : "into", 2480045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) 2481ea7cd592SNamhyung Kim return 0; 2482ea7cd592SNamhyung Kim 2483045b80ddSArnaldo Carvalho de Melo act->ms.map = map; 2484ea7cd592SNamhyung Kim act->fn = do_zoom_dso; 2485ea7cd592SNamhyung Kim return 1; 2486ea7cd592SNamhyung Kim } 2487ea7cd592SNamhyung Kim 2488ea7cd592SNamhyung Kim static int 2489ea7cd592SNamhyung Kim do_browse_map(struct hist_browser *browser __maybe_unused, 2490ea7cd592SNamhyung Kim struct popup_action *act) 2491ea7cd592SNamhyung Kim { 2492ea7cd592SNamhyung Kim map__browse(act->ms.map); 2493bc7cad42SNamhyung Kim return 0; 2494bc7cad42SNamhyung Kim } 2495bc7cad42SNamhyung Kim 2496bc7cad42SNamhyung Kim static int 249769849fc5SJiri Olsa add_map_opt(struct hist_browser *browser, 2498ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, struct map *map) 2499ea7cd592SNamhyung Kim { 250069849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2501ea7cd592SNamhyung Kim return 0; 2502ea7cd592SNamhyung Kim 2503ea7cd592SNamhyung Kim if (asprintf(optstr, "Browse map details") < 0) 2504ea7cd592SNamhyung Kim return 0; 2505ea7cd592SNamhyung Kim 2506ea7cd592SNamhyung Kim act->ms.map = map; 2507ea7cd592SNamhyung Kim act->fn = do_browse_map; 2508ea7cd592SNamhyung Kim return 1; 2509ea7cd592SNamhyung Kim } 2510ea7cd592SNamhyung Kim 2511ea7cd592SNamhyung Kim static int 2512bc7cad42SNamhyung Kim do_run_script(struct hist_browser *browser __maybe_unused, 2513ea7cd592SNamhyung Kim struct popup_action *act) 2514bc7cad42SNamhyung Kim { 2515bc7cad42SNamhyung Kim char script_opt[64]; 2516bc7cad42SNamhyung Kim memset(script_opt, 0, sizeof(script_opt)); 2517bc7cad42SNamhyung Kim 2518ea7cd592SNamhyung Kim if (act->thread) { 2519bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -c %s ", 2520ea7cd592SNamhyung Kim thread__comm_str(act->thread)); 2521ea7cd592SNamhyung Kim } else if (act->ms.sym) { 2522bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -S %s ", 2523ea7cd592SNamhyung Kim act->ms.sym->name); 2524bc7cad42SNamhyung Kim } 2525bc7cad42SNamhyung Kim 2526bc7cad42SNamhyung Kim script_browse(script_opt); 2527bc7cad42SNamhyung Kim return 0; 2528bc7cad42SNamhyung Kim } 2529bc7cad42SNamhyung Kim 2530bc7cad42SNamhyung Kim static int 2531ea7cd592SNamhyung Kim add_script_opt(struct hist_browser *browser __maybe_unused, 2532ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 2533ea7cd592SNamhyung Kim struct thread *thread, struct symbol *sym) 2534ea7cd592SNamhyung Kim { 2535ea7cd592SNamhyung Kim if (thread) { 2536ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of thread [%s]", 2537ea7cd592SNamhyung Kim thread__comm_str(thread)) < 0) 2538ea7cd592SNamhyung Kim return 0; 2539ea7cd592SNamhyung Kim } else if (sym) { 2540ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of symbol [%s]", 2541ea7cd592SNamhyung Kim sym->name) < 0) 2542ea7cd592SNamhyung Kim return 0; 2543ea7cd592SNamhyung Kim } else { 2544ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for all samples") < 0) 2545ea7cd592SNamhyung Kim return 0; 2546ea7cd592SNamhyung Kim } 2547ea7cd592SNamhyung Kim 2548ea7cd592SNamhyung Kim act->thread = thread; 2549ea7cd592SNamhyung Kim act->ms.sym = sym; 2550ea7cd592SNamhyung Kim act->fn = do_run_script; 2551ea7cd592SNamhyung Kim return 1; 2552ea7cd592SNamhyung Kim } 2553ea7cd592SNamhyung Kim 2554ea7cd592SNamhyung Kim static int 2555ea7cd592SNamhyung Kim do_switch_data(struct hist_browser *browser __maybe_unused, 2556ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2557bc7cad42SNamhyung Kim { 2558bc7cad42SNamhyung Kim if (switch_data_file()) { 2559bc7cad42SNamhyung Kim ui__warning("Won't switch the data files due to\n" 2560bc7cad42SNamhyung Kim "no valid data file get selected!\n"); 2561ea7cd592SNamhyung Kim return 0; 2562bc7cad42SNamhyung Kim } 2563bc7cad42SNamhyung Kim 2564bc7cad42SNamhyung Kim return K_SWITCH_INPUT_DATA; 2565bc7cad42SNamhyung Kim } 2566bc7cad42SNamhyung Kim 2567ea7cd592SNamhyung Kim static int 2568ea7cd592SNamhyung Kim add_switch_opt(struct hist_browser *browser, 2569ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2570ea7cd592SNamhyung Kim { 2571ea7cd592SNamhyung Kim if (!is_report_browser(browser->hbt)) 2572ea7cd592SNamhyung Kim return 0; 2573ea7cd592SNamhyung Kim 2574ea7cd592SNamhyung Kim if (asprintf(optstr, "Switch to another data file in PWD") < 0) 2575ea7cd592SNamhyung Kim return 0; 2576ea7cd592SNamhyung Kim 2577ea7cd592SNamhyung Kim act->fn = do_switch_data; 2578ea7cd592SNamhyung Kim return 1; 2579ea7cd592SNamhyung Kim } 2580ea7cd592SNamhyung Kim 2581ea7cd592SNamhyung Kim static int 2582ea7cd592SNamhyung Kim do_exit_browser(struct hist_browser *browser __maybe_unused, 2583ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2584ea7cd592SNamhyung Kim { 2585ea7cd592SNamhyung Kim return 0; 2586ea7cd592SNamhyung Kim } 2587ea7cd592SNamhyung Kim 2588ea7cd592SNamhyung Kim static int 2589ea7cd592SNamhyung Kim add_exit_opt(struct hist_browser *browser __maybe_unused, 2590ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2591ea7cd592SNamhyung Kim { 2592ea7cd592SNamhyung Kim if (asprintf(optstr, "Exit") < 0) 2593ea7cd592SNamhyung Kim return 0; 2594ea7cd592SNamhyung Kim 2595ea7cd592SNamhyung Kim act->fn = do_exit_browser; 2596ea7cd592SNamhyung Kim return 1; 2597ea7cd592SNamhyung Kim } 2598ea7cd592SNamhyung Kim 259984734b06SKan Liang static int 260084734b06SKan Liang do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 260184734b06SKan Liang { 260235a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || act->socket < 0) 2603599a2f38SNamhyung Kim return 0; 2604599a2f38SNamhyung Kim 260584734b06SKan Liang if (browser->hists->socket_filter > -1) { 260684734b06SKan Liang pstack__remove(browser->pstack, &browser->hists->socket_filter); 260784734b06SKan Liang browser->hists->socket_filter = -1; 260884734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, false); 260984734b06SKan Liang } else { 261084734b06SKan Liang browser->hists->socket_filter = act->socket; 261184734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, true); 261284734b06SKan Liang pstack__push(browser->pstack, &browser->hists->socket_filter); 261384734b06SKan Liang } 261484734b06SKan Liang 261584734b06SKan Liang hists__filter_by_socket(browser->hists); 261684734b06SKan Liang hist_browser__reset(browser); 261784734b06SKan Liang return 0; 261884734b06SKan Liang } 261984734b06SKan Liang 262084734b06SKan Liang static int 262184734b06SKan Liang add_socket_opt(struct hist_browser *browser, struct popup_action *act, 262284734b06SKan Liang char **optstr, int socket_id) 262384734b06SKan Liang { 262435a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || socket_id < 0) 262584734b06SKan Liang return 0; 262684734b06SKan Liang 262784734b06SKan Liang if (asprintf(optstr, "Zoom %s Processor Socket %d", 262884734b06SKan Liang (browser->hists->socket_filter > -1) ? "out of" : "into", 262984734b06SKan Liang socket_id) < 0) 263084734b06SKan Liang return 0; 263184734b06SKan Liang 263284734b06SKan Liang act->socket = socket_id; 263384734b06SKan Liang act->fn = do_zoom_socket; 263484734b06SKan Liang return 1; 263584734b06SKan Liang } 263684734b06SKan Liang 2637112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb) 2638064f1981SNamhyung Kim { 2639064f1981SNamhyung Kim u64 nr_entries = 0; 2640064f1981SNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 2641064f1981SNamhyung Kim 2642f5b763feSNamhyung Kim if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) { 2643268397cbSNamhyung Kim hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 2644268397cbSNamhyung Kim return; 2645268397cbSNamhyung Kim } 2646268397cbSNamhyung Kim 264714135663SNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2648064f1981SNamhyung Kim nr_entries++; 2649f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd); 2650064f1981SNamhyung Kim } 2651064f1981SNamhyung Kim 2652112f761fSNamhyung Kim hb->nr_non_filtered_entries = nr_entries; 2653f5b763feSNamhyung Kim hb->nr_hierarchy_entries = nr_entries; 2654064f1981SNamhyung Kim } 2655341487abSFeng Tang 2656b62e8dfcSNamhyung Kim static void hist_browser__update_percent_limit(struct hist_browser *hb, 2657b62e8dfcSNamhyung Kim double percent) 2658b62e8dfcSNamhyung Kim { 2659b62e8dfcSNamhyung Kim struct hist_entry *he; 2660b62e8dfcSNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 2661b62e8dfcSNamhyung Kim u64 total = hists__total_period(hb->hists); 2662b62e8dfcSNamhyung Kim u64 min_callchain_hits = total * (percent / 100); 2663b62e8dfcSNamhyung Kim 2664b62e8dfcSNamhyung Kim hb->min_pcnt = callchain_param.min_percent = percent; 2665b62e8dfcSNamhyung Kim 2666b62e8dfcSNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2667b62e8dfcSNamhyung Kim he = rb_entry(nd, struct hist_entry, rb_node); 2668b62e8dfcSNamhyung Kim 266979dded87SNamhyung Kim if (he->has_no_entry) { 267079dded87SNamhyung Kim he->has_no_entry = false; 267179dded87SNamhyung Kim he->nr_rows = 0; 267279dded87SNamhyung Kim } 267379dded87SNamhyung Kim 2674d0506edbSNamhyung Kim if (!he->leaf || !symbol_conf.use_callchain) 2675d0506edbSNamhyung Kim goto next; 2676d0506edbSNamhyung Kim 2677b62e8dfcSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) { 2678b62e8dfcSNamhyung Kim total = he->stat.period; 2679b62e8dfcSNamhyung Kim 2680b62e8dfcSNamhyung Kim if (symbol_conf.cumulate_callchain) 2681b62e8dfcSNamhyung Kim total = he->stat_acc->period; 2682b62e8dfcSNamhyung Kim 2683b62e8dfcSNamhyung Kim min_callchain_hits = total * (percent / 100); 2684b62e8dfcSNamhyung Kim } 2685b62e8dfcSNamhyung Kim 2686b62e8dfcSNamhyung Kim callchain_param.sort(&he->sorted_chain, he->callchain, 2687b62e8dfcSNamhyung Kim min_callchain_hits, &callchain_param); 2688b62e8dfcSNamhyung Kim 2689d0506edbSNamhyung Kim next: 2690201fde73SNamhyung Kim nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 2691d0506edbSNamhyung Kim 2692b62e8dfcSNamhyung Kim /* force to re-evaluate folding state of callchains */ 2693b62e8dfcSNamhyung Kim he->init_have_children = false; 2694492b1010SNamhyung Kim hist_entry__set_folding(he, hb, false); 2695b62e8dfcSNamhyung Kim } 2696b62e8dfcSNamhyung Kim } 2697b62e8dfcSNamhyung Kim 2698aca7a94dSNamhyung Kim static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 2699dd00d486SJiri Olsa const char *helpline, 2700aca7a94dSNamhyung Kim bool left_exits, 270168d80758SNamhyung Kim struct hist_browser_timer *hbt, 2702064f1981SNamhyung Kim float min_pcnt, 270306cc1a47SKan Liang struct perf_env *env, 2704cd0cccbaSArnaldo Carvalho de Melo bool warn_lost_event, 2705cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *annotation_opts) 2706aca7a94dSNamhyung Kim { 27074ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 2708cd0cccbaSArnaldo Carvalho de Melo struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts); 2709aca7a94dSNamhyung Kim struct branch_info *bi; 2710f2b487dbSNamhyung Kim #define MAX_OPTIONS 16 2711f2b487dbSNamhyung Kim char *options[MAX_OPTIONS]; 2712ea7cd592SNamhyung Kim struct popup_action actions[MAX_OPTIONS]; 2713aca7a94dSNamhyung Kim int nr_options = 0; 2714aca7a94dSNamhyung Kim int key = -1; 2715aca7a94dSNamhyung Kim char buf[64]; 27169783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 2717aca7a94dSNamhyung Kim 2718e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 2719e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 2720e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 2721e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 27226a02f06eSAndi Kleen "q/ESC/CTRL+C Exit browser or go back to previous screen\n\n" \ 2723e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 2724e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 2725e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 27267727a925SArnaldo Carvalho de Melo "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \ 27277727a925SArnaldo Carvalho de Melo "ESC Zoom out\n" \ 2728e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 2729e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 2730e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 2731e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 2732105eb30fSNamhyung Kim "F Toggle percentage of filtered entries\n" \ 2733025bf7eaSArnaldo Carvalho de Melo "H Display column headers\n" \ 2734b62e8dfcSNamhyung Kim "L Change percent limit\n" \ 273531eb4360SNamhyung Kim "m Display context menu\n" \ 273684734b06SKan Liang "S Zoom into current Processor Socket\n" \ 2737e8e684a5SNamhyung Kim 2738e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 2739e8e684a5SNamhyung Kim const char report_help[] = HIST_BROWSER_HELP_COMMON 27406dd60135SNamhyung Kim "i Show header information\n" 2741e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2742e8e684a5SNamhyung Kim "r Run available scripts\n" 2743e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 2744e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2745e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 2746e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2747e8e684a5SNamhyung Kim const char top_help[] = HIST_BROWSER_HELP_COMMON 2748e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2749e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2750e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 275142337a22SNamhyung Kim "z Toggle zeroing of samples\n" 2752fbb7997eSArnaldo Carvalho de Melo "f Enable/Disable events\n" 2753e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2754e8e684a5SNamhyung Kim 2755aca7a94dSNamhyung Kim if (browser == NULL) 2756aca7a94dSNamhyung Kim return -1; 2757aca7a94dSNamhyung Kim 2758ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 2759ed426915SNamhyung Kim SLang_reset_tty(); 2760ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 2761ed426915SNamhyung Kim 276203905048SNamhyung Kim if (min_pcnt) 2763064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 2764112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 2765064f1981SNamhyung Kim 276684734b06SKan Liang browser->pstack = pstack__new(3); 276701f00a1cSNamhyung Kim if (browser->pstack == NULL) 2768aca7a94dSNamhyung Kim goto out; 2769aca7a94dSNamhyung Kim 2770aca7a94dSNamhyung Kim ui_helpline__push(helpline); 2771aca7a94dSNamhyung Kim 2772aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 2773ea7cd592SNamhyung Kim memset(actions, 0, sizeof(actions)); 2774aca7a94dSNamhyung Kim 27755b591669SNamhyung Kim if (symbol_conf.col_width_list_str) 27765b591669SNamhyung Kim perf_hpp__set_user_width(symbol_conf.col_width_list_str); 27775b591669SNamhyung Kim 2778aca7a94dSNamhyung Kim while (1) { 2779f3b623b8SArnaldo Carvalho de Melo struct thread *thread = NULL; 2780045b80ddSArnaldo Carvalho de Melo struct map *map = NULL; 2781ea7cd592SNamhyung Kim int choice = 0; 278284734b06SKan Liang int socked_id = -1; 2783aca7a94dSNamhyung Kim 2784aca7a94dSNamhyung Kim nr_options = 0; 2785aca7a94dSNamhyung Kim 278606cc1a47SKan Liang key = hist_browser__run(browser, helpline, 278706cc1a47SKan Liang warn_lost_event); 2788aca7a94dSNamhyung Kim 2789aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 2790aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 2791045b80ddSArnaldo Carvalho de Melo map = browser->selection->map; 279284734b06SKan Liang socked_id = browser->he_selection->socket; 2793aca7a94dSNamhyung Kim } 2794aca7a94dSNamhyung Kim switch (key) { 2795aca7a94dSNamhyung Kim case K_TAB: 2796aca7a94dSNamhyung Kim case K_UNTAB: 2797aca7a94dSNamhyung Kim if (nr_events == 1) 2798aca7a94dSNamhyung Kim continue; 2799aca7a94dSNamhyung Kim /* 2800aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 2801aca7a94dSNamhyung Kim * go to the next or previous 2802aca7a94dSNamhyung Kim */ 2803aca7a94dSNamhyung Kim goto out_free_stack; 2804aca7a94dSNamhyung Kim case 'a': 28052e0453afSJiri Olsa if (!hists__has(hists, sym)) { 2806aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 2807aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 2808aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 2809aca7a94dSNamhyung Kim continue; 2810aca7a94dSNamhyung Kim } 2811aca7a94dSNamhyung Kim 2812aca7a94dSNamhyung Kim if (browser->selection == NULL || 2813aca7a94dSNamhyung Kim browser->selection->sym == NULL || 2814aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 2815aca7a94dSNamhyung Kim continue; 2816bc7cad42SNamhyung Kim 2817ea7cd592SNamhyung Kim actions->ms.map = browser->selection->map; 2818ea7cd592SNamhyung Kim actions->ms.sym = browser->selection->sym; 2819ea7cd592SNamhyung Kim do_annotate(browser, actions); 2820bc7cad42SNamhyung Kim continue; 2821aff3f3f6SArnaldo Carvalho de Melo case 'P': 2822aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 2823aff3f3f6SArnaldo Carvalho de Melo continue; 2824aca7a94dSNamhyung Kim case 'd': 2825fae00650SArnaldo Carvalho de Melo actions->ms.map = map; 2826ea7cd592SNamhyung Kim do_zoom_dso(browser, actions); 2827bc7cad42SNamhyung Kim continue; 2828a7cb8863SArnaldo Carvalho de Melo case 'V': 282921e8c810SAlexis Berlemont verbose = (verbose + 1) % 4; 283021e8c810SAlexis Berlemont browser->show_dso = verbose > 0; 283121e8c810SAlexis Berlemont ui_helpline__fpush("Verbosity level set to %d\n", 283221e8c810SAlexis Berlemont verbose); 2833a7cb8863SArnaldo Carvalho de Melo continue; 2834aca7a94dSNamhyung Kim case 't': 2835ea7cd592SNamhyung Kim actions->thread = thread; 2836ea7cd592SNamhyung Kim do_zoom_thread(browser, actions); 2837bc7cad42SNamhyung Kim continue; 283884734b06SKan Liang case 'S': 283984734b06SKan Liang actions->socket = socked_id; 284084734b06SKan Liang do_zoom_socket(browser, actions); 284184734b06SKan Liang continue; 28425a5626b1SArnaldo Carvalho de Melo case '/': 2843aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 28444aa8e454SArnaldo Carvalho de Melo "Please enter the name of symbol you want to see.\n" 28454aa8e454SArnaldo Carvalho de Melo "To remove the filter later, press / + ENTER.", 2846aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 2847aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 284805e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 284905e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 2850aca7a94dSNamhyung Kim hist_browser__reset(browser); 2851aca7a94dSNamhyung Kim } 2852aca7a94dSNamhyung Kim continue; 2853cdbab7c2SFeng Tang case 'r': 2854ea7cd592SNamhyung Kim if (is_report_browser(hbt)) { 2855ea7cd592SNamhyung Kim actions->thread = NULL; 2856ea7cd592SNamhyung Kim actions->ms.sym = NULL; 2857ea7cd592SNamhyung Kim do_run_script(browser, actions); 2858ea7cd592SNamhyung Kim } 2859c77d8d70SFeng Tang continue; 2860341487abSFeng Tang case 's': 2861bc7cad42SNamhyung Kim if (is_report_browser(hbt)) { 2862ea7cd592SNamhyung Kim key = do_switch_data(browser, actions); 2863bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 2864bc7cad42SNamhyung Kim goto out_free_stack; 2865bc7cad42SNamhyung Kim } 2866341487abSFeng Tang continue; 28676dd60135SNamhyung Kim case 'i': 28686dd60135SNamhyung Kim /* env->arch is NULL for live-mode (i.e. perf top) */ 28696dd60135SNamhyung Kim if (env->arch) 28706dd60135SNamhyung Kim tui__header_window(env); 28716dd60135SNamhyung Kim continue; 2872105eb30fSNamhyung Kim case 'F': 2873105eb30fSNamhyung Kim symbol_conf.filter_relative ^= 1; 2874105eb30fSNamhyung Kim continue; 287542337a22SNamhyung Kim case 'z': 287642337a22SNamhyung Kim if (!is_report_browser(hbt)) { 287742337a22SNamhyung Kim struct perf_top *top = hbt->arg; 287842337a22SNamhyung Kim 287942337a22SNamhyung Kim top->zero = !top->zero; 288042337a22SNamhyung Kim } 288142337a22SNamhyung Kim continue; 2882b62e8dfcSNamhyung Kim case 'L': 2883b62e8dfcSNamhyung Kim if (ui_browser__input_window("Percent Limit", 2884b62e8dfcSNamhyung Kim "Please enter the value you want to hide entries under that percent.", 2885b62e8dfcSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 2886b62e8dfcSNamhyung Kim delay_secs * 2) == K_ENTER) { 2887b62e8dfcSNamhyung Kim char *end; 2888b62e8dfcSNamhyung Kim double new_percent = strtod(buf, &end); 2889b62e8dfcSNamhyung Kim 2890b62e8dfcSNamhyung Kim if (new_percent < 0 || new_percent > 100) { 2891b62e8dfcSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 2892b62e8dfcSNamhyung Kim "Invalid percent: %.2f", new_percent); 2893b62e8dfcSNamhyung Kim continue; 2894b62e8dfcSNamhyung Kim } 2895b62e8dfcSNamhyung Kim 2896b62e8dfcSNamhyung Kim hist_browser__update_percent_limit(browser, new_percent); 2897b62e8dfcSNamhyung Kim hist_browser__reset(browser); 2898b62e8dfcSNamhyung Kim } 2899b62e8dfcSNamhyung Kim continue; 2900aca7a94dSNamhyung Kim case K_F1: 2901aca7a94dSNamhyung Kim case 'h': 2902aca7a94dSNamhyung Kim case '?': 2903aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 2904e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 2905aca7a94dSNamhyung Kim continue; 2906aca7a94dSNamhyung Kim case K_ENTER: 2907aca7a94dSNamhyung Kim case K_RIGHT: 290831eb4360SNamhyung Kim case 'm': 2909aca7a94dSNamhyung Kim /* menu */ 2910aca7a94dSNamhyung Kim break; 291163ab1749SArnaldo Carvalho de Melo case K_ESC: 2912aca7a94dSNamhyung Kim case K_LEFT: { 2913aca7a94dSNamhyung Kim const void *top; 2914aca7a94dSNamhyung Kim 291501f00a1cSNamhyung Kim if (pstack__empty(browser->pstack)) { 2916aca7a94dSNamhyung Kim /* 2917aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 2918aca7a94dSNamhyung Kim */ 2919aca7a94dSNamhyung Kim if (left_exits) 2920aca7a94dSNamhyung Kim goto out_free_stack; 292163ab1749SArnaldo Carvalho de Melo 292263ab1749SArnaldo Carvalho de Melo if (key == K_ESC && 292363ab1749SArnaldo Carvalho de Melo ui_browser__dialog_yesno(&browser->b, 292463ab1749SArnaldo Carvalho de Melo "Do you really want to exit?")) 292563ab1749SArnaldo Carvalho de Melo goto out_free_stack; 292663ab1749SArnaldo Carvalho de Melo 2927aca7a94dSNamhyung Kim continue; 2928aca7a94dSNamhyung Kim } 29296422184bSNamhyung Kim top = pstack__peek(browser->pstack); 2930bc7cad42SNamhyung Kim if (top == &browser->hists->dso_filter) { 29316422184bSNamhyung Kim /* 29326422184bSNamhyung Kim * No need to set actions->dso here since 29336422184bSNamhyung Kim * it's just to remove the current filter. 29346422184bSNamhyung Kim * Ditto for thread below. 29356422184bSNamhyung Kim */ 29366422184bSNamhyung Kim do_zoom_dso(browser, actions); 293784734b06SKan Liang } else if (top == &browser->hists->thread_filter) { 29386422184bSNamhyung Kim do_zoom_thread(browser, actions); 293984734b06SKan Liang } else if (top == &browser->hists->socket_filter) { 294084734b06SKan Liang do_zoom_socket(browser, actions); 294184734b06SKan Liang } 2942aca7a94dSNamhyung Kim continue; 2943aca7a94dSNamhyung Kim } 2944aca7a94dSNamhyung Kim case 'q': 2945aca7a94dSNamhyung Kim case CTRL('c'): 2946516e5368SArnaldo Carvalho de Melo goto out_free_stack; 2947fbb7997eSArnaldo Carvalho de Melo case 'f': 294813d1e536SNamhyung Kim if (!is_report_browser(hbt)) { 294913d1e536SNamhyung Kim struct perf_top *top = hbt->arg; 295013d1e536SNamhyung Kim 295113d1e536SNamhyung Kim perf_evlist__toggle_enable(top->evlist); 295213d1e536SNamhyung Kim /* 295313d1e536SNamhyung Kim * No need to refresh, resort/decay histogram 295413d1e536SNamhyung Kim * entries if we are not collecting samples: 295513d1e536SNamhyung Kim */ 295613d1e536SNamhyung Kim if (top->evlist->enabled) { 295713d1e536SNamhyung Kim helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; 295813d1e536SNamhyung Kim hbt->refresh = delay_secs; 295913d1e536SNamhyung Kim } else { 296013d1e536SNamhyung Kim helpline = "Press 'f' again to re-enable the events"; 296113d1e536SNamhyung Kim hbt->refresh = 0; 296213d1e536SNamhyung Kim } 296313d1e536SNamhyung Kim continue; 296413d1e536SNamhyung Kim } 29653e323dc0SArnaldo Carvalho de Melo /* Fall thru */ 2966aca7a94dSNamhyung Kim default: 29673e323dc0SArnaldo Carvalho de Melo helpline = "Press '?' for help on key bindings"; 2968aca7a94dSNamhyung Kim continue; 2969aca7a94dSNamhyung Kim } 2970aca7a94dSNamhyung Kim 29712e0453afSJiri Olsa if (!hists__has(hists, sym) || browser->selection == NULL) 29720ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 29730ba332f7SArnaldo Carvalho de Melo 297455369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 2975aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 29760ba332f7SArnaldo Carvalho de Melo 29770ba332f7SArnaldo Carvalho de Melo if (bi == NULL) 29780ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 29790ba332f7SArnaldo Carvalho de Melo 2980ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2981ea7cd592SNamhyung Kim &actions[nr_options], 2982ea7cd592SNamhyung Kim &options[nr_options], 2983ea7cd592SNamhyung Kim bi->from.map, 2984ea7cd592SNamhyung Kim bi->from.sym); 2985ea7cd592SNamhyung Kim if (bi->to.sym != bi->from.sym) 2986ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2987ea7cd592SNamhyung Kim &actions[nr_options], 2988ea7cd592SNamhyung Kim &options[nr_options], 2989ea7cd592SNamhyung Kim bi->to.map, 2990ea7cd592SNamhyung Kim bi->to.sym); 2991aca7a94dSNamhyung Kim } else { 2992ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2993ea7cd592SNamhyung Kim &actions[nr_options], 2994ea7cd592SNamhyung Kim &options[nr_options], 2995ea7cd592SNamhyung Kim browser->selection->map, 2996ea7cd592SNamhyung Kim browser->selection->sym); 2997446fb96cSArnaldo Carvalho de Melo } 29980ba332f7SArnaldo Carvalho de Melo skip_annotation: 2999ea7cd592SNamhyung Kim nr_options += add_thread_opt(browser, &actions[nr_options], 3000ea7cd592SNamhyung Kim &options[nr_options], thread); 3001ea7cd592SNamhyung Kim nr_options += add_dso_opt(browser, &actions[nr_options], 3002045b80ddSArnaldo Carvalho de Melo &options[nr_options], map); 3003ea7cd592SNamhyung Kim nr_options += add_map_opt(browser, &actions[nr_options], 3004ea7cd592SNamhyung Kim &options[nr_options], 3005bd315aabSWang Nan browser->selection ? 3006bd315aabSWang Nan browser->selection->map : NULL); 300784734b06SKan Liang nr_options += add_socket_opt(browser, &actions[nr_options], 300884734b06SKan Liang &options[nr_options], 300984734b06SKan Liang socked_id); 3010cdbab7c2SFeng Tang /* perf script support */ 3011b1baae89SNamhyung Kim if (!is_report_browser(hbt)) 3012b1baae89SNamhyung Kim goto skip_scripting; 3013b1baae89SNamhyung Kim 3014cdbab7c2SFeng Tang if (browser->he_selection) { 3015fa82911aSJiri Olsa if (hists__has(hists, thread) && thread) { 3016ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 3017ea7cd592SNamhyung Kim &actions[nr_options], 3018ea7cd592SNamhyung Kim &options[nr_options], 3019ea7cd592SNamhyung Kim thread, NULL); 30202eafd410SNamhyung Kim } 3021bd315aabSWang Nan /* 3022bd315aabSWang Nan * Note that browser->selection != NULL 3023bd315aabSWang Nan * when browser->he_selection is not NULL, 3024bd315aabSWang Nan * so we don't need to check browser->selection 3025bd315aabSWang Nan * before fetching browser->selection->sym like what 3026bd315aabSWang Nan * we do before fetching browser->selection->map. 3027bd315aabSWang Nan * 3028bd315aabSWang Nan * See hist_browser__show_entry. 3029bd315aabSWang Nan */ 30302e0453afSJiri Olsa if (hists__has(hists, sym) && browser->selection->sym) { 3031ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 3032ea7cd592SNamhyung Kim &actions[nr_options], 3033ea7cd592SNamhyung Kim &options[nr_options], 3034ea7cd592SNamhyung Kim NULL, browser->selection->sym); 3035cdbab7c2SFeng Tang } 3036c221acb0SNamhyung Kim } 3037ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, &actions[nr_options], 3038ea7cd592SNamhyung Kim &options[nr_options], NULL, NULL); 3039ea7cd592SNamhyung Kim nr_options += add_switch_opt(browser, &actions[nr_options], 3040ea7cd592SNamhyung Kim &options[nr_options]); 3041b1baae89SNamhyung Kim skip_scripting: 3042ea7cd592SNamhyung Kim nr_options += add_exit_opt(browser, &actions[nr_options], 3043ea7cd592SNamhyung Kim &options[nr_options]); 3044aca7a94dSNamhyung Kim 3045ea7cd592SNamhyung Kim do { 3046ea7cd592SNamhyung Kim struct popup_action *act; 3047ea7cd592SNamhyung Kim 3048ea7cd592SNamhyung Kim choice = ui__popup_menu(nr_options, options); 3049ea7cd592SNamhyung Kim if (choice == -1 || choice >= nr_options) 3050aca7a94dSNamhyung Kim break; 3051aca7a94dSNamhyung Kim 3052ea7cd592SNamhyung Kim act = &actions[choice]; 3053ea7cd592SNamhyung Kim key = act->fn(browser, act); 3054ea7cd592SNamhyung Kim } while (key == 1); 3055aca7a94dSNamhyung Kim 3056bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 3057341487abSFeng Tang break; 3058341487abSFeng Tang } 3059aca7a94dSNamhyung Kim out_free_stack: 306001f00a1cSNamhyung Kim pstack__delete(browser->pstack); 3061aca7a94dSNamhyung Kim out: 3062aca7a94dSNamhyung Kim hist_browser__delete(browser); 3063f2b487dbSNamhyung Kim free_popup_options(options, MAX_OPTIONS); 3064aca7a94dSNamhyung Kim return key; 3065aca7a94dSNamhyung Kim } 3066aca7a94dSNamhyung Kim 3067aca7a94dSNamhyung Kim struct perf_evsel_menu { 3068aca7a94dSNamhyung Kim struct ui_browser b; 3069aca7a94dSNamhyung Kim struct perf_evsel *selection; 3070cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *annotation_opts; 3071aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 3072064f1981SNamhyung Kim float min_pcnt; 3073ce80d3beSKan Liang struct perf_env *env; 3074aca7a94dSNamhyung Kim }; 3075aca7a94dSNamhyung Kim 3076aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 3077aca7a94dSNamhyung Kim void *entry, int row) 3078aca7a94dSNamhyung Kim { 3079aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 3080aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 3081aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 30824ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 3083aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 30844ea062edSArnaldo Carvalho de Melo unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 30857289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 3086aca7a94dSNamhyung Kim char bf[256], unit; 3087aca7a94dSNamhyung Kim const char *warn = " "; 3088aca7a94dSNamhyung Kim size_t printed; 3089aca7a94dSNamhyung Kim 3090aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 3091aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 3092aca7a94dSNamhyung Kim 3093759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 3094717e263fSNamhyung Kim struct perf_evsel *pos; 3095717e263fSNamhyung Kim 3096717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 3097717e263fSNamhyung Kim 3098717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 30994ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 31004ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 3101717e263fSNamhyung Kim } 3102717e263fSNamhyung Kim } 3103717e263fSNamhyung Kim 3104aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3105aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 3106aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 3107517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%s", bf); 3108aca7a94dSNamhyung Kim 31094ea062edSArnaldo Carvalho de Melo nr_events = hists->stats.nr_events[PERF_RECORD_LOST]; 3110aca7a94dSNamhyung Kim if (nr_events != 0) { 3111aca7a94dSNamhyung Kim menu->lost_events = true; 3112aca7a94dSNamhyung Kim if (!current_entry) 3113aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 3114aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3115aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 3116aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 3117aca7a94dSNamhyung Kim warn = bf; 3118aca7a94dSNamhyung Kim } 3119aca7a94dSNamhyung Kim 312026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, warn, browser->width - printed); 3121aca7a94dSNamhyung Kim 3122aca7a94dSNamhyung Kim if (current_entry) 3123aca7a94dSNamhyung Kim menu->selection = evsel; 3124aca7a94dSNamhyung Kim } 3125aca7a94dSNamhyung Kim 3126aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 3127aca7a94dSNamhyung Kim int nr_events, const char *help, 312806cc1a47SKan Liang struct hist_browser_timer *hbt, 312906cc1a47SKan Liang bool warn_lost_event) 3130aca7a94dSNamhyung Kim { 3131aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 3132aca7a94dSNamhyung Kim struct perf_evsel *pos; 3133dd00d486SJiri Olsa const char *title = "Available samples"; 31349783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 3135aca7a94dSNamhyung Kim int key; 3136aca7a94dSNamhyung Kim 3137aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 3138aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 3139aca7a94dSNamhyung Kim return -1; 3140aca7a94dSNamhyung Kim 3141aca7a94dSNamhyung Kim while (1) { 3142aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 3143aca7a94dSNamhyung Kim 3144aca7a94dSNamhyung Kim switch (key) { 3145aca7a94dSNamhyung Kim case K_TIMER: 31469783adf7SNamhyung Kim hbt->timer(hbt->arg); 3147aca7a94dSNamhyung Kim 314806cc1a47SKan Liang if (!menu->lost_events_warned && 314906cc1a47SKan Liang menu->lost_events && 315006cc1a47SKan Liang warn_lost_event) { 3151aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 3152aca7a94dSNamhyung Kim menu->lost_events_warned = true; 3153aca7a94dSNamhyung Kim } 3154aca7a94dSNamhyung Kim continue; 3155aca7a94dSNamhyung Kim case K_RIGHT: 3156aca7a94dSNamhyung Kim case K_ENTER: 3157aca7a94dSNamhyung Kim if (!menu->selection) 3158aca7a94dSNamhyung Kim continue; 3159aca7a94dSNamhyung Kim pos = menu->selection; 3160aca7a94dSNamhyung Kim browse_hists: 3161aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 3162aca7a94dSNamhyung Kim /* 3163aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 3164aca7a94dSNamhyung Kim * default evsel resorted hists tree. 3165aca7a94dSNamhyung Kim */ 31669783adf7SNamhyung Kim if (hbt) 31679783adf7SNamhyung Kim hbt->timer(hbt->arg); 3168aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 3169dd00d486SJiri Olsa true, hbt, 3170064f1981SNamhyung Kim menu->min_pcnt, 317106cc1a47SKan Liang menu->env, 3172cd0cccbaSArnaldo Carvalho de Melo warn_lost_event, 3173cd0cccbaSArnaldo Carvalho de Melo menu->annotation_opts); 3174aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 3175aca7a94dSNamhyung Kim switch (key) { 3176aca7a94dSNamhyung Kim case K_TAB: 3177aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 31789a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__first(evlist); 3179aca7a94dSNamhyung Kim else 31809a354cdcSArnaldo Carvalho de Melo pos = perf_evsel__next(pos); 3181aca7a94dSNamhyung Kim goto browse_hists; 3182aca7a94dSNamhyung Kim case K_UNTAB: 3183aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 31849a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__last(evlist); 3185aca7a94dSNamhyung Kim else 3186d87fcb4aSArnaldo Carvalho de Melo pos = perf_evsel__prev(pos); 3187aca7a94dSNamhyung Kim goto browse_hists; 3188341487abSFeng Tang case K_SWITCH_INPUT_DATA: 3189aca7a94dSNamhyung Kim case 'q': 3190aca7a94dSNamhyung Kim case CTRL('c'): 3191aca7a94dSNamhyung Kim goto out; 319263ab1749SArnaldo Carvalho de Melo case K_ESC: 3193aca7a94dSNamhyung Kim default: 3194aca7a94dSNamhyung Kim continue; 3195aca7a94dSNamhyung Kim } 3196aca7a94dSNamhyung Kim case K_LEFT: 3197aca7a94dSNamhyung Kim continue; 3198aca7a94dSNamhyung Kim case K_ESC: 3199aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 3200aca7a94dSNamhyung Kim "Do you really want to exit?")) 3201aca7a94dSNamhyung Kim continue; 3202aca7a94dSNamhyung Kim /* Fall thru */ 3203aca7a94dSNamhyung Kim case 'q': 3204aca7a94dSNamhyung Kim case CTRL('c'): 3205aca7a94dSNamhyung Kim goto out; 3206aca7a94dSNamhyung Kim default: 3207aca7a94dSNamhyung Kim continue; 3208aca7a94dSNamhyung Kim } 3209aca7a94dSNamhyung Kim } 3210aca7a94dSNamhyung Kim 3211aca7a94dSNamhyung Kim out: 3212aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 3213aca7a94dSNamhyung Kim return key; 3214aca7a94dSNamhyung Kim } 3215aca7a94dSNamhyung Kim 3216316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 3217fc24d7c2SNamhyung Kim void *entry) 3218fc24d7c2SNamhyung Kim { 3219fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 3220fc24d7c2SNamhyung Kim 3221fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 3222fc24d7c2SNamhyung Kim return true; 3223fc24d7c2SNamhyung Kim 3224fc24d7c2SNamhyung Kim return false; 3225fc24d7c2SNamhyung Kim } 3226fc24d7c2SNamhyung Kim 3227aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 3228fc24d7c2SNamhyung Kim int nr_entries, const char *help, 322968d80758SNamhyung Kim struct hist_browser_timer *hbt, 3230064f1981SNamhyung Kim float min_pcnt, 323106cc1a47SKan Liang struct perf_env *env, 3232cd0cccbaSArnaldo Carvalho de Melo bool warn_lost_event, 3233cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *annotation_opts) 3234aca7a94dSNamhyung Kim { 3235aca7a94dSNamhyung Kim struct perf_evsel *pos; 3236aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 3237aca7a94dSNamhyung Kim .b = { 3238aca7a94dSNamhyung Kim .entries = &evlist->entries, 3239aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 3240aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 3241aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 3242fc24d7c2SNamhyung Kim .filter = filter_group_entries, 3243fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 3244aca7a94dSNamhyung Kim .priv = evlist, 3245aca7a94dSNamhyung Kim }, 3246064f1981SNamhyung Kim .min_pcnt = min_pcnt, 324768d80758SNamhyung Kim .env = env, 3248cd0cccbaSArnaldo Carvalho de Melo .annotation_opts = annotation_opts, 3249aca7a94dSNamhyung Kim }; 3250aca7a94dSNamhyung Kim 3251aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 3252aca7a94dSNamhyung Kim 3253e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, pos) { 32547289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 3255aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 3256aca7a94dSNamhyung Kim 3257aca7a94dSNamhyung Kim if (menu.b.width < line_len) 3258aca7a94dSNamhyung Kim menu.b.width = line_len; 3259aca7a94dSNamhyung Kim } 3260aca7a94dSNamhyung Kim 326106cc1a47SKan Liang return perf_evsel_menu__run(&menu, nr_entries, help, 326206cc1a47SKan Liang hbt, warn_lost_event); 3263aca7a94dSNamhyung Kim } 3264aca7a94dSNamhyung Kim 3265aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 326668d80758SNamhyung Kim struct hist_browser_timer *hbt, 3267064f1981SNamhyung Kim float min_pcnt, 326806cc1a47SKan Liang struct perf_env *env, 3269cd0cccbaSArnaldo Carvalho de Melo bool warn_lost_event, 3270cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *annotation_opts) 3271aca7a94dSNamhyung Kim { 3272fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 3273fc24d7c2SNamhyung Kim 3274fc24d7c2SNamhyung Kim single_entry: 3275fc24d7c2SNamhyung Kim if (nr_entries == 1) { 32769a354cdcSArnaldo Carvalho de Melo struct perf_evsel *first = perf_evlist__first(evlist); 3277fc24d7c2SNamhyung Kim 3278fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 3279dd00d486SJiri Olsa false, hbt, min_pcnt, 3280cd0cccbaSArnaldo Carvalho de Melo env, warn_lost_event, 3281cd0cccbaSArnaldo Carvalho de Melo annotation_opts); 3282aca7a94dSNamhyung Kim } 3283aca7a94dSNamhyung Kim 3284fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 3285fc24d7c2SNamhyung Kim struct perf_evsel *pos; 3286fc24d7c2SNamhyung Kim 3287fc24d7c2SNamhyung Kim nr_entries = 0; 3288e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, pos) { 3289fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 3290fc24d7c2SNamhyung Kim nr_entries++; 32910050f7aaSArnaldo Carvalho de Melo } 3292fc24d7c2SNamhyung Kim 3293fc24d7c2SNamhyung Kim if (nr_entries == 1) 3294fc24d7c2SNamhyung Kim goto single_entry; 3295fc24d7c2SNamhyung Kim } 3296fc24d7c2SNamhyung Kim 3297fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 329806cc1a47SKan Liang hbt, min_pcnt, env, 3299cd0cccbaSArnaldo Carvalho de Melo warn_lost_event, 3300cd0cccbaSArnaldo Carvalho de Melo annotation_opts); 3301aca7a94dSNamhyung Kim } 3302