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> 93ca43b60SArnaldo Carvalho de Melo #include <linux/string.h> 10b0742e90SArnaldo Carvalho de Melo #include <sys/ttydefaults.h> 111d6c49dfSAndi Kleen #include <linux/time64.h> 127f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 13aca7a94dSNamhyung Kim 14b4209025SArnaldo Carvalho de Melo #include "../../util/debug.h" 154a3cec84SArnaldo Carvalho de Melo #include "../../util/dso.h" 16b10ba7f1SArnaldo Carvalho de Melo #include "../../util/callchain.h" 17aca7a94dSNamhyung Kim #include "../../util/evsel.h" 18aca7a94dSNamhyung Kim #include "../../util/evlist.h" 19f2a39fe8SArnaldo Carvalho de Melo #include "../../util/header.h" 20aca7a94dSNamhyung Kim #include "../../util/hist.h" 21209f4e70SArnaldo Carvalho de Melo #include "../../util/machine.h" 221101f69aSArnaldo Carvalho de Melo #include "../../util/map.h" 23209f4e70SArnaldo Carvalho de Melo #include "../../util/maps.h" 24daecf9e0SArnaldo Carvalho de Melo #include "../../util/symbol.h" 25d3300a3cSArnaldo Carvalho de Melo #include "../../util/map_symbol.h" 26d3300a3cSArnaldo Carvalho de Melo #include "../../util/branch.h" 27aca7a94dSNamhyung Kim #include "../../util/pstack.h" 28aca7a94dSNamhyung Kim #include "../../util/sort.h" 2942337a22SNamhyung Kim #include "../../util/top.h" 30e7ff8920SArnaldo Carvalho de Melo #include "../../util/thread.h" 317fa46cbfSJin Yao #include "../../util/block-info.h" 3268d80758SNamhyung Kim #include "../../arch/common.h" 33c1a604dfSArnaldo Carvalho de Melo #include "../../perf.h" 34aca7a94dSNamhyung Kim 35f758990fSJiri Olsa #include "../browsers/hists.h" 36aca7a94dSNamhyung Kim #include "../helpline.h" 37aca7a94dSNamhyung Kim #include "../util.h" 38aca7a94dSNamhyung Kim #include "../ui.h" 39aca7a94dSNamhyung Kim #include "map.h" 40d755330cSJiri Olsa #include "annotate.h" 41632a5cabSArnaldo Carvalho de Melo #include "srcline.h" 42a067558eSArnaldo Carvalho de Melo #include "string2.h" 4358db1d6eSArnaldo Carvalho de Melo #include "units.h" 441d6c49dfSAndi Kleen #include "time-utils.h" 45aca7a94dSNamhyung Kim 463052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 473d689ed6SArnaldo Carvalho de Melo 48f5951d56SNamhyung Kim extern void hist_browser__init_hpp(void); 49f5951d56SNamhyung Kim 50f016d24aSArnaldo Carvalho de Melo static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size); 51112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb); 52aca7a94dSNamhyung Kim 53c3b78952SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 54c3b78952SNamhyung Kim float min_pcnt); 55c3b78952SNamhyung Kim 56268397cbSNamhyung Kim static bool hist_browser__has_filter(struct hist_browser *hb) 57268397cbSNamhyung Kim { 585a1a99cdSJiri Olsa return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter; 59268397cbSNamhyung Kim } 60268397cbSNamhyung Kim 614fabf3d1SHe Kuang static int hist_browser__get_folding(struct hist_browser *browser) 624fabf3d1SHe Kuang { 634fabf3d1SHe Kuang struct rb_node *nd; 644fabf3d1SHe Kuang struct hists *hists = browser->hists; 654fabf3d1SHe Kuang int unfolded_rows = 0; 664fabf3d1SHe Kuang 672eb3d689SDavidlohr Bueso for (nd = rb_first_cached(&hists->entries); 684fabf3d1SHe Kuang (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 69f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd)) { 704fabf3d1SHe Kuang struct hist_entry *he = 714fabf3d1SHe Kuang rb_entry(nd, struct hist_entry, rb_node); 724fabf3d1SHe Kuang 73f5b763feSNamhyung Kim if (he->leaf && he->unfolded) 744fabf3d1SHe Kuang unfolded_rows += he->nr_rows; 754fabf3d1SHe Kuang } 764fabf3d1SHe Kuang return unfolded_rows; 774fabf3d1SHe Kuang } 784fabf3d1SHe Kuang 79ef9ff601SArnaldo Carvalho de Melo static void hist_browser__set_title_space(struct hist_browser *hb) 80ef9ff601SArnaldo Carvalho de Melo { 81ef9ff601SArnaldo Carvalho de Melo struct ui_browser *browser = &hb->b; 82ef9ff601SArnaldo Carvalho de Melo struct hists *hists = hb->hists; 83ef9ff601SArnaldo Carvalho de Melo struct perf_hpp_list *hpp_list = hists->hpp_list; 84ef9ff601SArnaldo Carvalho de Melo 85ef9ff601SArnaldo Carvalho de Melo browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0; 86ef9ff601SArnaldo Carvalho de Melo } 87ef9ff601SArnaldo Carvalho de Melo 88c3b78952SNamhyung Kim static u32 hist_browser__nr_entries(struct hist_browser *hb) 89c3b78952SNamhyung Kim { 90c3b78952SNamhyung Kim u32 nr_entries; 91c3b78952SNamhyung Kim 92f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 93f5b763feSNamhyung Kim nr_entries = hb->nr_hierarchy_entries; 94f5b763feSNamhyung Kim else if (hist_browser__has_filter(hb)) 95c3b78952SNamhyung Kim nr_entries = hb->nr_non_filtered_entries; 96c3b78952SNamhyung Kim else 97c3b78952SNamhyung Kim nr_entries = hb->hists->nr_entries; 98c3b78952SNamhyung Kim 994fabf3d1SHe Kuang hb->nr_callchain_rows = hist_browser__get_folding(hb); 100c3b78952SNamhyung Kim return nr_entries + hb->nr_callchain_rows; 101c3b78952SNamhyung Kim } 102c3b78952SNamhyung Kim 103025bf7eaSArnaldo Carvalho de Melo static void hist_browser__update_rows(struct hist_browser *hb) 104025bf7eaSArnaldo Carvalho de Melo { 105025bf7eaSArnaldo Carvalho de Melo struct ui_browser *browser = &hb->b; 106f8e6710dSJiri Olsa struct hists *hists = hb->hists; 107f8e6710dSJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 108ef9ff601SArnaldo Carvalho de Melo u16 index_row; 109025bf7eaSArnaldo Carvalho de Melo 110ef9ff601SArnaldo Carvalho de Melo if (!hb->show_headers) { 111ef9ff601SArnaldo Carvalho de Melo browser->rows += browser->extra_title_lines; 112ef9ff601SArnaldo Carvalho de Melo browser->extra_title_lines = 0; 113ef9ff601SArnaldo Carvalho de Melo return; 114ef9ff601SArnaldo Carvalho de Melo } 115ef9ff601SArnaldo Carvalho de Melo 116ef9ff601SArnaldo Carvalho de Melo browser->extra_title_lines = hpp_list->nr_header_lines; 117ef9ff601SArnaldo Carvalho de Melo browser->rows -= browser->extra_title_lines; 118025bf7eaSArnaldo Carvalho de Melo /* 119025bf7eaSArnaldo Carvalho de Melo * Verify if we were at the last line and that line isn't 120025bf7eaSArnaldo Carvalho de Melo * visibe because we now show the header line(s). 121025bf7eaSArnaldo Carvalho de Melo */ 122025bf7eaSArnaldo Carvalho de Melo index_row = browser->index - browser->top_idx; 123025bf7eaSArnaldo Carvalho de Melo if (index_row >= browser->rows) 124025bf7eaSArnaldo Carvalho de Melo browser->index -= index_row - browser->rows + 1; 125025bf7eaSArnaldo Carvalho de Melo } 126025bf7eaSArnaldo Carvalho de Melo 127357cfff1SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct ui_browser *browser) 128aca7a94dSNamhyung Kim { 129357cfff1SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 130357cfff1SArnaldo Carvalho de Melo 131aca7a94dSNamhyung Kim /* 3 == +/- toggle symbol before actual hist_entry rendering */ 132357cfff1SArnaldo Carvalho de Melo browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]")); 133357cfff1SArnaldo Carvalho de Melo /* 134357cfff1SArnaldo Carvalho de Melo * FIXME: Just keeping existing behaviour, but this really should be 135357cfff1SArnaldo Carvalho de Melo * before updating browser->width, as it will invalidate the 136357cfff1SArnaldo Carvalho de Melo * calculation above. Fix this and the fallout in another 137357cfff1SArnaldo Carvalho de Melo * changeset. 138357cfff1SArnaldo Carvalho de Melo */ 139357cfff1SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(browser); 140ca3ff33bSArnaldo Carvalho de Melo } 141ca3ff33bSArnaldo Carvalho de Melo 14205e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser) 143aca7a94dSNamhyung Kim { 144c3b78952SNamhyung Kim /* 145c3b78952SNamhyung Kim * The hists__remove_entry_filter() already folds non-filtered 146c3b78952SNamhyung Kim * entries so we can assume it has 0 callchain rows. 147c3b78952SNamhyung Kim */ 148c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 149c3b78952SNamhyung Kim 150268397cbSNamhyung Kim hist_browser__update_nr_entries(browser); 151c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 152357cfff1SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(&browser->b); 15305e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 154aca7a94dSNamhyung Kim } 155aca7a94dSNamhyung Kim 156aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded) 157aca7a94dSNamhyung Kim { 158aca7a94dSNamhyung Kim return unfolded ? '-' : '+'; 159aca7a94dSNamhyung Kim } 160aca7a94dSNamhyung Kim 16105e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he) 162aca7a94dSNamhyung Kim { 1633698dab1SNamhyung Kim return he->has_children ? tree__folded_sign(he->unfolded) : ' '; 164aca7a94dSNamhyung Kim } 165aca7a94dSNamhyung Kim 16605e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl) 167aca7a94dSNamhyung Kim { 1683698dab1SNamhyung Kim return cl->has_children ? tree__folded_sign(cl->unfolded) : ' '; 169aca7a94dSNamhyung Kim } 170aca7a94dSNamhyung Kim 1713698dab1SNamhyung Kim static void callchain_list__set_folding(struct callchain_list *cl, bool unfold) 172aca7a94dSNamhyung Kim { 1733698dab1SNamhyung Kim cl->unfolded = unfold ? cl->has_children : false; 174aca7a94dSNamhyung Kim } 175aca7a94dSNamhyung Kim 17605e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 177aca7a94dSNamhyung Kim { 1782a704fc8SMilian Wolff int n = 0; 179aca7a94dSNamhyung Kim struct rb_node *nd; 180aca7a94dSNamhyung Kim 18105e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 182aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 183aca7a94dSNamhyung Kim struct callchain_list *chain; 184aca7a94dSNamhyung Kim char folded_sign = ' '; /* No children */ 185aca7a94dSNamhyung Kim 186aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 187aca7a94dSNamhyung Kim ++n; 1880d3eb0b7SJin Yao 189aca7a94dSNamhyung Kim /* We need this because we may not have children */ 190aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 191aca7a94dSNamhyung Kim if (folded_sign == '+') 192aca7a94dSNamhyung Kim break; 193aca7a94dSNamhyung Kim } 194aca7a94dSNamhyung Kim 195aca7a94dSNamhyung Kim if (folded_sign == '-') /* Have children and they're unfolded */ 196aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(child); 197aca7a94dSNamhyung Kim } 198aca7a94dSNamhyung Kim 199aca7a94dSNamhyung Kim return n; 200aca7a94dSNamhyung Kim } 201aca7a94dSNamhyung Kim 2024b3a3212SNamhyung Kim static int callchain_node__count_flat_rows(struct callchain_node *node) 2034b3a3212SNamhyung Kim { 2044b3a3212SNamhyung Kim struct callchain_list *chain; 2054b3a3212SNamhyung Kim char folded_sign = 0; 2064b3a3212SNamhyung Kim int n = 0; 2074b3a3212SNamhyung Kim 2084b3a3212SNamhyung Kim list_for_each_entry(chain, &node->parent_val, list) { 2094b3a3212SNamhyung Kim if (!folded_sign) { 2104b3a3212SNamhyung Kim /* only check first chain list entry */ 2114b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 2124b3a3212SNamhyung Kim if (folded_sign == '+') 2134b3a3212SNamhyung Kim return 1; 2144b3a3212SNamhyung Kim } 2154b3a3212SNamhyung Kim n++; 2164b3a3212SNamhyung Kim } 2174b3a3212SNamhyung Kim 2184b3a3212SNamhyung Kim list_for_each_entry(chain, &node->val, list) { 2194b3a3212SNamhyung Kim if (!folded_sign) { 2204b3a3212SNamhyung Kim /* node->parent_val list might be empty */ 2214b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 2224b3a3212SNamhyung Kim if (folded_sign == '+') 2234b3a3212SNamhyung Kim return 1; 2244b3a3212SNamhyung Kim } 2254b3a3212SNamhyung Kim n++; 2264b3a3212SNamhyung Kim } 2274b3a3212SNamhyung Kim 2284b3a3212SNamhyung Kim return n; 2294b3a3212SNamhyung Kim } 2304b3a3212SNamhyung Kim 2318c430a34SNamhyung Kim static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused) 2328c430a34SNamhyung Kim { 2338c430a34SNamhyung Kim return 1; 2348c430a34SNamhyung Kim } 2358c430a34SNamhyung Kim 236aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 237aca7a94dSNamhyung Kim { 238aca7a94dSNamhyung Kim struct callchain_list *chain; 239aca7a94dSNamhyung Kim bool unfolded = false; 2402a704fc8SMilian Wolff int n = 0; 241aca7a94dSNamhyung Kim 2424b3a3212SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) 2434b3a3212SNamhyung Kim return callchain_node__count_flat_rows(node); 2448c430a34SNamhyung Kim else if (callchain_param.mode == CHAIN_FOLDED) 2458c430a34SNamhyung Kim return callchain_node__count_folded_rows(node); 2464b3a3212SNamhyung Kim 247aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 248aca7a94dSNamhyung Kim ++n; 2490d3eb0b7SJin Yao 2503698dab1SNamhyung Kim unfolded = chain->unfolded; 251aca7a94dSNamhyung Kim } 252aca7a94dSNamhyung Kim 253aca7a94dSNamhyung Kim if (unfolded) 254aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 255aca7a94dSNamhyung Kim 256aca7a94dSNamhyung Kim return n; 257aca7a94dSNamhyung Kim } 258aca7a94dSNamhyung Kim 259aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 260aca7a94dSNamhyung Kim { 261aca7a94dSNamhyung Kim struct rb_node *nd; 262aca7a94dSNamhyung Kim int n = 0; 263aca7a94dSNamhyung Kim 264aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 265aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 266aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 267aca7a94dSNamhyung Kim } 268aca7a94dSNamhyung Kim 269aca7a94dSNamhyung Kim return n; 270aca7a94dSNamhyung Kim } 271aca7a94dSNamhyung Kim 272f5b763feSNamhyung Kim static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he, 273f5b763feSNamhyung Kim bool include_children) 274f5b763feSNamhyung Kim { 275f5b763feSNamhyung Kim int count = 0; 276f5b763feSNamhyung Kim struct rb_node *node; 277f5b763feSNamhyung Kim struct hist_entry *child; 278f5b763feSNamhyung Kim 279f5b763feSNamhyung Kim if (he->leaf) 280f5b763feSNamhyung Kim return callchain__count_rows(&he->sorted_chain); 281f5b763feSNamhyung Kim 28279dded87SNamhyung Kim if (he->has_no_entry) 28379dded87SNamhyung Kim return 1; 28479dded87SNamhyung Kim 2852eb3d689SDavidlohr Bueso node = rb_first_cached(&he->hroot_out); 286f5b763feSNamhyung Kim while (node) { 287f5b763feSNamhyung Kim float percent; 288f5b763feSNamhyung Kim 289f5b763feSNamhyung Kim child = rb_entry(node, struct hist_entry, rb_node); 290f5b763feSNamhyung Kim percent = hist_entry__get_percent_limit(child); 291f5b763feSNamhyung Kim 292f5b763feSNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) { 293f5b763feSNamhyung Kim count++; 294f5b763feSNamhyung Kim 295f5b763feSNamhyung Kim if (include_children && child->unfolded) 296f5b763feSNamhyung Kim count += hierarchy_count_rows(hb, child, true); 297f5b763feSNamhyung Kim } 298f5b763feSNamhyung Kim 299f5b763feSNamhyung Kim node = rb_next(node); 300f5b763feSNamhyung Kim } 301f5b763feSNamhyung Kim return count; 302f5b763feSNamhyung Kim } 303f5b763feSNamhyung Kim 3043698dab1SNamhyung Kim static bool hist_entry__toggle_fold(struct hist_entry *he) 305aca7a94dSNamhyung Kim { 3063698dab1SNamhyung Kim if (!he) 307aca7a94dSNamhyung Kim return false; 308aca7a94dSNamhyung Kim 3093698dab1SNamhyung Kim if (!he->has_children) 310aca7a94dSNamhyung Kim return false; 311aca7a94dSNamhyung Kim 3123698dab1SNamhyung Kim he->unfolded = !he->unfolded; 3133698dab1SNamhyung Kim return true; 3143698dab1SNamhyung Kim } 3153698dab1SNamhyung Kim 3163698dab1SNamhyung Kim static bool callchain_list__toggle_fold(struct callchain_list *cl) 3173698dab1SNamhyung Kim { 3183698dab1SNamhyung Kim if (!cl) 3193698dab1SNamhyung Kim return false; 3203698dab1SNamhyung Kim 3213698dab1SNamhyung Kim if (!cl->has_children) 3223698dab1SNamhyung Kim return false; 3233698dab1SNamhyung Kim 3243698dab1SNamhyung Kim cl->unfolded = !cl->unfolded; 325aca7a94dSNamhyung Kim return true; 326aca7a94dSNamhyung Kim } 327aca7a94dSNamhyung Kim 32805e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 329aca7a94dSNamhyung Kim { 33005e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 331aca7a94dSNamhyung Kim 33205e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 333aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 334aca7a94dSNamhyung Kim struct callchain_list *chain; 335aca7a94dSNamhyung Kim bool first = true; 336aca7a94dSNamhyung Kim 337aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 338aca7a94dSNamhyung Kim if (first) { 339aca7a94dSNamhyung Kim first = false; 3403698dab1SNamhyung Kim chain->has_children = chain->list.next != &child->val || 341aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 342aca7a94dSNamhyung Kim } else 3433698dab1SNamhyung Kim chain->has_children = chain->list.next == &child->val && 344aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 345aca7a94dSNamhyung Kim } 346aca7a94dSNamhyung Kim 347aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 348aca7a94dSNamhyung Kim } 349aca7a94dSNamhyung Kim } 350aca7a94dSNamhyung Kim 351a7444af6SNamhyung Kim static void callchain_node__init_have_children(struct callchain_node *node, 352a7444af6SNamhyung Kim bool has_sibling) 353aca7a94dSNamhyung Kim { 354aca7a94dSNamhyung Kim struct callchain_list *chain; 355aca7a94dSNamhyung Kim 356a7444af6SNamhyung Kim chain = list_entry(node->val.next, struct callchain_list, list); 3573698dab1SNamhyung Kim chain->has_children = has_sibling; 358a7444af6SNamhyung Kim 35990989035SAndres Freund if (!list_empty(&node->val)) { 36082162b5aSNamhyung Kim chain = list_entry(node->val.prev, struct callchain_list, list); 3613698dab1SNamhyung Kim chain->has_children = !RB_EMPTY_ROOT(&node->rb_root); 36282162b5aSNamhyung Kim } 363aca7a94dSNamhyung Kim 36405e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 365aca7a94dSNamhyung Kim } 366aca7a94dSNamhyung Kim 36705e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 368aca7a94dSNamhyung Kim { 369a7444af6SNamhyung Kim struct rb_node *nd = rb_first(root); 370a7444af6SNamhyung Kim bool has_sibling = nd && rb_next(nd); 371aca7a94dSNamhyung Kim 37205e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 373aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 374a7444af6SNamhyung Kim callchain_node__init_have_children(node, has_sibling); 3758c430a34SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT || 3768c430a34SNamhyung Kim callchain_param.mode == CHAIN_FOLDED) 3774b3a3212SNamhyung Kim callchain_node__make_parent_list(node); 378aca7a94dSNamhyung Kim } 379aca7a94dSNamhyung Kim } 380aca7a94dSNamhyung Kim 38105e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 382aca7a94dSNamhyung Kim { 383f5b763feSNamhyung Kim if (he->init_have_children) 384f5b763feSNamhyung Kim return; 385f5b763feSNamhyung Kim 386f5b763feSNamhyung Kim if (he->leaf) { 3873698dab1SNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 38805e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 389f5b763feSNamhyung Kim } else { 3902eb3d689SDavidlohr Bueso he->has_children = !RB_EMPTY_ROOT(&he->hroot_out.rb_root); 391aca7a94dSNamhyung Kim } 392f5b763feSNamhyung Kim 393f5b763feSNamhyung Kim he->init_have_children = true; 394aca7a94dSNamhyung Kim } 395aca7a94dSNamhyung Kim 396bdc633feSArnaldo Carvalho de Melo static bool hist_browser__selection_has_children(struct hist_browser *browser) 397bdc633feSArnaldo Carvalho de Melo { 398bdc633feSArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 399bdc633feSArnaldo Carvalho de Melo struct map_symbol *ms = browser->selection; 400bdc633feSArnaldo Carvalho de Melo 401bdc633feSArnaldo Carvalho de Melo if (!he || !ms) 402bdc633feSArnaldo Carvalho de Melo return false; 403bdc633feSArnaldo Carvalho de Melo 404bdc633feSArnaldo Carvalho de Melo if (ms == &he->ms) 405bdc633feSArnaldo Carvalho de Melo return he->has_children; 406bdc633feSArnaldo Carvalho de Melo 407bdc633feSArnaldo Carvalho de Melo return container_of(ms, struct callchain_list, ms)->has_children; 408bdc633feSArnaldo Carvalho de Melo } 409bdc633feSArnaldo Carvalho de Melo 410e6d6abfcSArnaldo Carvalho de Melo static bool hist_browser__he_selection_unfolded(struct hist_browser *browser) 411e6d6abfcSArnaldo Carvalho de Melo { 412e6d6abfcSArnaldo Carvalho de Melo return browser->he_selection ? browser->he_selection->unfolded : false; 413e6d6abfcSArnaldo Carvalho de Melo } 414e6d6abfcSArnaldo Carvalho de Melo 415bdc633feSArnaldo Carvalho de Melo static bool hist_browser__selection_unfolded(struct hist_browser *browser) 416bdc633feSArnaldo Carvalho de Melo { 417bdc633feSArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 418bdc633feSArnaldo Carvalho de Melo struct map_symbol *ms = browser->selection; 419bdc633feSArnaldo Carvalho de Melo 420bdc633feSArnaldo Carvalho de Melo if (!he || !ms) 421bdc633feSArnaldo Carvalho de Melo return false; 422bdc633feSArnaldo Carvalho de Melo 423bdc633feSArnaldo Carvalho de Melo if (ms == &he->ms) 424bdc633feSArnaldo Carvalho de Melo return he->unfolded; 425bdc633feSArnaldo Carvalho de Melo 426bdc633feSArnaldo Carvalho de Melo return container_of(ms, struct callchain_list, ms)->unfolded; 427bdc633feSArnaldo Carvalho de Melo } 428bdc633feSArnaldo Carvalho de Melo 429bdc633feSArnaldo Carvalho de Melo static char *hist_browser__selection_sym_name(struct hist_browser *browser, char *bf, size_t size) 430bdc633feSArnaldo Carvalho de Melo { 431bdc633feSArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 432bdc633feSArnaldo Carvalho de Melo struct map_symbol *ms = browser->selection; 433bdc633feSArnaldo Carvalho de Melo struct callchain_list *callchain_entry; 434bdc633feSArnaldo Carvalho de Melo 435bdc633feSArnaldo Carvalho de Melo if (!he || !ms) 436bdc633feSArnaldo Carvalho de Melo return NULL; 437bdc633feSArnaldo Carvalho de Melo 438bdc633feSArnaldo Carvalho de Melo if (ms == &he->ms) { 439bdc633feSArnaldo Carvalho de Melo hist_entry__sym_snprintf(he, bf, size, 0); 440bdc633feSArnaldo Carvalho de Melo return bf + 4; // skip the level, e.g. '[k] ' 441bdc633feSArnaldo Carvalho de Melo } 442bdc633feSArnaldo Carvalho de Melo 443bdc633feSArnaldo Carvalho de Melo callchain_entry = container_of(ms, struct callchain_list, ms); 444bdc633feSArnaldo Carvalho de Melo return callchain_list__sym_name(callchain_entry, bf, size, browser->show_dso); 445bdc633feSArnaldo Carvalho de Melo } 446bdc633feSArnaldo Carvalho de Melo 44705e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 448aca7a94dSNamhyung Kim { 44905e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 4503698dab1SNamhyung Kim struct map_symbol *ms = browser->selection; 4513698dab1SNamhyung Kim struct callchain_list *cl = container_of(ms, struct callchain_list, ms); 4523698dab1SNamhyung Kim bool has_children; 453aca7a94dSNamhyung Kim 4544938cf0cSWang Nan if (!he || !ms) 4554938cf0cSWang Nan return false; 4564938cf0cSWang Nan 4573698dab1SNamhyung Kim if (ms == &he->ms) 4583698dab1SNamhyung Kim has_children = hist_entry__toggle_fold(he); 4593698dab1SNamhyung Kim else 4603698dab1SNamhyung Kim has_children = callchain_list__toggle_fold(cl); 4613698dab1SNamhyung Kim 4623698dab1SNamhyung Kim if (has_children) { 463f5b763feSNamhyung Kim int child_rows = 0; 464f5b763feSNamhyung Kim 465aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 466c3b78952SNamhyung Kim browser->b.nr_entries -= he->nr_rows; 467aca7a94dSNamhyung Kim 468f5b763feSNamhyung Kim if (he->leaf) 469f5b763feSNamhyung Kim browser->nr_callchain_rows -= he->nr_rows; 470f5b763feSNamhyung Kim else 471f5b763feSNamhyung Kim browser->nr_hierarchy_entries -= he->nr_rows; 472f5b763feSNamhyung Kim 473f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 474f5b763feSNamhyung Kim child_rows = hierarchy_count_rows(browser, he, true); 475f5b763feSNamhyung Kim 476f5b763feSNamhyung Kim if (he->unfolded) { 477f5b763feSNamhyung Kim if (he->leaf) 4780d3eb0b7SJin Yao he->nr_rows = callchain__count_rows( 4790d3eb0b7SJin Yao &he->sorted_chain); 480aca7a94dSNamhyung Kim else 481f5b763feSNamhyung Kim he->nr_rows = hierarchy_count_rows(browser, he, false); 482f5b763feSNamhyung Kim 483f5b763feSNamhyung Kim /* account grand children */ 484f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 485f5b763feSNamhyung Kim browser->b.nr_entries += child_rows - he->nr_rows; 48679dded87SNamhyung Kim 48779dded87SNamhyung Kim if (!he->leaf && he->nr_rows == 0) { 48879dded87SNamhyung Kim he->has_no_entry = true; 48979dded87SNamhyung Kim he->nr_rows = 1; 49079dded87SNamhyung Kim } 491f5b763feSNamhyung Kim } else { 492f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 493f5b763feSNamhyung Kim browser->b.nr_entries -= child_rows - he->nr_rows; 494f5b763feSNamhyung Kim 49579dded87SNamhyung Kim if (he->has_no_entry) 49679dded87SNamhyung Kim he->has_no_entry = false; 49779dded87SNamhyung Kim 498aca7a94dSNamhyung Kim he->nr_rows = 0; 499f5b763feSNamhyung Kim } 500c3b78952SNamhyung Kim 501c3b78952SNamhyung Kim browser->b.nr_entries += he->nr_rows; 502f5b763feSNamhyung Kim 503f5b763feSNamhyung Kim if (he->leaf) 504c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 505f5b763feSNamhyung Kim else 506f5b763feSNamhyung Kim browser->nr_hierarchy_entries += he->nr_rows; 507aca7a94dSNamhyung Kim 508aca7a94dSNamhyung Kim return true; 509aca7a94dSNamhyung Kim } 510aca7a94dSNamhyung Kim 511aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 512aca7a94dSNamhyung Kim return false; 513aca7a94dSNamhyung Kim } 514aca7a94dSNamhyung Kim 51505e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 516aca7a94dSNamhyung Kim { 517aca7a94dSNamhyung Kim int n = 0; 518aca7a94dSNamhyung Kim struct rb_node *nd; 519aca7a94dSNamhyung Kim 52005e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 521aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 522aca7a94dSNamhyung Kim struct callchain_list *chain; 523aca7a94dSNamhyung Kim bool has_children = false; 524aca7a94dSNamhyung Kim 525aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 526aca7a94dSNamhyung Kim ++n; 5273698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 5283698dab1SNamhyung Kim has_children = chain->has_children; 529aca7a94dSNamhyung Kim } 530aca7a94dSNamhyung Kim 531aca7a94dSNamhyung Kim if (has_children) 532aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 533aca7a94dSNamhyung Kim } 534aca7a94dSNamhyung Kim 535aca7a94dSNamhyung Kim return n; 536aca7a94dSNamhyung Kim } 537aca7a94dSNamhyung Kim 538aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 539aca7a94dSNamhyung Kim { 540aca7a94dSNamhyung Kim struct callchain_list *chain; 541aca7a94dSNamhyung Kim bool has_children = false; 542aca7a94dSNamhyung Kim int n = 0; 543aca7a94dSNamhyung Kim 544aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 545aca7a94dSNamhyung Kim ++n; 5463698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 5473698dab1SNamhyung Kim has_children = chain->has_children; 548aca7a94dSNamhyung Kim } 549aca7a94dSNamhyung Kim 550aca7a94dSNamhyung Kim if (has_children) 551aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 552aca7a94dSNamhyung Kim 553aca7a94dSNamhyung Kim return n; 554aca7a94dSNamhyung Kim } 555aca7a94dSNamhyung Kim 556aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 557aca7a94dSNamhyung Kim { 558aca7a94dSNamhyung Kim struct rb_node *nd; 559aca7a94dSNamhyung Kim int n = 0; 560aca7a94dSNamhyung Kim 561aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 562aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 563aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 564aca7a94dSNamhyung Kim } 565aca7a94dSNamhyung Kim 566aca7a94dSNamhyung Kim return n; 567aca7a94dSNamhyung Kim } 568aca7a94dSNamhyung Kim 569492b1010SNamhyung Kim static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he, 570492b1010SNamhyung Kim bool unfold __maybe_unused) 571492b1010SNamhyung Kim { 572492b1010SNamhyung Kim float percent; 573492b1010SNamhyung Kim struct rb_node *nd; 574492b1010SNamhyung Kim struct hist_entry *child; 575492b1010SNamhyung Kim int n = 0; 576492b1010SNamhyung Kim 5772eb3d689SDavidlohr Bueso for (nd = rb_first_cached(&he->hroot_out); nd; nd = rb_next(nd)) { 578492b1010SNamhyung Kim child = rb_entry(nd, struct hist_entry, rb_node); 579492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(child); 580492b1010SNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) 581492b1010SNamhyung Kim n++; 582492b1010SNamhyung Kim } 583492b1010SNamhyung Kim 584492b1010SNamhyung Kim return n; 585492b1010SNamhyung Kim } 586492b1010SNamhyung Kim 587b33f9226SJiri Olsa static void __hist_entry__set_folding(struct hist_entry *he, 588492b1010SNamhyung Kim struct hist_browser *hb, bool unfold) 589aca7a94dSNamhyung Kim { 59005e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 5913698dab1SNamhyung Kim he->unfolded = unfold ? he->has_children : false; 592aca7a94dSNamhyung Kim 5933698dab1SNamhyung Kim if (he->has_children) { 594492b1010SNamhyung Kim int n; 595492b1010SNamhyung Kim 596492b1010SNamhyung Kim if (he->leaf) 597492b1010SNamhyung Kim n = callchain__set_folding(&he->sorted_chain, unfold); 598492b1010SNamhyung Kim else 599492b1010SNamhyung Kim n = hierarchy_set_folding(hb, he, unfold); 600492b1010SNamhyung Kim 60105e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 602aca7a94dSNamhyung Kim } else 60305e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 604aca7a94dSNamhyung Kim } 605aca7a94dSNamhyung Kim 606b33f9226SJiri Olsa static void hist_entry__set_folding(struct hist_entry *he, 607b33f9226SJiri Olsa struct hist_browser *browser, bool unfold) 608aca7a94dSNamhyung Kim { 609492b1010SNamhyung Kim double percent; 610aca7a94dSNamhyung Kim 611492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(he); 612492b1010SNamhyung Kim if (he->filtered || percent < browser->min_pcnt) 613b33f9226SJiri Olsa return; 614b33f9226SJiri Olsa 615b33f9226SJiri Olsa __hist_entry__set_folding(he, browser, unfold); 616492b1010SNamhyung Kim 617492b1010SNamhyung Kim if (!he->depth || unfold) 618492b1010SNamhyung Kim browser->nr_hierarchy_entries++; 619492b1010SNamhyung Kim if (he->leaf) 620c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 62179dded87SNamhyung Kim else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) { 62279dded87SNamhyung Kim browser->nr_hierarchy_entries++; 62379dded87SNamhyung Kim he->has_no_entry = true; 62479dded87SNamhyung Kim he->nr_rows = 1; 62579dded87SNamhyung Kim } else 62679dded87SNamhyung Kim he->has_no_entry = false; 627aca7a94dSNamhyung Kim } 628b33f9226SJiri Olsa 629b33f9226SJiri Olsa static void 630b33f9226SJiri Olsa __hist_browser__set_folding(struct hist_browser *browser, bool unfold) 631b33f9226SJiri Olsa { 632b33f9226SJiri Olsa struct rb_node *nd; 633b33f9226SJiri Olsa struct hist_entry *he; 634b33f9226SJiri Olsa 6352eb3d689SDavidlohr Bueso nd = rb_first_cached(&browser->hists->entries); 636b33f9226SJiri Olsa while (nd) { 637b33f9226SJiri Olsa he = rb_entry(nd, struct hist_entry, rb_node); 638b33f9226SJiri Olsa 639b33f9226SJiri Olsa /* set folding state even if it's currently folded */ 640b33f9226SJiri Olsa nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 641b33f9226SJiri Olsa 642b33f9226SJiri Olsa hist_entry__set_folding(he, browser, unfold); 643b33f9226SJiri Olsa } 644aca7a94dSNamhyung Kim } 645aca7a94dSNamhyung Kim 64605e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 647aca7a94dSNamhyung Kim { 648492b1010SNamhyung Kim browser->nr_hierarchy_entries = 0; 649c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 650c3b78952SNamhyung Kim __hist_browser__set_folding(browser, unfold); 651c3b78952SNamhyung Kim 652c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 653aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 65405e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 655aca7a94dSNamhyung Kim } 656aca7a94dSNamhyung Kim 6570e3fa7a7SJiri Olsa static void hist_browser__set_folding_selected(struct hist_browser *browser, bool unfold) 6580e3fa7a7SJiri Olsa { 6590e3fa7a7SJiri Olsa if (!browser->he_selection) 6600e3fa7a7SJiri Olsa return; 6610e3fa7a7SJiri Olsa 6620e3fa7a7SJiri Olsa hist_entry__set_folding(browser->he_selection, browser, unfold); 6630e3fa7a7SJiri Olsa browser->b.nr_entries = hist_browser__nr_entries(browser); 6640e3fa7a7SJiri Olsa } 6650e3fa7a7SJiri Olsa 666aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 667aca7a94dSNamhyung Kim { 668aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 669aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 670aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 671aca7a94dSNamhyung Kim " perf top -r 80\n\n" 672aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 673aca7a94dSNamhyung Kim } 674aca7a94dSNamhyung Kim 6755b91a86fSJiri Olsa static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size) 6765b91a86fSJiri Olsa { 6775b91a86fSJiri Olsa return browser->title ? browser->title(browser, bf, size) : 0; 6785b91a86fSJiri Olsa } 6795b91a86fSJiri Olsa 680376c3c22SArnaldo Carvalho de Melo static int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_lost_event, char *title, size_t size, int key) 681aca7a94dSNamhyung Kim { 682aca7a94dSNamhyung Kim switch (key) { 683fa5df943SNamhyung Kim case K_TIMER: { 684d10ec006SArnaldo Carvalho de Melo struct hist_browser_timer *hbt = browser->hbt; 685fa5df943SNamhyung Kim u64 nr_entries; 686ceb75476SLeo Yan 687ceb75476SLeo Yan WARN_ON_ONCE(!hbt); 688ceb75476SLeo Yan 689ceb75476SLeo Yan if (hbt) 6909783adf7SNamhyung Kim hbt->timer(hbt->arg); 691fa5df943SNamhyung Kim 692d10ec006SArnaldo Carvalho de Melo if (hist_browser__has_filter(browser) || symbol_conf.report_hierarchy) 693112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 694fa5df943SNamhyung Kim 695c3b78952SNamhyung Kim nr_entries = hist_browser__nr_entries(browser); 696fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 697aca7a94dSNamhyung Kim 69806cc1a47SKan Liang if (warn_lost_event && 69906cc1a47SKan Liang (browser->hists->stats.nr_lost_warned != 70006cc1a47SKan Liang browser->hists->stats.nr_events[PERF_RECORD_LOST])) { 70105e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 70205e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 70305e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 704aca7a94dSNamhyung Kim } 705aca7a94dSNamhyung Kim 706376c3c22SArnaldo Carvalho de Melo hist_browser__title(browser, title, size); 70705e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 708d10ec006SArnaldo Carvalho de Melo break; 709fa5df943SNamhyung Kim } 710aca7a94dSNamhyung Kim case 'D': { /* Debug */ 711d10ec006SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, struct hist_entry, rb_node); 712aca7a94dSNamhyung Kim static int seq; 713d10ec006SArnaldo Carvalho de Melo 714aca7a94dSNamhyung Kim ui_helpline__pop(); 715fdae6400SArnaldo 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", 716d10ec006SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, browser->hists->nr_entries, 717d10ec006SArnaldo Carvalho de Melo browser->b.extra_title_lines, browser->b.rows, 718d10ec006SArnaldo Carvalho de Melo browser->b.index, browser->b.top_idx, h->row_offset, h->nr_rows); 719aca7a94dSNamhyung Kim } 720aca7a94dSNamhyung Kim break; 721aca7a94dSNamhyung Kim case 'C': 722aca7a94dSNamhyung Kim /* Collapse the whole world. */ 72305e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 724aca7a94dSNamhyung Kim break; 7250e3fa7a7SJiri Olsa case 'c': 7260e3fa7a7SJiri Olsa /* Collapse the selected entry. */ 7270e3fa7a7SJiri Olsa hist_browser__set_folding_selected(browser, false); 7280e3fa7a7SJiri Olsa break; 729aca7a94dSNamhyung Kim case 'E': 730aca7a94dSNamhyung Kim /* Expand the whole world. */ 73105e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 732aca7a94dSNamhyung Kim break; 7330e3fa7a7SJiri Olsa case 'e': 7340e3fa7a7SJiri Olsa /* Expand the selected entry. */ 735e6d6abfcSArnaldo Carvalho de Melo hist_browser__set_folding_selected(browser, !hist_browser__he_selection_unfolded(browser)); 7360e3fa7a7SJiri Olsa break; 737025bf7eaSArnaldo Carvalho de Melo case 'H': 738025bf7eaSArnaldo Carvalho de Melo browser->show_headers = !browser->show_headers; 739025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(browser); 740025bf7eaSArnaldo Carvalho de Melo break; 7419218a913SArnaldo Carvalho de Melo case '+': 74205e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 743aca7a94dSNamhyung Kim break; 744aca7a94dSNamhyung Kim /* fall thru */ 745aca7a94dSNamhyung Kim default: 746d10ec006SArnaldo Carvalho de Melo return -1; 747aca7a94dSNamhyung Kim } 748d10ec006SArnaldo Carvalho de Melo 749d10ec006SArnaldo Carvalho de Melo return 0; 750d10ec006SArnaldo Carvalho de Melo } 751d10ec006SArnaldo Carvalho de Melo 752d10ec006SArnaldo Carvalho de Melo int hist_browser__run(struct hist_browser *browser, const char *help, 753d10ec006SArnaldo Carvalho de Melo bool warn_lost_event, int key) 754d10ec006SArnaldo Carvalho de Melo { 755d10ec006SArnaldo Carvalho de Melo char title[160]; 756d10ec006SArnaldo Carvalho de Melo struct hist_browser_timer *hbt = browser->hbt; 757d10ec006SArnaldo Carvalho de Melo int delay_secs = hbt ? hbt->refresh : 0; 758d10ec006SArnaldo Carvalho de Melo 759d10ec006SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 760d10ec006SArnaldo Carvalho de Melo browser->b.nr_entries = hist_browser__nr_entries(browser); 761d10ec006SArnaldo Carvalho de Melo 762d10ec006SArnaldo Carvalho de Melo hist_browser__title(browser, title, sizeof(title)); 763d10ec006SArnaldo Carvalho de Melo 764d10ec006SArnaldo Carvalho de Melo if (ui_browser__show(&browser->b, title, "%s", help) < 0) 765d10ec006SArnaldo Carvalho de Melo return -1; 766d10ec006SArnaldo Carvalho de Melo 767376c3c22SArnaldo Carvalho de Melo if (key && hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key)) 768d10ec006SArnaldo Carvalho de Melo goto out; 769d10ec006SArnaldo Carvalho de Melo 770d10ec006SArnaldo Carvalho de Melo while (1) { 771d10ec006SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 772d10ec006SArnaldo Carvalho de Melo 773376c3c22SArnaldo Carvalho de Melo if (hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key)) 774d10ec006SArnaldo Carvalho de Melo break; 775aca7a94dSNamhyung Kim } 776aca7a94dSNamhyung Kim out: 77705e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 778aca7a94dSNamhyung Kim return key; 779aca7a94dSNamhyung Kim } 780aca7a94dSNamhyung Kim 78139ee533fSNamhyung Kim struct callchain_print_arg { 78239ee533fSNamhyung Kim /* for hists browser */ 78339ee533fSNamhyung Kim off_t row_offset; 78439ee533fSNamhyung Kim bool is_current_entry; 78539ee533fSNamhyung Kim 78639ee533fSNamhyung Kim /* for file dump */ 78739ee533fSNamhyung Kim FILE *fp; 78839ee533fSNamhyung Kim int printed; 78939ee533fSNamhyung Kim }; 79039ee533fSNamhyung Kim 79139ee533fSNamhyung Kim typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, 79239ee533fSNamhyung Kim struct callchain_list *chain, 79339ee533fSNamhyung Kim const char *str, int offset, 79439ee533fSNamhyung Kim unsigned short row, 79539ee533fSNamhyung Kim struct callchain_print_arg *arg); 79639ee533fSNamhyung Kim 797f4536dddSNamhyung Kim static void hist_browser__show_callchain_entry(struct hist_browser *browser, 798f4536dddSNamhyung Kim struct callchain_list *chain, 79939ee533fSNamhyung Kim const char *str, int offset, 80039ee533fSNamhyung Kim unsigned short row, 80139ee533fSNamhyung Kim struct callchain_print_arg *arg) 802f4536dddSNamhyung Kim { 803f4536dddSNamhyung Kim int color, width; 80439ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 80570e97278SArnaldo Carvalho de Melo bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src; 806f4536dddSNamhyung Kim 807f4536dddSNamhyung Kim color = HE_COLORSET_NORMAL; 808f4536dddSNamhyung Kim width = browser->b.width - (offset + 2); 809f4536dddSNamhyung Kim if (ui_browser__is_current_entry(&browser->b, row)) { 810f4536dddSNamhyung Kim browser->selection = &chain->ms; 811f4536dddSNamhyung Kim color = HE_COLORSET_SELECTED; 81239ee533fSNamhyung Kim arg->is_current_entry = true; 813f4536dddSNamhyung Kim } 814f4536dddSNamhyung Kim 815f4536dddSNamhyung Kim ui_browser__set_color(&browser->b, color); 816ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 81726270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, " ", offset); 818517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c", folded_sign); 81970e97278SArnaldo Carvalho de Melo ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); 82026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, str, width); 821f4536dddSNamhyung Kim } 822f4536dddSNamhyung Kim 82339ee533fSNamhyung Kim static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, 82439ee533fSNamhyung Kim struct callchain_list *chain, 82539ee533fSNamhyung Kim const char *str, int offset, 82639ee533fSNamhyung Kim unsigned short row __maybe_unused, 82739ee533fSNamhyung Kim struct callchain_print_arg *arg) 82839ee533fSNamhyung Kim { 82939ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 83039ee533fSNamhyung Kim 83139ee533fSNamhyung Kim arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", 83239ee533fSNamhyung Kim folded_sign, str); 83339ee533fSNamhyung Kim } 83439ee533fSNamhyung Kim 83539ee533fSNamhyung Kim typedef bool (*check_output_full_fn)(struct hist_browser *browser, 83639ee533fSNamhyung Kim unsigned short row); 83739ee533fSNamhyung Kim 83839ee533fSNamhyung Kim static bool hist_browser__check_output_full(struct hist_browser *browser, 83939ee533fSNamhyung Kim unsigned short row) 84039ee533fSNamhyung Kim { 84139ee533fSNamhyung Kim return browser->b.rows == row; 84239ee533fSNamhyung Kim } 84339ee533fSNamhyung Kim 84439ee533fSNamhyung Kim static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, 84539ee533fSNamhyung Kim unsigned short row __maybe_unused) 84639ee533fSNamhyung Kim { 84739ee533fSNamhyung Kim return false; 84839ee533fSNamhyung Kim } 84939ee533fSNamhyung Kim 850aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 851aca7a94dSNamhyung Kim 85218bb8381SNamhyung Kim static int hist_browser__show_callchain_list(struct hist_browser *browser, 85318bb8381SNamhyung Kim struct callchain_node *node, 85418bb8381SNamhyung Kim struct callchain_list *chain, 85518bb8381SNamhyung Kim unsigned short row, u64 total, 85618bb8381SNamhyung Kim bool need_percent, int offset, 85718bb8381SNamhyung Kim print_callchain_entry_fn print, 85818bb8381SNamhyung Kim struct callchain_print_arg *arg) 85918bb8381SNamhyung Kim { 86018bb8381SNamhyung Kim char bf[1024], *alloc_str; 861fef51ecdSJin Yao char buf[64], *alloc_str2; 86218bb8381SNamhyung Kim const char *str; 8632a704fc8SMilian Wolff int ret = 1; 86418bb8381SNamhyung Kim 86518bb8381SNamhyung Kim if (arg->row_offset != 0) { 86618bb8381SNamhyung Kim arg->row_offset--; 86718bb8381SNamhyung Kim return 0; 86818bb8381SNamhyung Kim } 86918bb8381SNamhyung Kim 87018bb8381SNamhyung Kim alloc_str = NULL; 871fef51ecdSJin Yao alloc_str2 = NULL; 872fef51ecdSJin Yao 87318bb8381SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 87418bb8381SNamhyung Kim browser->show_dso); 87518bb8381SNamhyung Kim 876fef51ecdSJin Yao if (symbol_conf.show_branchflag_count) { 877c4ee0625SJin Yao callchain_list_counts__printf_value(chain, NULL, 878fef51ecdSJin Yao buf, sizeof(buf)); 87918bb8381SNamhyung Kim 880fef51ecdSJin Yao if (asprintf(&alloc_str2, "%s%s", str, buf) < 0) 881fef51ecdSJin Yao str = "Not enough memory!"; 882fef51ecdSJin Yao else 883fef51ecdSJin Yao str = alloc_str2; 884fef51ecdSJin Yao } 885fef51ecdSJin Yao 886fef51ecdSJin Yao if (need_percent) { 88718bb8381SNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), 88818bb8381SNamhyung Kim total); 88918bb8381SNamhyung Kim 89018bb8381SNamhyung Kim if (asprintf(&alloc_str, "%s %s", buf, str) < 0) 89118bb8381SNamhyung Kim str = "Not enough memory!"; 89218bb8381SNamhyung Kim else 89318bb8381SNamhyung Kim str = alloc_str; 89418bb8381SNamhyung Kim } 89518bb8381SNamhyung Kim 89618bb8381SNamhyung Kim print(browser, chain, str, offset, row, arg); 89718bb8381SNamhyung Kim free(alloc_str); 898fef51ecdSJin Yao free(alloc_str2); 8990d3eb0b7SJin Yao 9002a704fc8SMilian Wolff return ret; 90118bb8381SNamhyung Kim } 90218bb8381SNamhyung Kim 90359c624e2SNamhyung Kim static bool check_percent_display(struct rb_node *node, u64 parent_total) 90459c624e2SNamhyung Kim { 90559c624e2SNamhyung Kim struct callchain_node *child; 90659c624e2SNamhyung Kim 90759c624e2SNamhyung Kim if (node == NULL) 90859c624e2SNamhyung Kim return false; 90959c624e2SNamhyung Kim 91059c624e2SNamhyung Kim if (rb_next(node)) 91159c624e2SNamhyung Kim return true; 91259c624e2SNamhyung Kim 91359c624e2SNamhyung Kim child = rb_entry(node, struct callchain_node, rb_node); 91459c624e2SNamhyung Kim return callchain_cumul_hits(child) != parent_total; 91559c624e2SNamhyung Kim } 91659c624e2SNamhyung Kim 9174b3a3212SNamhyung Kim static int hist_browser__show_callchain_flat(struct hist_browser *browser, 9184b3a3212SNamhyung Kim struct rb_root *root, 9194b3a3212SNamhyung Kim unsigned short row, u64 total, 92059c624e2SNamhyung Kim u64 parent_total, 9214b3a3212SNamhyung Kim print_callchain_entry_fn print, 9224b3a3212SNamhyung Kim struct callchain_print_arg *arg, 9234b3a3212SNamhyung Kim check_output_full_fn is_output_full) 9244b3a3212SNamhyung Kim { 9254b3a3212SNamhyung Kim struct rb_node *node; 9264b3a3212SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 9274b3a3212SNamhyung Kim bool need_percent; 9284b3a3212SNamhyung Kim 9294b3a3212SNamhyung Kim node = rb_first(root); 93059c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 9314b3a3212SNamhyung Kim 9324b3a3212SNamhyung Kim while (node) { 9334b3a3212SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 9344b3a3212SNamhyung Kim struct rb_node *next = rb_next(node); 9354b3a3212SNamhyung Kim struct callchain_list *chain; 9364b3a3212SNamhyung Kim char folded_sign = ' '; 9374b3a3212SNamhyung Kim int first = true; 9384b3a3212SNamhyung Kim int extra_offset = 0; 9394b3a3212SNamhyung Kim 9404b3a3212SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 9414b3a3212SNamhyung Kim bool was_first = first; 9424b3a3212SNamhyung Kim 9434b3a3212SNamhyung Kim if (first) 9444b3a3212SNamhyung Kim first = false; 9454b3a3212SNamhyung Kim else if (need_percent) 9464b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 9474b3a3212SNamhyung Kim 9484b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 9494b3a3212SNamhyung Kim 9504b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 9514b3a3212SNamhyung Kim chain, row, total, 9524b3a3212SNamhyung Kim was_first && need_percent, 9534b3a3212SNamhyung Kim offset + extra_offset, 9544b3a3212SNamhyung Kim print, arg); 9554b3a3212SNamhyung Kim 9564b3a3212SNamhyung Kim if (is_output_full(browser, row)) 9574b3a3212SNamhyung Kim goto out; 9584b3a3212SNamhyung Kim 9594b3a3212SNamhyung Kim if (folded_sign == '+') 9604b3a3212SNamhyung Kim goto next; 9614b3a3212SNamhyung Kim } 9624b3a3212SNamhyung Kim 9634b3a3212SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 9644b3a3212SNamhyung Kim bool was_first = first; 9654b3a3212SNamhyung Kim 9664b3a3212SNamhyung Kim if (first) 9674b3a3212SNamhyung Kim first = false; 9684b3a3212SNamhyung Kim else if (need_percent) 9694b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 9704b3a3212SNamhyung Kim 9714b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 9724b3a3212SNamhyung Kim 9734b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 9744b3a3212SNamhyung Kim chain, row, total, 9754b3a3212SNamhyung Kim was_first && need_percent, 9764b3a3212SNamhyung Kim offset + extra_offset, 9774b3a3212SNamhyung Kim print, arg); 9784b3a3212SNamhyung Kim 9794b3a3212SNamhyung Kim if (is_output_full(browser, row)) 9804b3a3212SNamhyung Kim goto out; 9814b3a3212SNamhyung Kim 9824b3a3212SNamhyung Kim if (folded_sign == '+') 9834b3a3212SNamhyung Kim break; 9844b3a3212SNamhyung Kim } 9854b3a3212SNamhyung Kim 9864b3a3212SNamhyung Kim next: 9874b3a3212SNamhyung Kim if (is_output_full(browser, row)) 9884b3a3212SNamhyung Kim break; 9894b3a3212SNamhyung Kim node = next; 9904b3a3212SNamhyung Kim } 9914b3a3212SNamhyung Kim out: 9924b3a3212SNamhyung Kim return row - first_row; 9934b3a3212SNamhyung Kim } 9944b3a3212SNamhyung Kim 9958c430a34SNamhyung Kim static char *hist_browser__folded_callchain_str(struct hist_browser *browser, 9968c430a34SNamhyung Kim struct callchain_list *chain, 9978c430a34SNamhyung Kim char *value_str, char *old_str) 9988c430a34SNamhyung Kim { 9998c430a34SNamhyung Kim char bf[1024]; 10008c430a34SNamhyung Kim const char *str; 10018c430a34SNamhyung Kim char *new; 10028c430a34SNamhyung Kim 10038c430a34SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 10048c430a34SNamhyung Kim browser->show_dso); 10058c430a34SNamhyung Kim if (old_str) { 10068c430a34SNamhyung Kim if (asprintf(&new, "%s%s%s", old_str, 10078c430a34SNamhyung Kim symbol_conf.field_sep ?: ";", str) < 0) 10088c430a34SNamhyung Kim new = NULL; 10098c430a34SNamhyung Kim } else { 10108c430a34SNamhyung Kim if (value_str) { 10118c430a34SNamhyung Kim if (asprintf(&new, "%s %s", value_str, str) < 0) 10128c430a34SNamhyung Kim new = NULL; 10138c430a34SNamhyung Kim } else { 10148c430a34SNamhyung Kim if (asprintf(&new, "%s", str) < 0) 10158c430a34SNamhyung Kim new = NULL; 10168c430a34SNamhyung Kim } 10178c430a34SNamhyung Kim } 10188c430a34SNamhyung Kim return new; 10198c430a34SNamhyung Kim } 10208c430a34SNamhyung Kim 10218c430a34SNamhyung Kim static int hist_browser__show_callchain_folded(struct hist_browser *browser, 10228c430a34SNamhyung Kim struct rb_root *root, 10238c430a34SNamhyung Kim unsigned short row, u64 total, 102459c624e2SNamhyung Kim u64 parent_total, 10258c430a34SNamhyung Kim print_callchain_entry_fn print, 10268c430a34SNamhyung Kim struct callchain_print_arg *arg, 10278c430a34SNamhyung Kim check_output_full_fn is_output_full) 10288c430a34SNamhyung Kim { 10298c430a34SNamhyung Kim struct rb_node *node; 10308c430a34SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 10318c430a34SNamhyung Kim bool need_percent; 10328c430a34SNamhyung Kim 10338c430a34SNamhyung Kim node = rb_first(root); 103459c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 10358c430a34SNamhyung Kim 10368c430a34SNamhyung Kim while (node) { 10378c430a34SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 10388c430a34SNamhyung Kim struct rb_node *next = rb_next(node); 10398c430a34SNamhyung Kim struct callchain_list *chain, *first_chain = NULL; 10408c430a34SNamhyung Kim int first = true; 10418c430a34SNamhyung Kim char *value_str = NULL, *value_str_alloc = NULL; 10428c430a34SNamhyung Kim char *chain_str = NULL, *chain_str_alloc = NULL; 10438c430a34SNamhyung Kim 10448c430a34SNamhyung Kim if (arg->row_offset != 0) { 10458c430a34SNamhyung Kim arg->row_offset--; 10468c430a34SNamhyung Kim goto next; 10478c430a34SNamhyung Kim } 10488c430a34SNamhyung Kim 10498c430a34SNamhyung Kim if (need_percent) { 10508c430a34SNamhyung Kim char buf[64]; 10518c430a34SNamhyung Kim 10528c430a34SNamhyung Kim callchain_node__scnprintf_value(child, buf, sizeof(buf), total); 10538c430a34SNamhyung Kim if (asprintf(&value_str, "%s", buf) < 0) { 10548c430a34SNamhyung Kim value_str = (char *)"<...>"; 10558c430a34SNamhyung Kim goto do_print; 10568c430a34SNamhyung Kim } 10578c430a34SNamhyung Kim value_str_alloc = value_str; 10588c430a34SNamhyung Kim } 10598c430a34SNamhyung Kim 10608c430a34SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 10618c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 10628c430a34SNamhyung Kim chain, value_str, chain_str); 10638c430a34SNamhyung Kim if (first) { 10648c430a34SNamhyung Kim first = false; 10658c430a34SNamhyung Kim first_chain = chain; 10668c430a34SNamhyung Kim } 10678c430a34SNamhyung Kim 10688c430a34SNamhyung Kim if (chain_str == NULL) { 10698c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 10708c430a34SNamhyung Kim goto do_print; 10718c430a34SNamhyung Kim } 10728c430a34SNamhyung Kim 10738c430a34SNamhyung Kim chain_str_alloc = chain_str; 10748c430a34SNamhyung Kim } 10758c430a34SNamhyung Kim 10768c430a34SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 10778c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 10788c430a34SNamhyung Kim chain, value_str, chain_str); 10798c430a34SNamhyung Kim if (first) { 10808c430a34SNamhyung Kim first = false; 10818c430a34SNamhyung Kim first_chain = chain; 10828c430a34SNamhyung Kim } 10838c430a34SNamhyung Kim 10848c430a34SNamhyung Kim if (chain_str == NULL) { 10858c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 10868c430a34SNamhyung Kim goto do_print; 10878c430a34SNamhyung Kim } 10888c430a34SNamhyung Kim 10898c430a34SNamhyung Kim chain_str_alloc = chain_str; 10908c430a34SNamhyung Kim } 10918c430a34SNamhyung Kim 10928c430a34SNamhyung Kim do_print: 10938c430a34SNamhyung Kim print(browser, first_chain, chain_str, offset, row++, arg); 10948c430a34SNamhyung Kim free(value_str_alloc); 10958c430a34SNamhyung Kim free(chain_str_alloc); 10968c430a34SNamhyung Kim 10978c430a34SNamhyung Kim next: 10988c430a34SNamhyung Kim if (is_output_full(browser, row)) 10998c430a34SNamhyung Kim break; 11008c430a34SNamhyung Kim node = next; 11018c430a34SNamhyung Kim } 11028c430a34SNamhyung Kim 11038c430a34SNamhyung Kim return row - first_row; 11048c430a34SNamhyung Kim } 11058c430a34SNamhyung Kim 11060c841c6cSNamhyung Kim static int hist_browser__show_callchain_graph(struct hist_browser *browser, 1107c09a7e75SNamhyung Kim struct rb_root *root, int level, 110839ee533fSNamhyung Kim unsigned short row, u64 total, 11095eca104eSNamhyung Kim u64 parent_total, 111039ee533fSNamhyung Kim print_callchain_entry_fn print, 111139ee533fSNamhyung Kim struct callchain_print_arg *arg, 111239ee533fSNamhyung Kim check_output_full_fn is_output_full) 1113aca7a94dSNamhyung Kim { 1114aca7a94dSNamhyung Kim struct rb_node *node; 1115f4536dddSNamhyung Kim int first_row = row, offset = level * LEVEL_OFFSET_STEP; 11164087d11cSNamhyung Kim bool need_percent; 11175eca104eSNamhyung Kim u64 percent_total = total; 11185eca104eSNamhyung Kim 11195eca104eSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 11205eca104eSNamhyung Kim percent_total = parent_total; 1121aca7a94dSNamhyung Kim 1122c09a7e75SNamhyung Kim node = rb_first(root); 112359c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 11244087d11cSNamhyung Kim 1125aca7a94dSNamhyung Kim while (node) { 1126aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 1127aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 1128aca7a94dSNamhyung Kim struct callchain_list *chain; 1129aca7a94dSNamhyung Kim char folded_sign = ' '; 1130aca7a94dSNamhyung Kim int first = true; 1131aca7a94dSNamhyung Kim int extra_offset = 0; 1132aca7a94dSNamhyung Kim 1133aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 1134aca7a94dSNamhyung Kim bool was_first = first; 1135aca7a94dSNamhyung Kim 1136aca7a94dSNamhyung Kim if (first) 1137aca7a94dSNamhyung Kim first = false; 11384087d11cSNamhyung Kim else if (need_percent) 1139aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 1140aca7a94dSNamhyung Kim 1141aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 1142aca7a94dSNamhyung Kim 114318bb8381SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 11445eca104eSNamhyung Kim chain, row, percent_total, 114518bb8381SNamhyung Kim was_first && need_percent, 114618bb8381SNamhyung Kim offset + extra_offset, 114718bb8381SNamhyung Kim print, arg); 1148c09a7e75SNamhyung Kim 114918bb8381SNamhyung Kim if (is_output_full(browser, row)) 1150aca7a94dSNamhyung Kim goto out; 115118bb8381SNamhyung Kim 1152aca7a94dSNamhyung Kim if (folded_sign == '+') 1153aca7a94dSNamhyung Kim break; 1154aca7a94dSNamhyung Kim } 1155aca7a94dSNamhyung Kim 1156aca7a94dSNamhyung Kim if (folded_sign == '-') { 1157aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 1158c09a7e75SNamhyung Kim 11590c841c6cSNamhyung Kim row += hist_browser__show_callchain_graph(browser, &child->rb_root, 11605eca104eSNamhyung Kim new_level, row, total, 11615eca104eSNamhyung Kim child->children_hit, 116239ee533fSNamhyung Kim print, arg, is_output_full); 1163aca7a94dSNamhyung Kim } 116439ee533fSNamhyung Kim if (is_output_full(browser, row)) 1165c09a7e75SNamhyung Kim break; 1166aca7a94dSNamhyung Kim node = next; 1167aca7a94dSNamhyung Kim } 1168aca7a94dSNamhyung Kim out: 1169aca7a94dSNamhyung Kim return row - first_row; 1170aca7a94dSNamhyung Kim } 1171aca7a94dSNamhyung Kim 11720c841c6cSNamhyung Kim static int hist_browser__show_callchain(struct hist_browser *browser, 11730c841c6cSNamhyung Kim struct hist_entry *entry, int level, 11740c841c6cSNamhyung Kim unsigned short row, 11750c841c6cSNamhyung Kim print_callchain_entry_fn print, 11760c841c6cSNamhyung Kim struct callchain_print_arg *arg, 11770c841c6cSNamhyung Kim check_output_full_fn is_output_full) 11780c841c6cSNamhyung Kim { 11790c841c6cSNamhyung Kim u64 total = hists__total_period(entry->hists); 11805eca104eSNamhyung Kim u64 parent_total; 11810c841c6cSNamhyung Kim int printed; 11820c841c6cSNamhyung Kim 11830c841c6cSNamhyung Kim if (symbol_conf.cumulate_callchain) 11845eca104eSNamhyung Kim parent_total = entry->stat_acc->period; 11850c841c6cSNamhyung Kim else 11865eca104eSNamhyung Kim parent_total = entry->stat.period; 11870c841c6cSNamhyung Kim 11880c841c6cSNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) { 11890c841c6cSNamhyung Kim printed = hist_browser__show_callchain_flat(browser, 11905eca104eSNamhyung Kim &entry->sorted_chain, row, 11915eca104eSNamhyung Kim total, parent_total, print, arg, 11925eca104eSNamhyung Kim is_output_full); 11930c841c6cSNamhyung Kim } else if (callchain_param.mode == CHAIN_FOLDED) { 11940c841c6cSNamhyung Kim printed = hist_browser__show_callchain_folded(browser, 11955eca104eSNamhyung Kim &entry->sorted_chain, row, 11965eca104eSNamhyung Kim total, parent_total, print, arg, 11975eca104eSNamhyung Kim is_output_full); 11980c841c6cSNamhyung Kim } else { 11990c841c6cSNamhyung Kim printed = hist_browser__show_callchain_graph(browser, 12005eca104eSNamhyung Kim &entry->sorted_chain, level, row, 12015eca104eSNamhyung Kim total, parent_total, print, arg, 12025eca104eSNamhyung Kim is_output_full); 12030c841c6cSNamhyung Kim } 12040c841c6cSNamhyung Kim 12050c841c6cSNamhyung Kim if (arg->is_current_entry) 12060c841c6cSNamhyung Kim browser->he_selection = entry; 12070c841c6cSNamhyung Kim 12080c841c6cSNamhyung Kim return printed; 12090c841c6cSNamhyung Kim } 12100c841c6cSNamhyung Kim 121189701460SNamhyung Kim struct hpp_arg { 121289701460SNamhyung Kim struct ui_browser *b; 121389701460SNamhyung Kim char folded_sign; 121489701460SNamhyung Kim bool current_entry; 121589701460SNamhyung Kim }; 121689701460SNamhyung Kim 121798ba1609SJiri Olsa int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 12182f6d9009SNamhyung Kim { 12192f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 1220d675107cSNamhyung Kim int ret, len; 12212f6d9009SNamhyung Kim va_list args; 12222f6d9009SNamhyung Kim double percent; 12232f6d9009SNamhyung Kim 12242f6d9009SNamhyung Kim va_start(args, fmt); 1225d675107cSNamhyung Kim len = va_arg(args, int); 12262f6d9009SNamhyung Kim percent = va_arg(args, double); 12272f6d9009SNamhyung Kim va_end(args); 12285aed9d24SNamhyung Kim 122989701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 12305aed9d24SNamhyung Kim 1231d675107cSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); 1232517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); 123389701460SNamhyung Kim 12345aed9d24SNamhyung Kim return ret; 1235f5951d56SNamhyung Kim } 1236f5951d56SNamhyung Kim 1237fb821c9eSNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field) \ 12385aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 12395aed9d24SNamhyung Kim { \ 12405aed9d24SNamhyung Kim return he->stat._field; \ 12415aed9d24SNamhyung Kim } \ 12425aed9d24SNamhyung Kim \ 12432c5d4b4aSJiri Olsa static int \ 12445b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 12452c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 12465aed9d24SNamhyung Kim struct hist_entry *he) \ 12475aed9d24SNamhyung Kim { \ 12485b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \ 12492f6d9009SNamhyung Kim __hpp__slsmg_color_printf, true); \ 12505aed9d24SNamhyung Kim } 1251f5951d56SNamhyung Kim 12520434ddd2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 12530434ddd2SNamhyung Kim static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ 12540434ddd2SNamhyung Kim { \ 12550434ddd2SNamhyung Kim return he->stat_acc->_field; \ 12560434ddd2SNamhyung Kim } \ 12570434ddd2SNamhyung Kim \ 12580434ddd2SNamhyung Kim static int \ 12595b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 12600434ddd2SNamhyung Kim struct perf_hpp *hpp, \ 12610434ddd2SNamhyung Kim struct hist_entry *he) \ 12620434ddd2SNamhyung Kim { \ 12630434ddd2SNamhyung Kim if (!symbol_conf.cumulate_callchain) { \ 1264517dfdb3SArnaldo Carvalho de Melo struct hpp_arg *arg = hpp->ptr; \ 12655b591669SNamhyung Kim int len = fmt->user_len ?: fmt->len; \ 1266d675107cSNamhyung Kim int ret = scnprintf(hpp->buf, hpp->size, \ 12675b591669SNamhyung Kim "%*s", len, "N/A"); \ 1268517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); \ 12690434ddd2SNamhyung Kim \ 12700434ddd2SNamhyung Kim return ret; \ 12710434ddd2SNamhyung Kim } \ 12725b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \ 12735b591669SNamhyung Kim " %*.2f%%", __hpp__slsmg_color_printf, true); \ 12740434ddd2SNamhyung Kim } 12750434ddd2SNamhyung Kim 1276fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period) 1277fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 1278fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us) 1279fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 1280fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 12810434ddd2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period) 12825aed9d24SNamhyung Kim 12835aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 12840434ddd2SNamhyung Kim #undef __HPP_COLOR_ACC_PERCENT_FN 1285f5951d56SNamhyung Kim 1286f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 1287f5951d56SNamhyung Kim { 1288f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 1289f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 1290f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 1291f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 1292f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 1293f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 1294f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 1295f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 1296f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 1297f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 12980434ddd2SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = 12990434ddd2SNamhyung Kim hist_browser__hpp_color_overhead_acc; 13004968ac8fSAndi Kleen 13014968ac8fSAndi Kleen res_sample_init(); 1302f5951d56SNamhyung Kim } 1303f5951d56SNamhyung Kim 130405e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 1305aca7a94dSNamhyung Kim struct hist_entry *entry, 1306aca7a94dSNamhyung Kim unsigned short row) 1307aca7a94dSNamhyung Kim { 13081240005eSJiri Olsa int printed = 0; 130967d25916SNamhyung Kim int width = browser->b.width; 1310aca7a94dSNamhyung Kim char folded_sign = ' '; 131105e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1312fabd37b8SArnaldo Carvalho de Melo bool use_callchain = hist_entry__has_callchains(entry) && symbol_conf.use_callchain; 1313aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 131463a1a3d8SNamhyung Kim bool first = true; 13151240005eSJiri Olsa struct perf_hpp_fmt *fmt; 1316aca7a94dSNamhyung Kim 1317aca7a94dSNamhyung Kim if (current_entry) { 131805e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 131905e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 1320aca7a94dSNamhyung Kim } 1321aca7a94dSNamhyung Kim 1322fabd37b8SArnaldo Carvalho de Melo if (use_callchain) { 1323aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 1324aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 1325aca7a94dSNamhyung Kim } 1326aca7a94dSNamhyung Kim 1327aca7a94dSNamhyung Kim if (row_offset == 0) { 132889701460SNamhyung Kim struct hpp_arg arg = { 132989701460SNamhyung Kim .b = &browser->b, 133089701460SNamhyung Kim .folded_sign = folded_sign, 133189701460SNamhyung Kim .current_entry = current_entry, 133289701460SNamhyung Kim }; 1333c6c3c02dSArnaldo Carvalho de Melo int column = 0; 1334f5951d56SNamhyung Kim 1335ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 1336f5951d56SNamhyung Kim 1337f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 133889fee709SArnaldo Carvalho de Melo char s[2048]; 133989fee709SArnaldo Carvalho de Melo struct perf_hpp hpp = { 134089fee709SArnaldo Carvalho de Melo .buf = s, 134189fee709SArnaldo Carvalho de Melo .size = sizeof(s), 134289fee709SArnaldo Carvalho de Melo .ptr = &arg, 134389fee709SArnaldo Carvalho de Melo }; 134489fee709SArnaldo Carvalho de Melo 1345361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1346361459f1SNamhyung Kim column++ < browser->b.horiz_scroll) 1347e67d49a7SNamhyung Kim continue; 1348e67d49a7SNamhyung Kim 1349fb821c9eSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1350fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1351fb821c9eSNamhyung Kim HE_COLORSET_SELECTED); 1352fb821c9eSNamhyung Kim } else { 1353fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1354fb821c9eSNamhyung Kim HE_COLORSET_NORMAL); 1355fb821c9eSNamhyung Kim } 1356fb821c9eSNamhyung Kim 1357fb821c9eSNamhyung Kim if (first) { 1358fabd37b8SArnaldo Carvalho de Melo if (use_callchain) { 1359517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c ", folded_sign); 1360f5951d56SNamhyung Kim width -= 2; 1361f5951d56SNamhyung Kim } 136263a1a3d8SNamhyung Kim first = false; 1363fb821c9eSNamhyung Kim } else { 1364517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, " "); 1365fb821c9eSNamhyung Kim width -= 2; 1366fb821c9eSNamhyung Kim } 1367f5951d56SNamhyung Kim 13681240005eSJiri Olsa if (fmt->color) { 136989fee709SArnaldo Carvalho de Melo int ret = fmt->color(fmt, &hpp, entry); 137089fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 137189fee709SArnaldo Carvalho de Melo /* 137289fee709SArnaldo Carvalho de Melo * fmt->color() already used ui_browser to 137389fee709SArnaldo Carvalho de Melo * print the non alignment bits, skip it (+ret): 137489fee709SArnaldo Carvalho de Melo */ 137589fee709SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s + ret); 1376f5951d56SNamhyung Kim } else { 137789fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry)); 1378517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s); 1379f5951d56SNamhyung Kim } 138089fee709SArnaldo Carvalho de Melo width -= hpp.buf - s; 1381f5951d56SNamhyung Kim } 1382aca7a94dSNamhyung Kim 1383aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 138405e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 1385aca7a94dSNamhyung Kim width += 1; 1386aca7a94dSNamhyung Kim 138726270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, "", width); 138826d8b338SNamhyung Kim 1389aca7a94dSNamhyung Kim ++row; 1390aca7a94dSNamhyung Kim ++printed; 1391aca7a94dSNamhyung Kim } else 1392aca7a94dSNamhyung Kim --row_offset; 1393aca7a94dSNamhyung Kim 139462c95ae3SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.rows) { 139539ee533fSNamhyung Kim struct callchain_print_arg arg = { 139639ee533fSNamhyung Kim .row_offset = row_offset, 139739ee533fSNamhyung Kim .is_current_entry = current_entry, 139839ee533fSNamhyung Kim }; 1399c09a7e75SNamhyung Kim 14000d3eb0b7SJin Yao printed += hist_browser__show_callchain(browser, 14010d3eb0b7SJin Yao entry, 1, row, 14020d3eb0b7SJin Yao hist_browser__show_callchain_entry, 14030d3eb0b7SJin Yao &arg, 14044b3a3212SNamhyung Kim hist_browser__check_output_full); 1405aca7a94dSNamhyung Kim } 1406aca7a94dSNamhyung Kim 1407aca7a94dSNamhyung Kim return printed; 1408aca7a94dSNamhyung Kim } 1409aca7a94dSNamhyung Kim 1410d0506edbSNamhyung Kim static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, 1411d0506edbSNamhyung Kim struct hist_entry *entry, 1412d0506edbSNamhyung Kim unsigned short row, 14132dbbe9f2SNamhyung Kim int level) 1414d0506edbSNamhyung Kim { 1415d0506edbSNamhyung Kim int printed = 0; 1416d0506edbSNamhyung Kim int width = browser->b.width; 1417d0506edbSNamhyung Kim char folded_sign = ' '; 1418d0506edbSNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1419d0506edbSNamhyung Kim off_t row_offset = entry->row_offset; 1420d0506edbSNamhyung Kim bool first = true; 1421d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 1422a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1423d0506edbSNamhyung Kim struct hpp_arg arg = { 1424d0506edbSNamhyung Kim .b = &browser->b, 1425d0506edbSNamhyung Kim .current_entry = current_entry, 1426d0506edbSNamhyung Kim }; 1427d0506edbSNamhyung Kim int column = 0; 14282dbbe9f2SNamhyung Kim int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 1429d0506edbSNamhyung Kim 1430d0506edbSNamhyung Kim if (current_entry) { 1431d0506edbSNamhyung Kim browser->he_selection = entry; 1432d0506edbSNamhyung Kim browser->selection = &entry->ms; 1433d0506edbSNamhyung Kim } 1434d0506edbSNamhyung Kim 1435d0506edbSNamhyung Kim hist_entry__init_have_children(entry); 1436d0506edbSNamhyung Kim folded_sign = hist_entry__folded(entry); 1437d0506edbSNamhyung Kim arg.folded_sign = folded_sign; 1438d0506edbSNamhyung Kim 1439d0506edbSNamhyung Kim if (entry->leaf && row_offset) { 1440d0506edbSNamhyung Kim row_offset--; 1441d0506edbSNamhyung Kim goto show_callchain; 1442d0506edbSNamhyung Kim } 1443d0506edbSNamhyung Kim 1444ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 1445d0506edbSNamhyung Kim 1446d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) 1447d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 1448d0506edbSNamhyung Kim else 1449d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 1450d0506edbSNamhyung Kim 1451d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 1452d0506edbSNamhyung Kim width -= level * HIERARCHY_INDENT; 1453d0506edbSNamhyung Kim 1454a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1455a61a22f6SNamhyung Kim fmt_node = list_first_entry(&entry->hists->hpp_formats, 1456a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1457a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1458d0506edbSNamhyung Kim char s[2048]; 1459d0506edbSNamhyung Kim struct perf_hpp hpp = { 1460d0506edbSNamhyung Kim .buf = s, 1461d0506edbSNamhyung Kim .size = sizeof(s), 1462d0506edbSNamhyung Kim .ptr = &arg, 1463d0506edbSNamhyung Kim }; 1464d0506edbSNamhyung Kim 1465d0506edbSNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1466d0506edbSNamhyung Kim column++ < browser->b.horiz_scroll) 1467d0506edbSNamhyung Kim continue; 1468d0506edbSNamhyung Kim 1469d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1470d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1471d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1472d0506edbSNamhyung Kim } else { 1473d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1474d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1475d0506edbSNamhyung Kim } 1476d0506edbSNamhyung Kim 1477d0506edbSNamhyung Kim if (first) { 1478d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%c ", folded_sign); 14793d9f4683SNamhyung Kim width -= 2; 1480d0506edbSNamhyung Kim first = false; 1481d0506edbSNamhyung Kim } else { 1482d0506edbSNamhyung Kim ui_browser__printf(&browser->b, " "); 1483d0506edbSNamhyung Kim width -= 2; 1484d0506edbSNamhyung Kim } 1485d0506edbSNamhyung Kim 1486d0506edbSNamhyung Kim if (fmt->color) { 1487d0506edbSNamhyung Kim int ret = fmt->color(fmt, &hpp, entry); 1488d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1489d0506edbSNamhyung Kim /* 1490d0506edbSNamhyung Kim * fmt->color() already used ui_browser to 1491d0506edbSNamhyung Kim * print the non alignment bits, skip it (+ret): 1492d0506edbSNamhyung Kim */ 1493d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s + ret); 1494d0506edbSNamhyung Kim } else { 1495d0506edbSNamhyung Kim int ret = fmt->entry(fmt, &hpp, entry); 1496d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1497d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s); 1498d0506edbSNamhyung Kim } 1499d0506edbSNamhyung Kim width -= hpp.buf - s; 1500d0506edbSNamhyung Kim } 1501d0506edbSNamhyung Kim 1502b9bf911eSNamhyung Kim if (!first) { 1503d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", hierarchy_indent); 1504d0506edbSNamhyung Kim width -= hierarchy_indent; 1505b9bf911eSNamhyung Kim } 1506d0506edbSNamhyung Kim 1507d0506edbSNamhyung Kim if (column >= browser->b.horiz_scroll) { 1508d0506edbSNamhyung Kim char s[2048]; 1509d0506edbSNamhyung Kim struct perf_hpp hpp = { 1510d0506edbSNamhyung Kim .buf = s, 1511d0506edbSNamhyung Kim .size = sizeof(s), 1512d0506edbSNamhyung Kim .ptr = &arg, 1513d0506edbSNamhyung Kim }; 1514d0506edbSNamhyung Kim 1515d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1516d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1517d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1518d0506edbSNamhyung Kim } else { 1519d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1520d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1521d0506edbSNamhyung Kim } 1522d0506edbSNamhyung Kim 15231b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(entry->hpp_list, fmt) { 1524131d51ebSNamhyung Kim if (first) { 1525131d51ebSNamhyung Kim ui_browser__printf(&browser->b, "%c ", folded_sign); 1526131d51ebSNamhyung Kim first = false; 1527131d51ebSNamhyung Kim } else { 1528d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", 2); 1529131d51ebSNamhyung Kim } 1530131d51ebSNamhyung Kim 1531d0506edbSNamhyung Kim width -= 2; 1532d0506edbSNamhyung Kim 1533d0506edbSNamhyung Kim /* 1534d0506edbSNamhyung Kim * No need to call hist_entry__snprintf_alignment() 1535d0506edbSNamhyung Kim * since this fmt is always the last column in the 1536d0506edbSNamhyung Kim * hierarchy mode. 1537d0506edbSNamhyung Kim */ 1538d0506edbSNamhyung Kim if (fmt->color) { 1539d0506edbSNamhyung Kim width -= fmt->color(fmt, &hpp, entry); 1540d0506edbSNamhyung Kim } else { 1541cb1fab91SNamhyung Kim int i = 0; 1542cb1fab91SNamhyung Kim 1543d0506edbSNamhyung Kim width -= fmt->entry(fmt, &hpp, entry); 154432858480SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", skip_spaces(s)); 1545cb1fab91SNamhyung Kim 1546cb1fab91SNamhyung Kim while (isspace(s[i++])) 1547cb1fab91SNamhyung Kim width++; 1548d0506edbSNamhyung Kim } 1549d0506edbSNamhyung Kim } 15501b2dbbf4SNamhyung Kim } 1551d0506edbSNamhyung Kim 1552d0506edbSNamhyung Kim /* The scroll bar isn't being used */ 1553d0506edbSNamhyung Kim if (!browser->b.navkeypressed) 1554d0506edbSNamhyung Kim width += 1; 1555d0506edbSNamhyung Kim 1556d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 1557d0506edbSNamhyung Kim 1558d0506edbSNamhyung Kim ++row; 1559d0506edbSNamhyung Kim ++printed; 1560d0506edbSNamhyung Kim 1561d0506edbSNamhyung Kim show_callchain: 1562d0506edbSNamhyung Kim if (entry->leaf && folded_sign == '-' && row != browser->b.rows) { 1563d0506edbSNamhyung Kim struct callchain_print_arg carg = { 1564d0506edbSNamhyung Kim .row_offset = row_offset, 1565d0506edbSNamhyung Kim }; 1566d0506edbSNamhyung Kim 1567d0506edbSNamhyung Kim printed += hist_browser__show_callchain(browser, entry, 1568d0506edbSNamhyung Kim level + 1, row, 1569d0506edbSNamhyung Kim hist_browser__show_callchain_entry, &carg, 1570d0506edbSNamhyung Kim hist_browser__check_output_full); 1571d0506edbSNamhyung Kim } 1572d0506edbSNamhyung Kim 1573d0506edbSNamhyung Kim return printed; 1574d0506edbSNamhyung Kim } 1575d0506edbSNamhyung Kim 157679dded87SNamhyung Kim static int hist_browser__show_no_entry(struct hist_browser *browser, 15772dbbe9f2SNamhyung Kim unsigned short row, int level) 157879dded87SNamhyung Kim { 157979dded87SNamhyung Kim int width = browser->b.width; 158079dded87SNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 158179dded87SNamhyung Kim bool first = true; 158279dded87SNamhyung Kim int column = 0; 158379dded87SNamhyung Kim int ret; 158479dded87SNamhyung Kim struct perf_hpp_fmt *fmt; 1585a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 15862dbbe9f2SNamhyung Kim int indent = browser->hists->nr_hpp_node - 2; 158779dded87SNamhyung Kim 158879dded87SNamhyung Kim if (current_entry) { 158979dded87SNamhyung Kim browser->he_selection = NULL; 159079dded87SNamhyung Kim browser->selection = NULL; 159179dded87SNamhyung Kim } 159279dded87SNamhyung Kim 1593ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 159479dded87SNamhyung Kim 159579dded87SNamhyung Kim if (current_entry && browser->b.navkeypressed) 159679dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 159779dded87SNamhyung Kim else 159879dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 159979dded87SNamhyung Kim 160079dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 160179dded87SNamhyung Kim width -= level * HIERARCHY_INDENT; 160279dded87SNamhyung Kim 1603a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1604a61a22f6SNamhyung Kim fmt_node = list_first_entry(&browser->hists->hpp_formats, 1605a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1606a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 160779dded87SNamhyung Kim if (perf_hpp__should_skip(fmt, browser->hists) || 160879dded87SNamhyung Kim column++ < browser->b.horiz_scroll) 160979dded87SNamhyung Kim continue; 161079dded87SNamhyung Kim 1611da1b0407SJiri Olsa ret = fmt->width(fmt, NULL, browser->hists); 161279dded87SNamhyung Kim 161379dded87SNamhyung Kim if (first) { 161479dded87SNamhyung Kim /* for folded sign */ 161579dded87SNamhyung Kim first = false; 161679dded87SNamhyung Kim ret++; 161779dded87SNamhyung Kim } else { 161879dded87SNamhyung Kim /* space between columns */ 161979dded87SNamhyung Kim ret += 2; 162079dded87SNamhyung Kim } 162179dded87SNamhyung Kim 162279dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", ret); 162379dded87SNamhyung Kim width -= ret; 162479dded87SNamhyung Kim } 162579dded87SNamhyung Kim 16262dbbe9f2SNamhyung Kim ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT); 16272dbbe9f2SNamhyung Kim width -= indent * HIERARCHY_INDENT; 162879dded87SNamhyung Kim 162979dded87SNamhyung Kim if (column >= browser->b.horiz_scroll) { 163079dded87SNamhyung Kim char buf[32]; 163179dded87SNamhyung Kim 163279dded87SNamhyung Kim ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt); 163379dded87SNamhyung Kim ui_browser__printf(&browser->b, " %s", buf); 163479dded87SNamhyung Kim width -= ret + 2; 163579dded87SNamhyung Kim } 163679dded87SNamhyung Kim 163779dded87SNamhyung Kim /* The scroll bar isn't being used */ 163879dded87SNamhyung Kim if (!browser->b.navkeypressed) 163979dded87SNamhyung Kim width += 1; 164079dded87SNamhyung Kim 164179dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 164279dded87SNamhyung Kim return 1; 164379dded87SNamhyung Kim } 164479dded87SNamhyung Kim 164581a888feSJiri Olsa static int advance_hpp_check(struct perf_hpp *hpp, int inc) 164681a888feSJiri Olsa { 164781a888feSJiri Olsa advance_hpp(hpp, inc); 164881a888feSJiri Olsa return hpp->size <= 0; 164981a888feSJiri Olsa } 165081a888feSJiri Olsa 165169705b35SJiri Olsa static int 165269705b35SJiri Olsa hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, 165369705b35SJiri Olsa size_t size, int line) 165481a888feSJiri Olsa { 1655c6c3c02dSArnaldo Carvalho de Melo struct hists *hists = browser->hists; 165681a888feSJiri Olsa struct perf_hpp dummy_hpp = { 165781a888feSJiri Olsa .buf = buf, 165881a888feSJiri Olsa .size = size, 165981a888feSJiri Olsa }; 166081a888feSJiri Olsa struct perf_hpp_fmt *fmt; 166181a888feSJiri Olsa size_t ret = 0; 1662c6c3c02dSArnaldo Carvalho de Melo int column = 0; 166329659ab4SJiri Olsa int span = 0; 166481a888feSJiri Olsa 1665fabd37b8SArnaldo Carvalho de Melo if (hists__has_callchains(hists) && symbol_conf.use_callchain) { 166681a888feSJiri Olsa ret = scnprintf(buf, size, " "); 166781a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 166881a888feSJiri Olsa return ret; 166981a888feSJiri Olsa } 167081a888feSJiri Olsa 1671f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 1672361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) 167381a888feSJiri Olsa continue; 167481a888feSJiri Olsa 167529659ab4SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists, line, &span); 167681a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 167781a888feSJiri Olsa break; 167881a888feSJiri Olsa 167929659ab4SJiri Olsa if (span) 168029659ab4SJiri Olsa continue; 168129659ab4SJiri Olsa 168281a888feSJiri Olsa ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 168381a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 168481a888feSJiri Olsa break; 168581a888feSJiri Olsa } 168681a888feSJiri Olsa 168781a888feSJiri Olsa return ret; 168881a888feSJiri Olsa } 168981a888feSJiri Olsa 1690d8b92400SNamhyung Kim static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size) 1691d8b92400SNamhyung Kim { 1692d8b92400SNamhyung Kim struct hists *hists = browser->hists; 1693d8b92400SNamhyung Kim struct perf_hpp dummy_hpp = { 1694d8b92400SNamhyung Kim .buf = buf, 1695d8b92400SNamhyung Kim .size = size, 1696d8b92400SNamhyung Kim }; 1697d8b92400SNamhyung Kim struct perf_hpp_fmt *fmt; 1698a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1699d8b92400SNamhyung Kim size_t ret = 0; 1700d8b92400SNamhyung Kim int column = 0; 17012dbbe9f2SNamhyung Kim int indent = hists->nr_hpp_node - 2; 1702a61a22f6SNamhyung Kim bool first_node, first_col; 1703d8b92400SNamhyung Kim 1704d8b92400SNamhyung Kim ret = scnprintf(buf, size, " "); 1705d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1706d8b92400SNamhyung Kim return ret; 1707d8b92400SNamhyung Kim 1708b9bf911eSNamhyung Kim first_node = true; 1709a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1710a61a22f6SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 1711a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1712a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1713d8b92400SNamhyung Kim if (column++ < browser->b.horiz_scroll) 1714d8b92400SNamhyung Kim continue; 1715d8b92400SNamhyung Kim 171629659ab4SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL); 1717d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1718d8b92400SNamhyung Kim break; 1719d8b92400SNamhyung Kim 1720d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 1721d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1722d8b92400SNamhyung Kim break; 1723b9bf911eSNamhyung Kim 1724b9bf911eSNamhyung Kim first_node = false; 1725d8b92400SNamhyung Kim } 1726d8b92400SNamhyung Kim 1727b9bf911eSNamhyung Kim if (!first_node) { 1728d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s", 17292dbbe9f2SNamhyung Kim indent * HIERARCHY_INDENT, ""); 1730d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1731d8b92400SNamhyung Kim return ret; 1732b9bf911eSNamhyung Kim } 1733d8b92400SNamhyung Kim 1734a61a22f6SNamhyung Kim first_node = true; 1735a61a22f6SNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) { 1736a61a22f6SNamhyung Kim if (!first_node) { 1737d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / "); 1738d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1739d8b92400SNamhyung Kim break; 1740d8b92400SNamhyung Kim } 1741a61a22f6SNamhyung Kim first_node = false; 1742a61a22f6SNamhyung Kim 1743a61a22f6SNamhyung Kim first_col = true; 1744a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1745a61a22f6SNamhyung Kim char *start; 1746a61a22f6SNamhyung Kim 1747a61a22f6SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 1748a61a22f6SNamhyung Kim continue; 1749a61a22f6SNamhyung Kim 1750a61a22f6SNamhyung Kim if (!first_col) { 1751a61a22f6SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+"); 1752a61a22f6SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1753a61a22f6SNamhyung Kim break; 1754a61a22f6SNamhyung Kim } 1755a61a22f6SNamhyung Kim first_col = false; 1756d8b92400SNamhyung Kim 175729659ab4SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL); 1758d8b92400SNamhyung Kim dummy_hpp.buf[ret] = '\0'; 1759d8b92400SNamhyung Kim 17603ca43b60SArnaldo Carvalho de Melo start = strim(dummy_hpp.buf); 1761cb1fab91SNamhyung Kim ret = strlen(start); 1762cb1fab91SNamhyung Kim 1763cb1fab91SNamhyung Kim if (start != dummy_hpp.buf) 1764cb1fab91SNamhyung Kim memmove(dummy_hpp.buf, start, ret + 1); 1765cb1fab91SNamhyung Kim 1766d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1767d8b92400SNamhyung Kim break; 1768d8b92400SNamhyung Kim } 1769a61a22f6SNamhyung Kim } 1770d8b92400SNamhyung Kim 1771d8b92400SNamhyung Kim return ret; 1772d8b92400SNamhyung Kim } 1773d8b92400SNamhyung Kim 177401b4770dSJiri Olsa static void hists_browser__hierarchy_headers(struct hist_browser *browser) 1775025bf7eaSArnaldo Carvalho de Melo { 177681a888feSJiri Olsa char headers[1024]; 177781a888feSJiri Olsa 1778d8b92400SNamhyung Kim hists_browser__scnprintf_hierarchy_headers(browser, headers, 1779d8b92400SNamhyung Kim sizeof(headers)); 178001b4770dSJiri Olsa 1781025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, 0, 0); 1782025bf7eaSArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 178326270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 1784025bf7eaSArnaldo Carvalho de Melo } 1785025bf7eaSArnaldo Carvalho de Melo 178601b4770dSJiri Olsa static void hists_browser__headers(struct hist_browser *browser) 178701b4770dSJiri Olsa { 178869705b35SJiri Olsa struct hists *hists = browser->hists; 178969705b35SJiri Olsa struct perf_hpp_list *hpp_list = hists->hpp_list; 179069705b35SJiri Olsa 179169705b35SJiri Olsa int line; 179269705b35SJiri Olsa 179369705b35SJiri Olsa for (line = 0; line < hpp_list->nr_header_lines; line++) { 179401b4770dSJiri Olsa char headers[1024]; 179501b4770dSJiri Olsa 179601b4770dSJiri Olsa hists_browser__scnprintf_headers(browser, headers, 179769705b35SJiri Olsa sizeof(headers), line); 179801b4770dSJiri Olsa 1799ef9ff601SArnaldo Carvalho de Melo ui_browser__gotorc_title(&browser->b, line, 0); 180001b4770dSJiri Olsa ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 180101b4770dSJiri Olsa ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 180201b4770dSJiri Olsa } 180369705b35SJiri Olsa } 180401b4770dSJiri Olsa 180501b4770dSJiri Olsa static void hist_browser__show_headers(struct hist_browser *browser) 180601b4770dSJiri Olsa { 180701b4770dSJiri Olsa if (symbol_conf.report_hierarchy) 180801b4770dSJiri Olsa hists_browser__hierarchy_headers(browser); 180901b4770dSJiri Olsa else 181001b4770dSJiri Olsa hists_browser__headers(browser); 181101b4770dSJiri Olsa } 181201b4770dSJiri Olsa 1813aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 1814aca7a94dSNamhyung Kim { 1815aca7a94dSNamhyung Kim if (browser->top == NULL) { 1816aca7a94dSNamhyung Kim struct hist_browser *hb; 1817aca7a94dSNamhyung Kim 1818aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 18192eb3d689SDavidlohr Bueso browser->top = rb_first_cached(&hb->hists->entries); 1820aca7a94dSNamhyung Kim } 1821aca7a94dSNamhyung Kim } 1822aca7a94dSNamhyung Kim 182305e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 1824aca7a94dSNamhyung Kim { 1825aca7a94dSNamhyung Kim unsigned row = 0; 1826aca7a94dSNamhyung Kim struct rb_node *nd; 182705e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 1828aca7a94dSNamhyung Kim 182994e87a8bSArnaldo Carvalho de Melo if (hb->show_headers) 1830025bf7eaSArnaldo Carvalho de Melo hist_browser__show_headers(hb); 1831025bf7eaSArnaldo Carvalho de Melo 183205e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1833979d2cacSWang Nan hb->he_selection = NULL; 1834979d2cacSWang Nan hb->selection = NULL; 1835aca7a94dSNamhyung Kim 1836d0506edbSNamhyung Kim for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) { 1837aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 183814135663SNamhyung Kim float percent; 1839aca7a94dSNamhyung Kim 1840d0506edbSNamhyung Kim if (h->filtered) { 1841d0506edbSNamhyung Kim /* let it move to sibling */ 1842d0506edbSNamhyung Kim h->unfolded = false; 1843aca7a94dSNamhyung Kim continue; 1844d0506edbSNamhyung Kim } 1845aca7a94dSNamhyung Kim 18467fa46cbfSJin Yao if (symbol_conf.report_individual_block) 18477fa46cbfSJin Yao percent = block_info__total_cycles_percent(h); 18487fa46cbfSJin Yao else 184914135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 18507fa46cbfSJin Yao 1851064f1981SNamhyung Kim if (percent < hb->min_pcnt) 1852064f1981SNamhyung Kim continue; 1853064f1981SNamhyung Kim 1854d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 1855d0506edbSNamhyung Kim row += hist_browser__show_hierarchy_entry(hb, h, row, 18562dbbe9f2SNamhyung Kim h->depth); 185779dded87SNamhyung Kim if (row == browser->rows) 185879dded87SNamhyung Kim break; 185979dded87SNamhyung Kim 186079dded87SNamhyung Kim if (h->has_no_entry) { 1861a61a22f6SNamhyung Kim hist_browser__show_no_entry(hb, row, h->depth + 1); 186279dded87SNamhyung Kim row++; 186379dded87SNamhyung Kim } 1864d0506edbSNamhyung Kim } else { 1865aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 1866d0506edbSNamhyung Kim } 1867d0506edbSNamhyung Kim 186862c95ae3SArnaldo Carvalho de Melo if (row == browser->rows) 1869aca7a94dSNamhyung Kim break; 1870aca7a94dSNamhyung Kim } 1871aca7a94dSNamhyung Kim 187294e87a8bSArnaldo Carvalho de Melo return row; 1873aca7a94dSNamhyung Kim } 1874aca7a94dSNamhyung Kim 1875064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 1876064f1981SNamhyung Kim float min_pcnt) 1877aca7a94dSNamhyung Kim { 1878aca7a94dSNamhyung Kim while (nd != NULL) { 1879aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 188014135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1881064f1981SNamhyung Kim 1882c0f1527bSNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1883aca7a94dSNamhyung Kim return nd; 1884aca7a94dSNamhyung Kim 1885d0506edbSNamhyung Kim /* 1886d0506edbSNamhyung Kim * If it's filtered, its all children also were filtered. 1887d0506edbSNamhyung Kim * So move to sibling node. 1888d0506edbSNamhyung Kim */ 1889d0506edbSNamhyung Kim if (rb_next(nd)) 1890aca7a94dSNamhyung Kim nd = rb_next(nd); 1891d0506edbSNamhyung Kim else 1892d0506edbSNamhyung Kim nd = rb_hierarchy_next(nd); 1893aca7a94dSNamhyung Kim } 1894aca7a94dSNamhyung Kim 1895aca7a94dSNamhyung Kim return NULL; 1896aca7a94dSNamhyung Kim } 1897aca7a94dSNamhyung Kim 1898064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 1899064f1981SNamhyung Kim float min_pcnt) 1900aca7a94dSNamhyung Kim { 1901aca7a94dSNamhyung Kim while (nd != NULL) { 1902aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 190314135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1904064f1981SNamhyung Kim 1905064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1906aca7a94dSNamhyung Kim return nd; 1907aca7a94dSNamhyung Kim 1908d0506edbSNamhyung Kim nd = rb_hierarchy_prev(nd); 1909aca7a94dSNamhyung Kim } 1910aca7a94dSNamhyung Kim 1911aca7a94dSNamhyung Kim return NULL; 1912aca7a94dSNamhyung Kim } 1913aca7a94dSNamhyung Kim 191405e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 1915aca7a94dSNamhyung Kim off_t offset, int whence) 1916aca7a94dSNamhyung Kim { 1917aca7a94dSNamhyung Kim struct hist_entry *h; 1918aca7a94dSNamhyung Kim struct rb_node *nd; 1919aca7a94dSNamhyung Kim bool first = true; 1920064f1981SNamhyung Kim struct hist_browser *hb; 1921064f1981SNamhyung Kim 1922064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1923aca7a94dSNamhyung Kim 192405e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 1925aca7a94dSNamhyung Kim return; 1926aca7a94dSNamhyung Kim 192705e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1928aca7a94dSNamhyung Kim 1929aca7a94dSNamhyung Kim switch (whence) { 1930aca7a94dSNamhyung Kim case SEEK_SET: 1931064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 193214135663SNamhyung Kim hb->min_pcnt); 1933aca7a94dSNamhyung Kim break; 1934aca7a94dSNamhyung Kim case SEEK_CUR: 193505e8b080SArnaldo Carvalho de Melo nd = browser->top; 1936aca7a94dSNamhyung Kim goto do_offset; 1937aca7a94dSNamhyung Kim case SEEK_END: 1938d0506edbSNamhyung Kim nd = rb_hierarchy_last(rb_last(browser->entries)); 1939d0506edbSNamhyung Kim nd = hists__filter_prev_entries(nd, hb->min_pcnt); 1940aca7a94dSNamhyung Kim first = false; 1941aca7a94dSNamhyung Kim break; 1942aca7a94dSNamhyung Kim default: 1943aca7a94dSNamhyung Kim return; 1944aca7a94dSNamhyung Kim } 1945aca7a94dSNamhyung Kim 1946aca7a94dSNamhyung Kim /* 1947aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 1948aca7a94dSNamhyung Kim * row_offset: 1949aca7a94dSNamhyung Kim */ 195005e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 1951aca7a94dSNamhyung Kim h->row_offset = 0; 1952aca7a94dSNamhyung Kim 1953aca7a94dSNamhyung Kim /* 1954aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 1955aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 1956aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 1957aca7a94dSNamhyung Kim * 1958aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 1959aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 1960aca7a94dSNamhyung Kim * 1961aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 1962aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 1963aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 1964aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 1965aca7a94dSNamhyung Kim */ 1966aca7a94dSNamhyung Kim do_offset: 1967837eeb75SWang Nan if (!nd) 1968837eeb75SWang Nan return; 1969837eeb75SWang Nan 1970aca7a94dSNamhyung Kim if (offset > 0) { 1971aca7a94dSNamhyung Kim do { 1972aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1973d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1974aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 1975aca7a94dSNamhyung Kim if (offset > remaining) { 1976aca7a94dSNamhyung Kim offset -= remaining; 1977aca7a94dSNamhyung Kim h->row_offset = 0; 1978aca7a94dSNamhyung Kim } else { 1979aca7a94dSNamhyung Kim h->row_offset += offset; 1980aca7a94dSNamhyung Kim offset = 0; 198105e8b080SArnaldo Carvalho de Melo browser->top = nd; 1982aca7a94dSNamhyung Kim break; 1983aca7a94dSNamhyung Kim } 1984aca7a94dSNamhyung Kim } 1985d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 1986d0506edbSNamhyung Kim hb->min_pcnt); 1987aca7a94dSNamhyung Kim if (nd == NULL) 1988aca7a94dSNamhyung Kim break; 1989aca7a94dSNamhyung Kim --offset; 199005e8b080SArnaldo Carvalho de Melo browser->top = nd; 1991aca7a94dSNamhyung Kim } while (offset != 0); 1992aca7a94dSNamhyung Kim } else if (offset < 0) { 1993aca7a94dSNamhyung Kim while (1) { 1994aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1995d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1996aca7a94dSNamhyung Kim if (first) { 1997aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 1998aca7a94dSNamhyung Kim offset += h->row_offset; 1999aca7a94dSNamhyung Kim h->row_offset = 0; 2000aca7a94dSNamhyung Kim } else { 2001aca7a94dSNamhyung Kim h->row_offset += offset; 2002aca7a94dSNamhyung Kim offset = 0; 200305e8b080SArnaldo Carvalho de Melo browser->top = nd; 2004aca7a94dSNamhyung Kim break; 2005aca7a94dSNamhyung Kim } 2006aca7a94dSNamhyung Kim } else { 2007aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 2008aca7a94dSNamhyung Kim offset += h->nr_rows; 2009aca7a94dSNamhyung Kim h->row_offset = 0; 2010aca7a94dSNamhyung Kim } else { 2011aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 2012aca7a94dSNamhyung Kim offset = 0; 201305e8b080SArnaldo Carvalho de Melo browser->top = nd; 2014aca7a94dSNamhyung Kim break; 2015aca7a94dSNamhyung Kim } 2016aca7a94dSNamhyung Kim } 2017aca7a94dSNamhyung Kim } 2018aca7a94dSNamhyung Kim 2019d0506edbSNamhyung Kim nd = hists__filter_prev_entries(rb_hierarchy_prev(nd), 2020064f1981SNamhyung Kim hb->min_pcnt); 2021aca7a94dSNamhyung Kim if (nd == NULL) 2022aca7a94dSNamhyung Kim break; 2023aca7a94dSNamhyung Kim ++offset; 202405e8b080SArnaldo Carvalho de Melo browser->top = nd; 2025aca7a94dSNamhyung Kim if (offset == 0) { 2026aca7a94dSNamhyung Kim /* 2027aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 2028aca7a94dSNamhyung Kim * unfolded, if it is then we should have 2029aca7a94dSNamhyung Kim * row_offset at its last entry. 2030aca7a94dSNamhyung Kim */ 2031aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 2032d0506edbSNamhyung Kim if (h->unfolded && h->leaf) 2033aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 2034aca7a94dSNamhyung Kim break; 2035aca7a94dSNamhyung Kim } 2036aca7a94dSNamhyung Kim first = false; 2037aca7a94dSNamhyung Kim } 2038aca7a94dSNamhyung Kim } else { 203905e8b080SArnaldo Carvalho de Melo browser->top = nd; 2040aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 2041aca7a94dSNamhyung Kim h->row_offset = 0; 2042aca7a94dSNamhyung Kim } 2043aca7a94dSNamhyung Kim } 2044aca7a94dSNamhyung Kim 2045aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 2046d0506edbSNamhyung Kim struct hist_entry *he, FILE *fp, 2047d0506edbSNamhyung Kim int level) 2048aff3f3f6SArnaldo Carvalho de Melo { 204939ee533fSNamhyung Kim struct callchain_print_arg arg = { 205039ee533fSNamhyung Kim .fp = fp, 205139ee533fSNamhyung Kim }; 2052aff3f3f6SArnaldo Carvalho de Melo 2053d0506edbSNamhyung Kim hist_browser__show_callchain(browser, he, level, 0, 205439ee533fSNamhyung Kim hist_browser__fprintf_callchain_entry, &arg, 205539ee533fSNamhyung Kim hist_browser__check_dump_full); 205639ee533fSNamhyung Kim return arg.printed; 2057aff3f3f6SArnaldo Carvalho de Melo } 2058aff3f3f6SArnaldo Carvalho de Melo 2059aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 2060aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 2061aff3f3f6SArnaldo Carvalho de Melo { 2062aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 2063aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 2064aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 206526d8b338SNamhyung Kim struct perf_hpp hpp = { 206626d8b338SNamhyung Kim .buf = s, 206726d8b338SNamhyung Kim .size = sizeof(s), 206826d8b338SNamhyung Kim }; 206926d8b338SNamhyung Kim struct perf_hpp_fmt *fmt; 207026d8b338SNamhyung Kim bool first = true; 207126d8b338SNamhyung Kim int ret; 2072aff3f3f6SArnaldo Carvalho de Melo 2073fabd37b8SArnaldo Carvalho de Melo if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) { 2074aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 2075aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 20761b6b678eSArnaldo Carvalho de Melo } 2077aff3f3f6SArnaldo Carvalho de Melo 2078f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 2079361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, he->hists)) 2080e67d49a7SNamhyung Kim continue; 2081e67d49a7SNamhyung Kim 208226d8b338SNamhyung Kim if (!first) { 208326d8b338SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 208426d8b338SNamhyung Kim advance_hpp(&hpp, ret); 208526d8b338SNamhyung Kim } else 208626d8b338SNamhyung Kim first = false; 2087aff3f3f6SArnaldo Carvalho de Melo 208826d8b338SNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 208989fee709SArnaldo Carvalho de Melo ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret); 209026d8b338SNamhyung Kim advance_hpp(&hpp, ret); 209126d8b338SNamhyung Kim } 209289fee709SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", s); 2093aff3f3f6SArnaldo Carvalho de Melo 2094aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 2095d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 1); 2096d0506edbSNamhyung Kim 2097d0506edbSNamhyung Kim return printed; 2098d0506edbSNamhyung Kim } 2099d0506edbSNamhyung Kim 2100d0506edbSNamhyung Kim 2101d0506edbSNamhyung Kim static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser, 2102d0506edbSNamhyung Kim struct hist_entry *he, 2103325a6283SNamhyung Kim FILE *fp, int level) 2104d0506edbSNamhyung Kim { 2105d0506edbSNamhyung Kim char s[8192]; 2106d0506edbSNamhyung Kim int printed = 0; 2107d0506edbSNamhyung Kim char folded_sign = ' '; 2108d0506edbSNamhyung Kim struct perf_hpp hpp = { 2109d0506edbSNamhyung Kim .buf = s, 2110d0506edbSNamhyung Kim .size = sizeof(s), 2111d0506edbSNamhyung Kim }; 2112d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 2113325a6283SNamhyung Kim struct perf_hpp_list_node *fmt_node; 2114d0506edbSNamhyung Kim bool first = true; 2115d0506edbSNamhyung Kim int ret; 2116325a6283SNamhyung Kim int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 2117d0506edbSNamhyung Kim 2118d0506edbSNamhyung Kim printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, ""); 2119d0506edbSNamhyung Kim 2120d0506edbSNamhyung Kim folded_sign = hist_entry__folded(he); 2121d0506edbSNamhyung Kim printed += fprintf(fp, "%c", folded_sign); 2122d0506edbSNamhyung Kim 2123325a6283SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 2124325a6283SNamhyung Kim fmt_node = list_first_entry(&he->hists->hpp_formats, 2125325a6283SNamhyung Kim struct perf_hpp_list_node, list); 2126325a6283SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 2127d0506edbSNamhyung Kim if (!first) { 2128d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 2129d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 2130d0506edbSNamhyung Kim } else 2131d0506edbSNamhyung Kim first = false; 2132d0506edbSNamhyung Kim 2133d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 2134d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 2135d0506edbSNamhyung Kim } 2136d0506edbSNamhyung Kim 2137d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, ""); 2138d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 2139d0506edbSNamhyung Kim 21401b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(he->hpp_list, fmt) { 21411b2dbbf4SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 21421b2dbbf4SNamhyung Kim advance_hpp(&hpp, ret); 21431b2dbbf4SNamhyung Kim 2144d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 2145d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 21461b2dbbf4SNamhyung Kim } 2147d0506edbSNamhyung Kim 214813c230abSArnaldo Carvalho de Melo strim(s); 214913c230abSArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", s); 2150d0506edbSNamhyung Kim 2151d0506edbSNamhyung Kim if (he->leaf && folded_sign == '-') { 2152d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 2153d0506edbSNamhyung Kim he->depth + 1); 2154d0506edbSNamhyung Kim } 2155aff3f3f6SArnaldo Carvalho de Melo 2156aff3f3f6SArnaldo Carvalho de Melo return printed; 2157aff3f3f6SArnaldo Carvalho de Melo } 2158aff3f3f6SArnaldo Carvalho de Melo 2159aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 2160aff3f3f6SArnaldo Carvalho de Melo { 2161064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 2162064f1981SNamhyung Kim browser->min_pcnt); 2163aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 2164aff3f3f6SArnaldo Carvalho de Melo 2165aff3f3f6SArnaldo Carvalho de Melo while (nd) { 2166aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 2167aff3f3f6SArnaldo Carvalho de Melo 2168d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 2169d0506edbSNamhyung Kim printed += hist_browser__fprintf_hierarchy_entry(browser, 2170d0506edbSNamhyung Kim h, fp, 2171325a6283SNamhyung Kim h->depth); 2172d0506edbSNamhyung Kim } else { 2173aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 2174d0506edbSNamhyung Kim } 2175d0506edbSNamhyung Kim 2176d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 2177d0506edbSNamhyung Kim browser->min_pcnt); 2178aff3f3f6SArnaldo Carvalho de Melo } 2179aff3f3f6SArnaldo Carvalho de Melo 2180aff3f3f6SArnaldo Carvalho de Melo return printed; 2181aff3f3f6SArnaldo Carvalho de Melo } 2182aff3f3f6SArnaldo Carvalho de Melo 2183aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 2184aff3f3f6SArnaldo Carvalho de Melo { 2185aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 2186aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 2187aff3f3f6SArnaldo Carvalho de Melo 2188aff3f3f6SArnaldo Carvalho de Melo while (1) { 2189aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 2190aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 2191aff3f3f6SArnaldo Carvalho de Melo break; 2192aff3f3f6SArnaldo Carvalho de Melo /* 2193aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 2194aff3f3f6SArnaldo Carvalho de Melo */ 2195aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 2196aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 2197aff3f3f6SArnaldo Carvalho de Melo return -1; 2198aff3f3f6SArnaldo Carvalho de Melo } 2199aff3f3f6SArnaldo Carvalho de Melo } 2200aff3f3f6SArnaldo Carvalho de Melo 2201aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 2202aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 2203aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 2204c8b5f2c9SArnaldo Carvalho de Melo const char *err = str_error_r(errno, bf, sizeof(bf)); 22054cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 2206aff3f3f6SArnaldo Carvalho de Melo return -1; 2207aff3f3f6SArnaldo Carvalho de Melo } 2208aff3f3f6SArnaldo Carvalho de Melo 2209aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 2210aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 2211aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 2212aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 2213aff3f3f6SArnaldo Carvalho de Melo 2214aff3f3f6SArnaldo Carvalho de Melo return 0; 2215aff3f3f6SArnaldo Carvalho de Melo } 2216aff3f3f6SArnaldo Carvalho de Melo 2217fcd86426SJiri Olsa void hist_browser__init(struct hist_browser *browser, 2218fcd86426SJiri Olsa struct hists *hists) 2219aca7a94dSNamhyung Kim { 2220b1c7a8f7SJiri Olsa struct perf_hpp_fmt *fmt; 2221b1c7a8f7SJiri Olsa 222205e8b080SArnaldo Carvalho de Melo browser->hists = hists; 222305e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 2224357cfff1SArnaldo Carvalho de Melo browser->b.refresh_dimensions = hist_browser__refresh_dimensions; 222505e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 222605e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 2227c8302367SJiri Olsa browser->show_headers = symbol_conf.show_hist_headers; 2228ef9ff601SArnaldo Carvalho de Melo hist_browser__set_title_space(browser); 2229b1c7a8f7SJiri Olsa 22308a06b0beSNamhyung Kim if (symbol_conf.report_hierarchy) { 22318a06b0beSNamhyung Kim struct perf_hpp_list_node *fmt_node; 22328a06b0beSNamhyung Kim 22338a06b0beSNamhyung Kim /* count overhead columns (in the first node) */ 22348a06b0beSNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 22358a06b0beSNamhyung Kim struct perf_hpp_list_node, list); 22368a06b0beSNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) 22378a06b0beSNamhyung Kim ++browser->b.columns; 22388a06b0beSNamhyung Kim 22398a06b0beSNamhyung Kim /* add a single column for whole hierarchy sort keys*/ 22408a06b0beSNamhyung Kim ++browser->b.columns; 22418a06b0beSNamhyung Kim } else { 2242e3b60bc9SNamhyung Kim hists__for_each_format(hists, fmt) 2243b1c7a8f7SJiri Olsa ++browser->b.columns; 22448a06b0beSNamhyung Kim } 2245e3b60bc9SNamhyung Kim 2246e3b60bc9SNamhyung Kim hists__reset_column_width(hists); 2247aca7a94dSNamhyung Kim } 2248aca7a94dSNamhyung Kim 2249fcd86426SJiri Olsa struct hist_browser *hist_browser__new(struct hists *hists) 2250fcd86426SJiri Olsa { 2251fcd86426SJiri Olsa struct hist_browser *browser = zalloc(sizeof(*browser)); 2252fcd86426SJiri Olsa 2253fcd86426SJiri Olsa if (browser) 2254fcd86426SJiri Olsa hist_browser__init(browser, hists); 2255fcd86426SJiri Olsa 225605e8b080SArnaldo Carvalho de Melo return browser; 2257aca7a94dSNamhyung Kim } 2258aca7a94dSNamhyung Kim 2259a6ec894dSJiri Olsa static struct hist_browser * 226032dcd021SJiri Olsa perf_evsel_browser__new(struct evsel *evsel, 2261a6ec894dSJiri Olsa struct hist_browser_timer *hbt, 2262cd0cccbaSArnaldo Carvalho de Melo struct perf_env *env, 2263cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *annotation_opts) 2264a6ec894dSJiri Olsa { 2265a6ec894dSJiri Olsa struct hist_browser *browser = hist_browser__new(evsel__hists(evsel)); 2266a6ec894dSJiri Olsa 2267a6ec894dSJiri Olsa if (browser) { 2268a6ec894dSJiri Olsa browser->hbt = hbt; 2269a6ec894dSJiri Olsa browser->env = env; 2270f016d24aSArnaldo Carvalho de Melo browser->title = hists_browser__scnprintf_title; 2271cd0cccbaSArnaldo Carvalho de Melo browser->annotation_opts = annotation_opts; 2272a6ec894dSJiri Olsa } 2273a6ec894dSJiri Olsa return browser; 2274a6ec894dSJiri Olsa } 2275a6ec894dSJiri Olsa 2276dabd2012SJiri Olsa void hist_browser__delete(struct hist_browser *browser) 2277aca7a94dSNamhyung Kim { 227805e8b080SArnaldo Carvalho de Melo free(browser); 2279aca7a94dSNamhyung Kim } 2280aca7a94dSNamhyung Kim 228105e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 2282aca7a94dSNamhyung Kim { 228305e8b080SArnaldo Carvalho de Melo return browser->he_selection; 2284aca7a94dSNamhyung Kim } 2285aca7a94dSNamhyung Kim 228605e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 2287aca7a94dSNamhyung Kim { 228805e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 2289aca7a94dSNamhyung Kim } 2290aca7a94dSNamhyung Kim 2291d61cbb85SWei Li static struct res_sample *hist_browser__selected_res_sample(struct hist_browser *browser) 2292d61cbb85SWei Li { 2293d61cbb85SWei Li return browser->he_selection ? browser->he_selection->res_samples : NULL; 2294d61cbb85SWei Li } 2295d61cbb85SWei Li 22961e378ebdSTaeung Song /* Check whether the browser is for 'top' or 'report' */ 22971e378ebdSTaeung Song static inline bool is_report_browser(void *timer) 22981e378ebdSTaeung Song { 22991e378ebdSTaeung Song return timer == NULL; 23001e378ebdSTaeung Song } 23011e378ebdSTaeung Song 2302967a464aSArnaldo Carvalho de Melo static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size) 2303967a464aSArnaldo Carvalho de Melo { 2304967a464aSArnaldo Carvalho de Melo struct hist_browser_timer *hbt = browser->hbt; 2305967a464aSArnaldo Carvalho de Melo int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt)); 2306967a464aSArnaldo Carvalho de Melo 23071e378ebdSTaeung Song if (!is_report_browser(hbt)) { 23081e378ebdSTaeung Song struct perf_top *top = hbt->arg; 23091e378ebdSTaeung Song 2310d24e3c98SJiri Olsa printed += scnprintf(bf + printed, size - printed, 2311d24e3c98SJiri Olsa " lost: %" PRIu64 "/%" PRIu64, 2312d24e3c98SJiri Olsa top->lost, top->lost_total); 2313d24e3c98SJiri Olsa 231497f7e0b3SJiri Olsa printed += scnprintf(bf + printed, size - printed, 231597f7e0b3SJiri Olsa " drop: %" PRIu64 "/%" PRIu64, 231697f7e0b3SJiri Olsa top->drop, top->drop_total); 231797f7e0b3SJiri Olsa 23181e378ebdSTaeung Song if (top->zero) 23191e378ebdSTaeung Song printed += scnprintf(bf + printed, size - printed, " [z]"); 23208aa5c8edSJiri Olsa 23218aa5c8edSJiri Olsa perf_top__reset_sample_counters(top); 23221e378ebdSTaeung Song } 23231e378ebdSTaeung Song 23248aa5c8edSJiri Olsa 2325aca7a94dSNamhyung Kim return printed; 2326aca7a94dSNamhyung Kim } 2327aca7a94dSNamhyung Kim 2328aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 2329aca7a94dSNamhyung Kim { 2330aca7a94dSNamhyung Kim int i; 2331aca7a94dSNamhyung Kim 233204662523SArnaldo Carvalho de Melo for (i = 0; i < n; ++i) 233304662523SArnaldo Carvalho de Melo zfree(&options[i]); 2334aca7a94dSNamhyung Kim } 2335aca7a94dSNamhyung Kim 2336341487abSFeng Tang /* 2337341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 2338341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 2339341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 2340341487abSFeng Tang */ 2341341487abSFeng Tang static bool is_input_name_malloced = false; 2342341487abSFeng Tang 2343341487abSFeng Tang static int switch_data_file(void) 2344341487abSFeng Tang { 2345341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 2346341487abSFeng Tang DIR *pwd_dir; 2347341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 2348341487abSFeng Tang struct dirent *dent; 2349341487abSFeng Tang 2350341487abSFeng Tang pwd = getenv("PWD"); 2351341487abSFeng Tang if (!pwd) 2352341487abSFeng Tang return ret; 2353341487abSFeng Tang 2354341487abSFeng Tang pwd_dir = opendir(pwd); 2355341487abSFeng Tang if (!pwd_dir) 2356341487abSFeng Tang return ret; 2357341487abSFeng Tang 2358341487abSFeng Tang memset(options, 0, sizeof(options)); 23593ef5b402SChangbin Du memset(abs_path, 0, sizeof(abs_path)); 2360341487abSFeng Tang 2361341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 2362341487abSFeng Tang char path[PATH_MAX]; 2363341487abSFeng Tang u64 magic; 2364341487abSFeng Tang char *name = dent->d_name; 2365341487abSFeng Tang FILE *file; 2366341487abSFeng Tang 2367341487abSFeng Tang if (!(dent->d_type == DT_REG)) 2368341487abSFeng Tang continue; 2369341487abSFeng Tang 2370341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 2371341487abSFeng Tang 2372341487abSFeng Tang file = fopen(path, "r"); 2373341487abSFeng Tang if (!file) 2374341487abSFeng Tang continue; 2375341487abSFeng Tang 2376341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 2377341487abSFeng Tang goto close_file_and_continue; 2378341487abSFeng Tang 2379341487abSFeng Tang if (is_perf_magic(magic)) { 2380341487abSFeng Tang options[nr_options] = strdup(name); 2381341487abSFeng Tang if (!options[nr_options]) 2382341487abSFeng Tang goto close_file_and_continue; 2383341487abSFeng Tang 2384341487abSFeng Tang abs_path[nr_options] = strdup(path); 2385341487abSFeng Tang if (!abs_path[nr_options]) { 238674cf249dSArnaldo Carvalho de Melo zfree(&options[nr_options]); 2387341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 2388341487abSFeng Tang fclose(file); 2389341487abSFeng Tang break; 2390341487abSFeng Tang } 2391341487abSFeng Tang 2392341487abSFeng Tang nr_options++; 2393341487abSFeng Tang } 2394341487abSFeng Tang 2395341487abSFeng Tang close_file_and_continue: 2396341487abSFeng Tang fclose(file); 2397341487abSFeng Tang if (nr_options >= 32) { 2398341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 2399341487abSFeng Tang "Only the first 32 files will be listed.\n"); 2400341487abSFeng Tang break; 2401341487abSFeng Tang } 2402341487abSFeng Tang } 2403341487abSFeng Tang closedir(pwd_dir); 2404341487abSFeng Tang 2405341487abSFeng Tang if (nr_options) { 2406d0712656SArnaldo Carvalho de Melo choice = ui__popup_menu(nr_options, options, NULL); 2407341487abSFeng Tang if (choice < nr_options && choice >= 0) { 2408341487abSFeng Tang tmp = strdup(abs_path[choice]); 2409341487abSFeng Tang if (tmp) { 2410341487abSFeng Tang if (is_input_name_malloced) 2411341487abSFeng Tang free((void *)input_name); 2412341487abSFeng Tang input_name = tmp; 2413341487abSFeng Tang is_input_name_malloced = true; 2414341487abSFeng Tang ret = 0; 2415341487abSFeng Tang } else 2416341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 2417341487abSFeng Tang } 2418341487abSFeng Tang } 2419341487abSFeng Tang 2420341487abSFeng Tang free_popup_options(options, nr_options); 2421341487abSFeng Tang free_popup_options(abs_path, nr_options); 2422341487abSFeng Tang return ret; 2423341487abSFeng Tang } 2424341487abSFeng Tang 2425ea7cd592SNamhyung Kim struct popup_action { 24261d6c49dfSAndi Kleen unsigned long time; 2427ea7cd592SNamhyung Kim struct thread *thread; 2428ea7cd592SNamhyung Kim struct map_symbol ms; 242984734b06SKan Liang int socket; 243032dcd021SJiri Olsa struct evsel *evsel; 24314968ac8fSAndi Kleen enum rstype rstype; 2432ea7cd592SNamhyung Kim 2433ea7cd592SNamhyung Kim int (*fn)(struct hist_browser *browser, struct popup_action *act); 2434ea7cd592SNamhyung Kim }; 2435ea7cd592SNamhyung Kim 2436bc7cad42SNamhyung Kim static int 2437ea7cd592SNamhyung Kim do_annotate(struct hist_browser *browser, struct popup_action *act) 2438bc7cad42SNamhyung Kim { 243932dcd021SJiri Olsa struct evsel *evsel; 2440bc7cad42SNamhyung Kim struct annotation *notes; 2441bc7cad42SNamhyung Kim struct hist_entry *he; 2442bc7cad42SNamhyung Kim int err; 2443bc7cad42SNamhyung Kim 2444f178fd2dSArnaldo Carvalho de Melo if (!browser->annotation_opts->objdump_path && 2445f178fd2dSArnaldo Carvalho de Melo perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path)) 2446bc7cad42SNamhyung Kim return 0; 2447bc7cad42SNamhyung Kim 2448ea7cd592SNamhyung Kim notes = symbol__annotation(act->ms.sym); 2449bc7cad42SNamhyung Kim if (!notes->src) 2450bc7cad42SNamhyung Kim return 0; 2451bc7cad42SNamhyung Kim 2452848a5e50SJin Yao if (browser->block_evsel) 2453848a5e50SJin Yao evsel = browser->block_evsel; 2454848a5e50SJin Yao else 2455bc7cad42SNamhyung Kim evsel = hists_to_evsel(browser->hists); 2456848a5e50SJin Yao 2457cd0cccbaSArnaldo Carvalho de Melo err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt, 2458cd0cccbaSArnaldo Carvalho de Melo browser->annotation_opts); 2459bc7cad42SNamhyung Kim he = hist_browser__selected_entry(browser); 2460bc7cad42SNamhyung Kim /* 2461bc7cad42SNamhyung Kim * offer option to annotate the other branch source or target 2462bc7cad42SNamhyung Kim * (if they exists) when returning from annotate 2463bc7cad42SNamhyung Kim */ 2464bc7cad42SNamhyung Kim if ((err == 'q' || err == CTRL('c')) && he->branch_info) 2465bc7cad42SNamhyung Kim return 1; 2466bc7cad42SNamhyung Kim 2467bc7cad42SNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 2468bc7cad42SNamhyung Kim if (err) 2469bc7cad42SNamhyung Kim ui_browser__handle_resize(&browser->b); 2470bc7cad42SNamhyung Kim return 0; 2471bc7cad42SNamhyung Kim } 2472bc7cad42SNamhyung Kim 24737b0a0dcbSJin Yao static struct symbol *symbol__new_unresolved(u64 addr, struct map *map) 24747b0a0dcbSJin Yao { 24757b0a0dcbSJin Yao struct annotated_source *src; 24767b0a0dcbSJin Yao struct symbol *sym; 24777b0a0dcbSJin Yao char name[64]; 24787b0a0dcbSJin Yao 24797b0a0dcbSJin Yao snprintf(name, sizeof(name), "%.*" PRIx64, BITS_PER_LONG / 4, addr); 24807b0a0dcbSJin Yao 24817b0a0dcbSJin Yao sym = symbol__new(addr, ANNOTATION_DUMMY_LEN, 0, 0, name); 24827b0a0dcbSJin Yao if (sym) { 24837b0a0dcbSJin Yao src = symbol__hists(sym, 1); 24847b0a0dcbSJin Yao if (!src) { 24857b0a0dcbSJin Yao symbol__delete(sym); 24867b0a0dcbSJin Yao return NULL; 24877b0a0dcbSJin Yao } 24887b0a0dcbSJin Yao 24897b0a0dcbSJin Yao dso__insert_symbol(map->dso, sym); 24907b0a0dcbSJin Yao } 24917b0a0dcbSJin Yao 24927b0a0dcbSJin Yao return sym; 24937b0a0dcbSJin Yao } 24947b0a0dcbSJin Yao 2495bc7cad42SNamhyung Kim static int 2496ea7cd592SNamhyung Kim add_annotate_opt(struct hist_browser *browser __maybe_unused, 2497ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 24987b0a0dcbSJin Yao struct map_symbol *ms, 24997b0a0dcbSJin Yao u64 addr) 2500bc7cad42SNamhyung Kim { 25017b0a0dcbSJin Yao if (!ms->map || !ms->map->dso || ms->map->dso->annotate_warned) 25027b0a0dcbSJin Yao return 0; 25037b0a0dcbSJin Yao 25047b0a0dcbSJin Yao if (!ms->sym) 25057b0a0dcbSJin Yao ms->sym = symbol__new_unresolved(addr, ms->map); 25067b0a0dcbSJin Yao 25077b0a0dcbSJin Yao if (ms->sym == NULL || symbol__annotation(ms->sym)->src == NULL) 2508ea7cd592SNamhyung Kim return 0; 2509ea7cd592SNamhyung Kim 2510d46a4cdfSArnaldo Carvalho de Melo if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0) 2511ea7cd592SNamhyung Kim return 0; 2512ea7cd592SNamhyung Kim 2513d46a4cdfSArnaldo Carvalho de Melo act->ms = *ms; 2514ea7cd592SNamhyung Kim act->fn = do_annotate; 2515ea7cd592SNamhyung Kim return 1; 2516ea7cd592SNamhyung Kim } 2517ea7cd592SNamhyung Kim 2518ea7cd592SNamhyung Kim static int 2519ea7cd592SNamhyung Kim do_zoom_thread(struct hist_browser *browser, struct popup_action *act) 2520ea7cd592SNamhyung Kim { 2521ea7cd592SNamhyung Kim struct thread *thread = act->thread; 2522ea7cd592SNamhyung Kim 25237cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 25247cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2525599a2f38SNamhyung Kim return 0; 2526599a2f38SNamhyung Kim 2527bc7cad42SNamhyung Kim if (browser->hists->thread_filter) { 2528bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->thread_filter); 2529bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2530bc7cad42SNamhyung Kim thread__zput(browser->hists->thread_filter); 2531bc7cad42SNamhyung Kim ui_helpline__pop(); 2532bc7cad42SNamhyung Kim } else { 2533fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 25347727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 2535bc7cad42SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 2536bc7cad42SNamhyung Kim thread->tid); 25376962ccb3SNamhyung Kim } else { 25386962ccb3SNamhyung Kim ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"", 25396962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 25406962ccb3SNamhyung Kim } 25416962ccb3SNamhyung Kim 2542bc7cad42SNamhyung Kim browser->hists->thread_filter = thread__get(thread); 2543bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2544bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->thread_filter); 2545bc7cad42SNamhyung Kim } 2546bc7cad42SNamhyung Kim 2547bc7cad42SNamhyung Kim hists__filter_by_thread(browser->hists); 2548bc7cad42SNamhyung Kim hist_browser__reset(browser); 2549bc7cad42SNamhyung Kim return 0; 2550bc7cad42SNamhyung Kim } 2551bc7cad42SNamhyung Kim 2552bc7cad42SNamhyung Kim static int 2553ea7cd592SNamhyung Kim add_thread_opt(struct hist_browser *browser, struct popup_action *act, 2554ea7cd592SNamhyung Kim char **optstr, struct thread *thread) 2555bc7cad42SNamhyung Kim { 25566962ccb3SNamhyung Kim int ret; 25576962ccb3SNamhyung Kim 25587cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 25597cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2560ea7cd592SNamhyung Kim return 0; 2561ea7cd592SNamhyung Kim 2562fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 25636962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s(%d) thread", 2564ea7cd592SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 2565ea7cd592SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 25666962ccb3SNamhyung Kim thread->tid); 25676962ccb3SNamhyung Kim } else { 25686962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s thread", 25696962ccb3SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 25706962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 25716962ccb3SNamhyung Kim } 25726962ccb3SNamhyung Kim if (ret < 0) 2573ea7cd592SNamhyung Kim return 0; 2574ea7cd592SNamhyung Kim 2575ea7cd592SNamhyung Kim act->thread = thread; 2576ea7cd592SNamhyung Kim act->fn = do_zoom_thread; 2577ea7cd592SNamhyung Kim return 1; 2578ea7cd592SNamhyung Kim } 2579ea7cd592SNamhyung Kim 2580632003f4SArnaldo Carvalho de Melo static int hists_browser__zoom_map(struct hist_browser *browser, struct map *map) 2581ea7cd592SNamhyung Kim { 258269849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2583599a2f38SNamhyung Kim return 0; 2584599a2f38SNamhyung Kim 2585bc7cad42SNamhyung Kim if (browser->hists->dso_filter) { 2586bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->dso_filter); 2587bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, false); 2588bc7cad42SNamhyung Kim browser->hists->dso_filter = NULL; 2589bc7cad42SNamhyung Kim ui_helpline__pop(); 2590bc7cad42SNamhyung Kim } else { 25917727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", 2592045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); 2593045b80ddSArnaldo Carvalho de Melo browser->hists->dso_filter = map->dso; 2594bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, true); 2595bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->dso_filter); 2596bc7cad42SNamhyung Kim } 2597bc7cad42SNamhyung Kim 2598bc7cad42SNamhyung Kim hists__filter_by_dso(browser->hists); 2599bc7cad42SNamhyung Kim hist_browser__reset(browser); 2600bc7cad42SNamhyung Kim return 0; 2601bc7cad42SNamhyung Kim } 2602bc7cad42SNamhyung Kim 2603bc7cad42SNamhyung Kim static int 2604632003f4SArnaldo Carvalho de Melo do_zoom_dso(struct hist_browser *browser, struct popup_action *act) 2605632003f4SArnaldo Carvalho de Melo { 2606632003f4SArnaldo Carvalho de Melo return hists_browser__zoom_map(browser, act->ms.map); 2607632003f4SArnaldo Carvalho de Melo } 2608632003f4SArnaldo Carvalho de Melo 2609632003f4SArnaldo Carvalho de Melo static int 2610ea7cd592SNamhyung Kim add_dso_opt(struct hist_browser *browser, struct popup_action *act, 2611045b80ddSArnaldo Carvalho de Melo char **optstr, struct map *map) 2612bc7cad42SNamhyung Kim { 261369849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2614ea7cd592SNamhyung Kim return 0; 2615ea7cd592SNamhyung Kim 2616209f4e70SArnaldo Carvalho de Melo if (asprintf(optstr, "Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)", 2617ea7cd592SNamhyung Kim browser->hists->dso_filter ? "out of" : "into", 2618045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) 2619ea7cd592SNamhyung Kim return 0; 2620ea7cd592SNamhyung Kim 2621045b80ddSArnaldo Carvalho de Melo act->ms.map = map; 2622ea7cd592SNamhyung Kim act->fn = do_zoom_dso; 2623ea7cd592SNamhyung Kim return 1; 2624ea7cd592SNamhyung Kim } 2625ea7cd592SNamhyung Kim 2626d5a599d9SArnaldo Carvalho de Melo static int do_toggle_callchain(struct hist_browser *browser, struct popup_action *act __maybe_unused) 2627d5a599d9SArnaldo Carvalho de Melo { 2628d5a599d9SArnaldo Carvalho de Melo hist_browser__toggle_fold(browser); 2629d5a599d9SArnaldo Carvalho de Melo return 0; 2630d5a599d9SArnaldo Carvalho de Melo } 2631d5a599d9SArnaldo Carvalho de Melo 2632d5a599d9SArnaldo Carvalho de Melo static int add_callchain_toggle_opt(struct hist_browser *browser, struct popup_action *act, char **optstr) 2633d5a599d9SArnaldo Carvalho de Melo { 2634bdc633feSArnaldo Carvalho de Melo char sym_name[512]; 2635d5a599d9SArnaldo Carvalho de Melo 2636bdc633feSArnaldo Carvalho de Melo if (!hist_browser__selection_has_children(browser)) 2637d5a599d9SArnaldo Carvalho de Melo return 0; 2638d5a599d9SArnaldo Carvalho de Melo 2639bdc633feSArnaldo Carvalho de Melo if (asprintf(optstr, "%s [%s] callchain (one level, same as '+' hotkey, use 'e'/'c' for the whole main level entry)", 2640bdc633feSArnaldo Carvalho de Melo hist_browser__selection_unfolded(browser) ? "Collapse" : "Expand", 2641bdc633feSArnaldo Carvalho de Melo hist_browser__selection_sym_name(browser, sym_name, sizeof(sym_name))) < 0) 2642d5a599d9SArnaldo Carvalho de Melo return 0; 2643d5a599d9SArnaldo Carvalho de Melo 2644d5a599d9SArnaldo Carvalho de Melo act->fn = do_toggle_callchain; 2645d5a599d9SArnaldo Carvalho de Melo return 1; 2646d5a599d9SArnaldo Carvalho de Melo } 2647d5a599d9SArnaldo Carvalho de Melo 2648ea7cd592SNamhyung Kim static int 2649ea7cd592SNamhyung Kim do_browse_map(struct hist_browser *browser __maybe_unused, 2650ea7cd592SNamhyung Kim struct popup_action *act) 2651ea7cd592SNamhyung Kim { 2652ea7cd592SNamhyung Kim map__browse(act->ms.map); 2653bc7cad42SNamhyung Kim return 0; 2654bc7cad42SNamhyung Kim } 2655bc7cad42SNamhyung Kim 2656bc7cad42SNamhyung Kim static int 265769849fc5SJiri Olsa add_map_opt(struct hist_browser *browser, 2658ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, struct map *map) 2659ea7cd592SNamhyung Kim { 266069849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2661ea7cd592SNamhyung Kim return 0; 2662ea7cd592SNamhyung Kim 2663ea7cd592SNamhyung Kim if (asprintf(optstr, "Browse map details") < 0) 2664ea7cd592SNamhyung Kim return 0; 2665ea7cd592SNamhyung Kim 2666ea7cd592SNamhyung Kim act->ms.map = map; 2667ea7cd592SNamhyung Kim act->fn = do_browse_map; 2668ea7cd592SNamhyung Kim return 1; 2669ea7cd592SNamhyung Kim } 2670ea7cd592SNamhyung Kim 2671ea7cd592SNamhyung Kim static int 2672bc7cad42SNamhyung Kim do_run_script(struct hist_browser *browser __maybe_unused, 2673ea7cd592SNamhyung Kim struct popup_action *act) 2674bc7cad42SNamhyung Kim { 26751d6c49dfSAndi Kleen char *script_opt; 26761d6c49dfSAndi Kleen int len; 26771d6c49dfSAndi Kleen int n = 0; 2678bc7cad42SNamhyung Kim 26791d6c49dfSAndi Kleen len = 100; 26801d6c49dfSAndi Kleen if (act->thread) 26811d6c49dfSAndi Kleen len += strlen(thread__comm_str(act->thread)); 26821d6c49dfSAndi Kleen else if (act->ms.sym) 26831d6c49dfSAndi Kleen len += strlen(act->ms.sym->name); 26841d6c49dfSAndi Kleen script_opt = malloc(len); 26851d6c49dfSAndi Kleen if (!script_opt) 26861d6c49dfSAndi Kleen return -1; 26871d6c49dfSAndi Kleen 26881d6c49dfSAndi Kleen script_opt[0] = 0; 2689ea7cd592SNamhyung Kim if (act->thread) { 26901d6c49dfSAndi Kleen n = scnprintf(script_opt, len, " -c %s ", 2691ea7cd592SNamhyung Kim thread__comm_str(act->thread)); 2692ea7cd592SNamhyung Kim } else if (act->ms.sym) { 26931d6c49dfSAndi Kleen n = scnprintf(script_opt, len, " -S %s ", 2694ea7cd592SNamhyung Kim act->ms.sym->name); 2695bc7cad42SNamhyung Kim } 2696bc7cad42SNamhyung Kim 26971d6c49dfSAndi Kleen if (act->time) { 26981d6c49dfSAndi Kleen char start[32], end[32]; 26991d6c49dfSAndi Kleen unsigned long starttime = act->time; 27001d6c49dfSAndi Kleen unsigned long endtime = act->time + symbol_conf.time_quantum; 27011d6c49dfSAndi Kleen 27021d6c49dfSAndi Kleen if (starttime == endtime) { /* Display 1ms as fallback */ 27031d6c49dfSAndi Kleen starttime -= 1*NSEC_PER_MSEC; 27041d6c49dfSAndi Kleen endtime += 1*NSEC_PER_MSEC; 27051d6c49dfSAndi Kleen } 27061d6c49dfSAndi Kleen timestamp__scnprintf_usec(starttime, start, sizeof start); 27071d6c49dfSAndi Kleen timestamp__scnprintf_usec(endtime, end, sizeof end); 27081d6c49dfSAndi Kleen n += snprintf(script_opt + n, len - n, " --time %s,%s", start, end); 27091d6c49dfSAndi Kleen } 27101d6c49dfSAndi Kleen 27116f3da20eSAndi Kleen script_browse(script_opt, act->evsel); 27121d6c49dfSAndi Kleen free(script_opt); 2713bc7cad42SNamhyung Kim return 0; 2714bc7cad42SNamhyung Kim } 2715bc7cad42SNamhyung Kim 2716bc7cad42SNamhyung Kim static int 27174968ac8fSAndi Kleen do_res_sample_script(struct hist_browser *browser __maybe_unused, 27184968ac8fSAndi Kleen struct popup_action *act) 27194968ac8fSAndi Kleen { 27204968ac8fSAndi Kleen struct hist_entry *he; 27214968ac8fSAndi Kleen 27224968ac8fSAndi Kleen he = hist_browser__selected_entry(browser); 27234968ac8fSAndi Kleen res_sample_browse(he->res_samples, he->num_res, act->evsel, act->rstype); 27244968ac8fSAndi Kleen return 0; 27254968ac8fSAndi Kleen } 27264968ac8fSAndi Kleen 27274968ac8fSAndi Kleen static int 27281d6c49dfSAndi Kleen add_script_opt_2(struct hist_browser *browser __maybe_unused, 2729ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 27301d6c49dfSAndi Kleen struct thread *thread, struct symbol *sym, 273132dcd021SJiri Olsa struct evsel *evsel, const char *tstr) 2732ea7cd592SNamhyung Kim { 27331d6c49dfSAndi Kleen 2734ea7cd592SNamhyung Kim if (thread) { 27351d6c49dfSAndi Kleen if (asprintf(optstr, "Run scripts for samples of thread [%s]%s", 27361d6c49dfSAndi Kleen thread__comm_str(thread), tstr) < 0) 2737ea7cd592SNamhyung Kim return 0; 2738ea7cd592SNamhyung Kim } else if (sym) { 27391d6c49dfSAndi Kleen if (asprintf(optstr, "Run scripts for samples of symbol [%s]%s", 27401d6c49dfSAndi Kleen sym->name, tstr) < 0) 2741ea7cd592SNamhyung Kim return 0; 2742ea7cd592SNamhyung Kim } else { 27431d6c49dfSAndi Kleen if (asprintf(optstr, "Run scripts for all samples%s", tstr) < 0) 2744ea7cd592SNamhyung Kim return 0; 2745ea7cd592SNamhyung Kim } 2746ea7cd592SNamhyung Kim 2747ea7cd592SNamhyung Kim act->thread = thread; 2748ea7cd592SNamhyung Kim act->ms.sym = sym; 27496f3da20eSAndi Kleen act->evsel = evsel; 2750ea7cd592SNamhyung Kim act->fn = do_run_script; 2751ea7cd592SNamhyung Kim return 1; 2752ea7cd592SNamhyung Kim } 2753ea7cd592SNamhyung Kim 2754ea7cd592SNamhyung Kim static int 27551d6c49dfSAndi Kleen add_script_opt(struct hist_browser *browser, 27561d6c49dfSAndi Kleen struct popup_action *act, char **optstr, 27576f3da20eSAndi Kleen struct thread *thread, struct symbol *sym, 275832dcd021SJiri Olsa struct evsel *evsel) 27591d6c49dfSAndi Kleen { 27601d6c49dfSAndi Kleen int n, j; 27611d6c49dfSAndi Kleen struct hist_entry *he; 27621d6c49dfSAndi Kleen 27636f3da20eSAndi Kleen n = add_script_opt_2(browser, act, optstr, thread, sym, evsel, ""); 27641d6c49dfSAndi Kleen 27651d6c49dfSAndi Kleen he = hist_browser__selected_entry(browser); 27661d6c49dfSAndi Kleen if (sort_order && strstr(sort_order, "time")) { 27671d6c49dfSAndi Kleen char tstr[128]; 27681d6c49dfSAndi Kleen 27691d6c49dfSAndi Kleen optstr++; 27701d6c49dfSAndi Kleen act++; 27711d6c49dfSAndi Kleen j = sprintf(tstr, " in "); 27721d6c49dfSAndi Kleen j += timestamp__scnprintf_usec(he->time, tstr + j, 27731d6c49dfSAndi Kleen sizeof tstr - j); 27741d6c49dfSAndi Kleen j += sprintf(tstr + j, "-"); 27751d6c49dfSAndi Kleen timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum, 27766f3da20eSAndi Kleen tstr + j, sizeof tstr - j); 27771d6c49dfSAndi Kleen n += add_script_opt_2(browser, act, optstr, thread, sym, 27786f3da20eSAndi Kleen evsel, tstr); 27791d6c49dfSAndi Kleen act->time = he->time; 27801d6c49dfSAndi Kleen } 27811d6c49dfSAndi Kleen return n; 27821d6c49dfSAndi Kleen } 27831d6c49dfSAndi Kleen 27841d6c49dfSAndi Kleen static int 27854968ac8fSAndi Kleen add_res_sample_opt(struct hist_browser *browser __maybe_unused, 27864968ac8fSAndi Kleen struct popup_action *act, char **optstr, 27874968ac8fSAndi Kleen struct res_sample *res_sample, 278832dcd021SJiri Olsa struct evsel *evsel, 27894968ac8fSAndi Kleen enum rstype type) 27904968ac8fSAndi Kleen { 27914968ac8fSAndi Kleen if (!res_sample) 27924968ac8fSAndi Kleen return 0; 27934968ac8fSAndi Kleen 27944968ac8fSAndi Kleen if (asprintf(optstr, "Show context for individual samples %s", 27954968ac8fSAndi Kleen type == A_ASM ? "with assembler" : 27964968ac8fSAndi Kleen type == A_SOURCE ? "with source" : "") < 0) 27974968ac8fSAndi Kleen return 0; 27984968ac8fSAndi Kleen 27994968ac8fSAndi Kleen act->fn = do_res_sample_script; 28004968ac8fSAndi Kleen act->evsel = evsel; 28014968ac8fSAndi Kleen act->rstype = type; 28024968ac8fSAndi Kleen return 1; 28034968ac8fSAndi Kleen } 28044968ac8fSAndi Kleen 28054968ac8fSAndi Kleen static int 2806ea7cd592SNamhyung Kim do_switch_data(struct hist_browser *browser __maybe_unused, 2807ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2808bc7cad42SNamhyung Kim { 2809bc7cad42SNamhyung Kim if (switch_data_file()) { 2810bc7cad42SNamhyung Kim ui__warning("Won't switch the data files due to\n" 2811bc7cad42SNamhyung Kim "no valid data file get selected!\n"); 2812ea7cd592SNamhyung Kim return 0; 2813bc7cad42SNamhyung Kim } 2814bc7cad42SNamhyung Kim 2815bc7cad42SNamhyung Kim return K_SWITCH_INPUT_DATA; 2816bc7cad42SNamhyung Kim } 2817bc7cad42SNamhyung Kim 2818ea7cd592SNamhyung Kim static int 2819ea7cd592SNamhyung Kim add_switch_opt(struct hist_browser *browser, 2820ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2821ea7cd592SNamhyung Kim { 2822ea7cd592SNamhyung Kim if (!is_report_browser(browser->hbt)) 2823ea7cd592SNamhyung Kim return 0; 2824ea7cd592SNamhyung Kim 2825ea7cd592SNamhyung Kim if (asprintf(optstr, "Switch to another data file in PWD") < 0) 2826ea7cd592SNamhyung Kim return 0; 2827ea7cd592SNamhyung Kim 2828ea7cd592SNamhyung Kim act->fn = do_switch_data; 2829ea7cd592SNamhyung Kim return 1; 2830ea7cd592SNamhyung Kim } 2831ea7cd592SNamhyung Kim 2832ea7cd592SNamhyung Kim static int 2833ea7cd592SNamhyung Kim do_exit_browser(struct hist_browser *browser __maybe_unused, 2834ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2835ea7cd592SNamhyung Kim { 2836ea7cd592SNamhyung Kim return 0; 2837ea7cd592SNamhyung Kim } 2838ea7cd592SNamhyung Kim 2839ea7cd592SNamhyung Kim static int 2840ea7cd592SNamhyung Kim add_exit_opt(struct hist_browser *browser __maybe_unused, 2841ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2842ea7cd592SNamhyung Kim { 2843ea7cd592SNamhyung Kim if (asprintf(optstr, "Exit") < 0) 2844ea7cd592SNamhyung Kim return 0; 2845ea7cd592SNamhyung Kim 2846ea7cd592SNamhyung Kim act->fn = do_exit_browser; 2847ea7cd592SNamhyung Kim return 1; 2848ea7cd592SNamhyung Kim } 2849ea7cd592SNamhyung Kim 285084734b06SKan Liang static int 285184734b06SKan Liang do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 285284734b06SKan Liang { 285335a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || act->socket < 0) 2854599a2f38SNamhyung Kim return 0; 2855599a2f38SNamhyung Kim 285684734b06SKan Liang if (browser->hists->socket_filter > -1) { 285784734b06SKan Liang pstack__remove(browser->pstack, &browser->hists->socket_filter); 285884734b06SKan Liang browser->hists->socket_filter = -1; 285984734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, false); 286084734b06SKan Liang } else { 286184734b06SKan Liang browser->hists->socket_filter = act->socket; 286284734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, true); 286384734b06SKan Liang pstack__push(browser->pstack, &browser->hists->socket_filter); 286484734b06SKan Liang } 286584734b06SKan Liang 286684734b06SKan Liang hists__filter_by_socket(browser->hists); 286784734b06SKan Liang hist_browser__reset(browser); 286884734b06SKan Liang return 0; 286984734b06SKan Liang } 287084734b06SKan Liang 287184734b06SKan Liang static int 287284734b06SKan Liang add_socket_opt(struct hist_browser *browser, struct popup_action *act, 287384734b06SKan Liang char **optstr, int socket_id) 287484734b06SKan Liang { 287535a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || socket_id < 0) 287684734b06SKan Liang return 0; 287784734b06SKan Liang 287884734b06SKan Liang if (asprintf(optstr, "Zoom %s Processor Socket %d", 287984734b06SKan Liang (browser->hists->socket_filter > -1) ? "out of" : "into", 288084734b06SKan Liang socket_id) < 0) 288184734b06SKan Liang return 0; 288284734b06SKan Liang 288384734b06SKan Liang act->socket = socket_id; 288484734b06SKan Liang act->fn = do_zoom_socket; 288584734b06SKan Liang return 1; 288684734b06SKan Liang } 288784734b06SKan Liang 2888112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb) 2889064f1981SNamhyung Kim { 2890064f1981SNamhyung Kim u64 nr_entries = 0; 28912eb3d689SDavidlohr Bueso struct rb_node *nd = rb_first_cached(&hb->hists->entries); 2892064f1981SNamhyung Kim 2893f5b763feSNamhyung Kim if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) { 2894268397cbSNamhyung Kim hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 2895268397cbSNamhyung Kim return; 2896268397cbSNamhyung Kim } 2897268397cbSNamhyung Kim 289814135663SNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2899064f1981SNamhyung Kim nr_entries++; 2900f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd); 2901064f1981SNamhyung Kim } 2902064f1981SNamhyung Kim 2903112f761fSNamhyung Kim hb->nr_non_filtered_entries = nr_entries; 2904f5b763feSNamhyung Kim hb->nr_hierarchy_entries = nr_entries; 2905064f1981SNamhyung Kim } 2906341487abSFeng Tang 2907b62e8dfcSNamhyung Kim static void hist_browser__update_percent_limit(struct hist_browser *hb, 2908b62e8dfcSNamhyung Kim double percent) 2909b62e8dfcSNamhyung Kim { 2910b62e8dfcSNamhyung Kim struct hist_entry *he; 29112eb3d689SDavidlohr Bueso struct rb_node *nd = rb_first_cached(&hb->hists->entries); 2912b62e8dfcSNamhyung Kim u64 total = hists__total_period(hb->hists); 2913b62e8dfcSNamhyung Kim u64 min_callchain_hits = total * (percent / 100); 2914b62e8dfcSNamhyung Kim 2915b62e8dfcSNamhyung Kim hb->min_pcnt = callchain_param.min_percent = percent; 2916b62e8dfcSNamhyung Kim 2917b62e8dfcSNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2918b62e8dfcSNamhyung Kim he = rb_entry(nd, struct hist_entry, rb_node); 2919b62e8dfcSNamhyung Kim 292079dded87SNamhyung Kim if (he->has_no_entry) { 292179dded87SNamhyung Kim he->has_no_entry = false; 292279dded87SNamhyung Kim he->nr_rows = 0; 292379dded87SNamhyung Kim } 292479dded87SNamhyung Kim 2925fabd37b8SArnaldo Carvalho de Melo if (!he->leaf || !hist_entry__has_callchains(he) || !symbol_conf.use_callchain) 2926d0506edbSNamhyung Kim goto next; 2927d0506edbSNamhyung Kim 2928b62e8dfcSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) { 2929b62e8dfcSNamhyung Kim total = he->stat.period; 2930b62e8dfcSNamhyung Kim 2931b62e8dfcSNamhyung Kim if (symbol_conf.cumulate_callchain) 2932b62e8dfcSNamhyung Kim total = he->stat_acc->period; 2933b62e8dfcSNamhyung Kim 2934b62e8dfcSNamhyung Kim min_callchain_hits = total * (percent / 100); 2935b62e8dfcSNamhyung Kim } 2936b62e8dfcSNamhyung Kim 2937b62e8dfcSNamhyung Kim callchain_param.sort(&he->sorted_chain, he->callchain, 2938b62e8dfcSNamhyung Kim min_callchain_hits, &callchain_param); 2939b62e8dfcSNamhyung Kim 2940d0506edbSNamhyung Kim next: 2941201fde73SNamhyung Kim nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 2942d0506edbSNamhyung Kim 2943b62e8dfcSNamhyung Kim /* force to re-evaluate folding state of callchains */ 2944b62e8dfcSNamhyung Kim he->init_have_children = false; 2945492b1010SNamhyung Kim hist_entry__set_folding(he, hb, false); 2946b62e8dfcSNamhyung Kim } 2947b62e8dfcSNamhyung Kim } 2948b62e8dfcSNamhyung Kim 294956933029SArnaldo Carvalho de Melo static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *helpline, 295056933029SArnaldo Carvalho de Melo bool left_exits, struct hist_browser_timer *hbt, float min_pcnt, 295156933029SArnaldo Carvalho de Melo struct perf_env *env, bool warn_lost_event, 2952cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *annotation_opts) 2953aca7a94dSNamhyung Kim { 29544ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 2955cd0cccbaSArnaldo Carvalho de Melo struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts); 2956ceb75476SLeo Yan struct branch_info *bi = NULL; 2957f2b487dbSNamhyung Kim #define MAX_OPTIONS 16 2958f2b487dbSNamhyung Kim char *options[MAX_OPTIONS]; 2959ea7cd592SNamhyung Kim struct popup_action actions[MAX_OPTIONS]; 2960aca7a94dSNamhyung Kim int nr_options = 0; 2961aca7a94dSNamhyung Kim int key = -1; 296286449b12SSong Liu char buf[128]; 29639783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 2964aca7a94dSNamhyung Kim 2965e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 2966e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 2967e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 2968e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 29696a02f06eSAndi Kleen "q/ESC/CTRL+C Exit browser or go back to previous screen\n\n" \ 2970e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 2971e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 2972e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 29737727a925SArnaldo Carvalho de Melo "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \ 29747727a925SArnaldo Carvalho de Melo "ESC Zoom out\n" \ 29759218a913SArnaldo Carvalho de Melo "+ Expand/Collapse one callchain level\n" \ 2976e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 2977e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 2978e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 2979e6d6abfcSArnaldo Carvalho de Melo "e Expand/Collapse main entry callchains\n" \ 2980e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 2981105eb30fSNamhyung Kim "F Toggle percentage of filtered entries\n" \ 2982025bf7eaSArnaldo Carvalho de Melo "H Display column headers\n" \ 2983209f4e70SArnaldo Carvalho de Melo "k Zoom into the kernel map\n" \ 2984b62e8dfcSNamhyung Kim "L Change percent limit\n" \ 298531eb4360SNamhyung Kim "m Display context menu\n" \ 298684734b06SKan Liang "S Zoom into current Processor Socket\n" \ 2987e8e684a5SNamhyung Kim 2988e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 298949b8e2beSRasmus Villemoes static const char report_help[] = HIST_BROWSER_HELP_COMMON 29906dd60135SNamhyung Kim "i Show header information\n" 2991e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2992e8e684a5SNamhyung Kim "r Run available scripts\n" 2993e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 2994e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2995e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 2996dbddf174SJin Yao "/ Filter symbol by name\n" 2997dbddf174SJin Yao "0-9 Sort by event n in group"; 299849b8e2beSRasmus Villemoes static const char top_help[] = HIST_BROWSER_HELP_COMMON 2999e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 3000e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 3001e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 300242337a22SNamhyung Kim "z Toggle zeroing of samples\n" 3003fbb7997eSArnaldo Carvalho de Melo "f Enable/Disable events\n" 3004e8e684a5SNamhyung Kim "/ Filter symbol by name"; 3005e8e684a5SNamhyung Kim 3006aca7a94dSNamhyung Kim if (browser == NULL) 3007aca7a94dSNamhyung Kim return -1; 3008aca7a94dSNamhyung Kim 3009ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 3010ed426915SNamhyung Kim SLang_reset_tty(); 3011ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 3012ed426915SNamhyung Kim 301303905048SNamhyung Kim if (min_pcnt) 3014064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 3015112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 3016064f1981SNamhyung Kim 301784734b06SKan Liang browser->pstack = pstack__new(3); 301801f00a1cSNamhyung Kim if (browser->pstack == NULL) 3019aca7a94dSNamhyung Kim goto out; 3020aca7a94dSNamhyung Kim 3021aca7a94dSNamhyung Kim ui_helpline__push(helpline); 3022aca7a94dSNamhyung Kim 3023aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 3024ea7cd592SNamhyung Kim memset(actions, 0, sizeof(actions)); 3025aca7a94dSNamhyung Kim 30265b591669SNamhyung Kim if (symbol_conf.col_width_list_str) 30275b591669SNamhyung Kim perf_hpp__set_user_width(symbol_conf.col_width_list_str); 30285b591669SNamhyung Kim 30295c959b6dSArnaldo Carvalho de Melo if (!is_report_browser(hbt)) 30305c959b6dSArnaldo Carvalho de Melo browser->b.no_samples_msg = "Collecting samples..."; 30315c959b6dSArnaldo Carvalho de Melo 3032aca7a94dSNamhyung Kim while (1) { 3033f3b623b8SArnaldo Carvalho de Melo struct thread *thread = NULL; 3034045b80ddSArnaldo Carvalho de Melo struct map *map = NULL; 30354c8b9c0fSArnaldo Carvalho de Melo int choice; 303684734b06SKan Liang int socked_id = -1; 3037aca7a94dSNamhyung Kim 30384c8b9c0fSArnaldo Carvalho de Melo key = 0; // reset key 30394c8b9c0fSArnaldo Carvalho de Melo do_hotkey: // key came straight from options ui__popup_menu() 30404c8b9c0fSArnaldo Carvalho de Melo choice = nr_options = 0; 30414c8b9c0fSArnaldo Carvalho de Melo key = hist_browser__run(browser, helpline, warn_lost_event, key); 3042aca7a94dSNamhyung Kim 3043aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 3044aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 3045045b80ddSArnaldo Carvalho de Melo map = browser->selection->map; 304684734b06SKan Liang socked_id = browser->he_selection->socket; 3047aca7a94dSNamhyung Kim } 3048aca7a94dSNamhyung Kim switch (key) { 3049aca7a94dSNamhyung Kim case K_TAB: 3050aca7a94dSNamhyung Kim case K_UNTAB: 3051aca7a94dSNamhyung Kim if (nr_events == 1) 3052aca7a94dSNamhyung Kim continue; 3053aca7a94dSNamhyung Kim /* 3054aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 3055aca7a94dSNamhyung Kim * go to the next or previous 3056aca7a94dSNamhyung Kim */ 3057aca7a94dSNamhyung Kim goto out_free_stack; 3058dbddf174SJin Yao case '0' ... '9': 3059dbddf174SJin Yao if (!symbol_conf.event_group || 3060dbddf174SJin Yao evsel->core.nr_members < 2) { 3061dbddf174SJin Yao snprintf(buf, sizeof(buf), 3062dbddf174SJin Yao "Sort by index only available with group events!"); 3063dbddf174SJin Yao helpline = buf; 3064dbddf174SJin Yao continue; 3065dbddf174SJin Yao } 3066dbddf174SJin Yao 3067dbddf174SJin Yao if (key - '0' == symbol_conf.group_sort_idx) 3068dbddf174SJin Yao continue; 3069dbddf174SJin Yao 3070dbddf174SJin Yao symbol_conf.group_sort_idx = key - '0'; 3071dbddf174SJin Yao 3072dbddf174SJin Yao if (symbol_conf.group_sort_idx >= evsel->core.nr_members) { 3073dbddf174SJin Yao snprintf(buf, sizeof(buf), 3074dbddf174SJin Yao "Max event group index to sort is %d (index from 0 to %d)", 3075dbddf174SJin Yao evsel->core.nr_members - 1, 3076dbddf174SJin Yao evsel->core.nr_members - 1); 3077dbddf174SJin Yao helpline = buf; 3078dbddf174SJin Yao continue; 3079dbddf174SJin Yao } 3080dbddf174SJin Yao 3081dbddf174SJin Yao key = K_RELOAD; 3082dbddf174SJin Yao goto out_free_stack; 3083aca7a94dSNamhyung Kim case 'a': 30842e0453afSJiri Olsa if (!hists__has(hists, sym)) { 3085aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 3086aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 3087aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 3088aca7a94dSNamhyung Kim continue; 3089aca7a94dSNamhyung Kim } 3090aca7a94dSNamhyung Kim 3091ec0479a6SJin Yao if (!browser->selection || 3092ec0479a6SJin Yao !browser->selection->map || 3093ec0479a6SJin Yao !browser->selection->map->dso || 3094ec0479a6SJin Yao browser->selection->map->dso->annotate_warned) { 3095ec0479a6SJin Yao continue; 3096ec0479a6SJin Yao } 3097ec0479a6SJin Yao 3098ec0479a6SJin Yao if (!browser->selection->sym) { 3099ec0479a6SJin Yao if (!browser->he_selection) 3100aca7a94dSNamhyung Kim continue; 3101bc7cad42SNamhyung Kim 3102ec0479a6SJin Yao if (sort__mode == SORT_MODE__BRANCH) { 3103ec0479a6SJin Yao bi = browser->he_selection->branch_info; 3104ec0479a6SJin Yao if (!bi || !bi->to.ms.map) 3105ec0479a6SJin Yao continue; 3106ec0479a6SJin Yao 3107ec0479a6SJin Yao actions->ms.sym = symbol__new_unresolved(bi->to.al_addr, bi->to.ms.map); 3108ec0479a6SJin Yao actions->ms.map = bi->to.ms.map; 3109ec0479a6SJin Yao } else { 3110ec0479a6SJin Yao actions->ms.sym = symbol__new_unresolved(browser->he_selection->ip, 3111ec0479a6SJin Yao browser->selection->map); 3112ec0479a6SJin Yao actions->ms.map = browser->selection->map; 3113ec0479a6SJin Yao } 3114ec0479a6SJin Yao 3115ec0479a6SJin Yao if (!actions->ms.sym) 3116ec0479a6SJin Yao continue; 3117ec0479a6SJin Yao } else { 3118ea537f22SArnaldo Carvalho de Melo if (symbol__annotation(browser->selection->sym)->src == NULL) { 3119ea537f22SArnaldo Carvalho de Melo ui_browser__warning(&browser->b, delay_secs * 2, 3120ea537f22SArnaldo Carvalho de Melo "No samples for the \"%s\" symbol.\n\n" 3121ea537f22SArnaldo Carvalho de Melo "Probably appeared just in a callchain", 3122ea537f22SArnaldo Carvalho de Melo browser->selection->sym->name); 3123ea537f22SArnaldo Carvalho de Melo continue; 3124ea537f22SArnaldo Carvalho de Melo } 3125ea537f22SArnaldo Carvalho de Melo 3126ea7cd592SNamhyung Kim actions->ms.map = browser->selection->map; 3127ea7cd592SNamhyung Kim actions->ms.sym = browser->selection->sym; 3128ec0479a6SJin Yao } 3129ec0479a6SJin Yao 3130ea7cd592SNamhyung Kim do_annotate(browser, actions); 3131bc7cad42SNamhyung Kim continue; 3132aff3f3f6SArnaldo Carvalho de Melo case 'P': 3133aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 3134aff3f3f6SArnaldo Carvalho de Melo continue; 3135aca7a94dSNamhyung Kim case 'd': 3136fae00650SArnaldo Carvalho de Melo actions->ms.map = map; 3137ea7cd592SNamhyung Kim do_zoom_dso(browser, actions); 3138bc7cad42SNamhyung Kim continue; 3139209f4e70SArnaldo Carvalho de Melo case 'k': 3140209f4e70SArnaldo Carvalho de Melo if (browser->selection != NULL) 3141209f4e70SArnaldo Carvalho de Melo hists_browser__zoom_map(browser, browser->selection->maps->machine->vmlinux_map); 3142209f4e70SArnaldo Carvalho de Melo continue; 3143a7cb8863SArnaldo Carvalho de Melo case 'V': 314421e8c810SAlexis Berlemont verbose = (verbose + 1) % 4; 314521e8c810SAlexis Berlemont browser->show_dso = verbose > 0; 314621e8c810SAlexis Berlemont ui_helpline__fpush("Verbosity level set to %d\n", 314721e8c810SAlexis Berlemont verbose); 3148a7cb8863SArnaldo Carvalho de Melo continue; 3149aca7a94dSNamhyung Kim case 't': 3150ea7cd592SNamhyung Kim actions->thread = thread; 3151ea7cd592SNamhyung Kim do_zoom_thread(browser, actions); 3152bc7cad42SNamhyung Kim continue; 315384734b06SKan Liang case 'S': 315484734b06SKan Liang actions->socket = socked_id; 315584734b06SKan Liang do_zoom_socket(browser, actions); 315684734b06SKan Liang continue; 31575a5626b1SArnaldo Carvalho de Melo case '/': 3158aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 31594aa8e454SArnaldo Carvalho de Melo "Please enter the name of symbol you want to see.\n" 31604aa8e454SArnaldo Carvalho de Melo "To remove the filter later, press / + ENTER.", 3161aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 3162aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 316305e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 316405e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 3165aca7a94dSNamhyung Kim hist_browser__reset(browser); 3166aca7a94dSNamhyung Kim } 3167aca7a94dSNamhyung Kim continue; 3168cdbab7c2SFeng Tang case 'r': 3169ea7cd592SNamhyung Kim if (is_report_browser(hbt)) { 3170ea7cd592SNamhyung Kim actions->thread = NULL; 3171ea7cd592SNamhyung Kim actions->ms.sym = NULL; 3172ea7cd592SNamhyung Kim do_run_script(browser, actions); 3173ea7cd592SNamhyung Kim } 3174c77d8d70SFeng Tang continue; 3175341487abSFeng Tang case 's': 3176bc7cad42SNamhyung Kim if (is_report_browser(hbt)) { 3177ea7cd592SNamhyung Kim key = do_switch_data(browser, actions); 3178bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 3179bc7cad42SNamhyung Kim goto out_free_stack; 3180bc7cad42SNamhyung Kim } 3181341487abSFeng Tang continue; 31826dd60135SNamhyung Kim case 'i': 31836dd60135SNamhyung Kim /* env->arch is NULL for live-mode (i.e. perf top) */ 31846dd60135SNamhyung Kim if (env->arch) 31856dd60135SNamhyung Kim tui__header_window(env); 31866dd60135SNamhyung Kim continue; 3187105eb30fSNamhyung Kim case 'F': 3188105eb30fSNamhyung Kim symbol_conf.filter_relative ^= 1; 3189105eb30fSNamhyung Kim continue; 319042337a22SNamhyung Kim case 'z': 319142337a22SNamhyung Kim if (!is_report_browser(hbt)) { 319242337a22SNamhyung Kim struct perf_top *top = hbt->arg; 319342337a22SNamhyung Kim 319442337a22SNamhyung Kim top->zero = !top->zero; 319542337a22SNamhyung Kim } 319642337a22SNamhyung Kim continue; 3197b62e8dfcSNamhyung Kim case 'L': 3198b62e8dfcSNamhyung Kim if (ui_browser__input_window("Percent Limit", 3199b62e8dfcSNamhyung Kim "Please enter the value you want to hide entries under that percent.", 3200b62e8dfcSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 3201b62e8dfcSNamhyung Kim delay_secs * 2) == K_ENTER) { 3202b62e8dfcSNamhyung Kim char *end; 3203b62e8dfcSNamhyung Kim double new_percent = strtod(buf, &end); 3204b62e8dfcSNamhyung Kim 3205b62e8dfcSNamhyung Kim if (new_percent < 0 || new_percent > 100) { 3206b62e8dfcSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 3207b62e8dfcSNamhyung Kim "Invalid percent: %.2f", new_percent); 3208b62e8dfcSNamhyung Kim continue; 3209b62e8dfcSNamhyung Kim } 3210b62e8dfcSNamhyung Kim 3211b62e8dfcSNamhyung Kim hist_browser__update_percent_limit(browser, new_percent); 3212b62e8dfcSNamhyung Kim hist_browser__reset(browser); 3213b62e8dfcSNamhyung Kim } 3214b62e8dfcSNamhyung Kim continue; 3215aca7a94dSNamhyung Kim case K_F1: 3216aca7a94dSNamhyung Kim case 'h': 3217aca7a94dSNamhyung Kim case '?': 3218aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 3219e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 3220aca7a94dSNamhyung Kim continue; 3221aca7a94dSNamhyung Kim case K_ENTER: 3222aca7a94dSNamhyung Kim case K_RIGHT: 322331eb4360SNamhyung Kim case 'm': 3224aca7a94dSNamhyung Kim /* menu */ 3225aca7a94dSNamhyung Kim break; 322663ab1749SArnaldo Carvalho de Melo case K_ESC: 3227aca7a94dSNamhyung Kim case K_LEFT: { 3228aca7a94dSNamhyung Kim const void *top; 3229aca7a94dSNamhyung Kim 323001f00a1cSNamhyung Kim if (pstack__empty(browser->pstack)) { 3231aca7a94dSNamhyung Kim /* 3232aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 3233aca7a94dSNamhyung Kim */ 3234aca7a94dSNamhyung Kim if (left_exits) 3235aca7a94dSNamhyung Kim goto out_free_stack; 323663ab1749SArnaldo Carvalho de Melo 323763ab1749SArnaldo Carvalho de Melo if (key == K_ESC && 323863ab1749SArnaldo Carvalho de Melo ui_browser__dialog_yesno(&browser->b, 323963ab1749SArnaldo Carvalho de Melo "Do you really want to exit?")) 324063ab1749SArnaldo Carvalho de Melo goto out_free_stack; 324163ab1749SArnaldo Carvalho de Melo 3242aca7a94dSNamhyung Kim continue; 3243aca7a94dSNamhyung Kim } 32443f777403SArnaldo Carvalho de Melo actions->ms.map = map; 32456422184bSNamhyung Kim top = pstack__peek(browser->pstack); 3246bc7cad42SNamhyung Kim if (top == &browser->hists->dso_filter) { 32476422184bSNamhyung Kim /* 32486422184bSNamhyung Kim * No need to set actions->dso here since 32496422184bSNamhyung Kim * it's just to remove the current filter. 32506422184bSNamhyung Kim * Ditto for thread below. 32516422184bSNamhyung Kim */ 32526422184bSNamhyung Kim do_zoom_dso(browser, actions); 325384734b06SKan Liang } else if (top == &browser->hists->thread_filter) { 32546422184bSNamhyung Kim do_zoom_thread(browser, actions); 325584734b06SKan Liang } else if (top == &browser->hists->socket_filter) { 325684734b06SKan Liang do_zoom_socket(browser, actions); 325784734b06SKan Liang } 3258aca7a94dSNamhyung Kim continue; 3259aca7a94dSNamhyung Kim } 3260aca7a94dSNamhyung Kim case 'q': 3261aca7a94dSNamhyung Kim case CTRL('c'): 3262516e5368SArnaldo Carvalho de Melo goto out_free_stack; 3263fbb7997eSArnaldo Carvalho de Melo case 'f': 326413d1e536SNamhyung Kim if (!is_report_browser(hbt)) { 326513d1e536SNamhyung Kim struct perf_top *top = hbt->arg; 326613d1e536SNamhyung Kim 3267ade9d208SArnaldo Carvalho de Melo evlist__toggle_enable(top->evlist); 326813d1e536SNamhyung Kim /* 326913d1e536SNamhyung Kim * No need to refresh, resort/decay histogram 327013d1e536SNamhyung Kim * entries if we are not collecting samples: 327113d1e536SNamhyung Kim */ 327213d1e536SNamhyung Kim if (top->evlist->enabled) { 327313d1e536SNamhyung Kim helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; 327413d1e536SNamhyung Kim hbt->refresh = delay_secs; 327513d1e536SNamhyung Kim } else { 327613d1e536SNamhyung Kim helpline = "Press 'f' again to re-enable the events"; 327713d1e536SNamhyung Kim hbt->refresh = 0; 327813d1e536SNamhyung Kim } 327913d1e536SNamhyung Kim continue; 328013d1e536SNamhyung Kim } 32813e323dc0SArnaldo Carvalho de Melo /* Fall thru */ 3282aca7a94dSNamhyung Kim default: 32833e323dc0SArnaldo Carvalho de Melo helpline = "Press '?' for help on key bindings"; 3284aca7a94dSNamhyung Kim continue; 3285aca7a94dSNamhyung Kim } 3286aca7a94dSNamhyung Kim 32872e0453afSJiri Olsa if (!hists__has(hists, sym) || browser->selection == NULL) 32880ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 32890ba332f7SArnaldo Carvalho de Melo 329055369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 3291ceb75476SLeo Yan 3292ceb75476SLeo Yan if (browser->he_selection) 3293aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 32940ba332f7SArnaldo Carvalho de Melo 32950ba332f7SArnaldo Carvalho de Melo if (bi == NULL) 32960ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 32970ba332f7SArnaldo Carvalho de Melo 3298ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 3299ea7cd592SNamhyung Kim &actions[nr_options], 3300ea7cd592SNamhyung Kim &options[nr_options], 33017b0a0dcbSJin Yao &bi->from.ms, 33027b0a0dcbSJin Yao bi->from.al_addr); 3303d46a4cdfSArnaldo Carvalho de Melo if (bi->to.ms.sym != bi->from.ms.sym) 3304ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 3305ea7cd592SNamhyung Kim &actions[nr_options], 3306ea7cd592SNamhyung Kim &options[nr_options], 33077b0a0dcbSJin Yao &bi->to.ms, 33087b0a0dcbSJin Yao bi->to.al_addr); 3309aca7a94dSNamhyung Kim } else { 3310ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 3311ea7cd592SNamhyung Kim &actions[nr_options], 3312ea7cd592SNamhyung Kim &options[nr_options], 33137b0a0dcbSJin Yao browser->selection, 33147b0a0dcbSJin Yao browser->he_selection->ip); 3315446fb96cSArnaldo Carvalho de Melo } 33160ba332f7SArnaldo Carvalho de Melo skip_annotation: 3317ea7cd592SNamhyung Kim nr_options += add_thread_opt(browser, &actions[nr_options], 3318ea7cd592SNamhyung Kim &options[nr_options], thread); 3319ea7cd592SNamhyung Kim nr_options += add_dso_opt(browser, &actions[nr_options], 3320045b80ddSArnaldo Carvalho de Melo &options[nr_options], map); 3321d5a599d9SArnaldo Carvalho de Melo nr_options += add_callchain_toggle_opt(browser, &actions[nr_options], &options[nr_options]); 3322ea7cd592SNamhyung Kim nr_options += add_map_opt(browser, &actions[nr_options], 3323ea7cd592SNamhyung Kim &options[nr_options], 3324bd315aabSWang Nan browser->selection ? 3325bd315aabSWang Nan browser->selection->map : NULL); 332684734b06SKan Liang nr_options += add_socket_opt(browser, &actions[nr_options], 332784734b06SKan Liang &options[nr_options], 332884734b06SKan Liang socked_id); 3329cdbab7c2SFeng Tang /* perf script support */ 3330b1baae89SNamhyung Kim if (!is_report_browser(hbt)) 3331b1baae89SNamhyung Kim goto skip_scripting; 3332b1baae89SNamhyung Kim 3333cdbab7c2SFeng Tang if (browser->he_selection) { 3334fa82911aSJiri Olsa if (hists__has(hists, thread) && thread) { 3335ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 3336ea7cd592SNamhyung Kim &actions[nr_options], 3337ea7cd592SNamhyung Kim &options[nr_options], 33386f3da20eSAndi Kleen thread, NULL, evsel); 33392eafd410SNamhyung Kim } 3340bd315aabSWang Nan /* 3341bd315aabSWang Nan * Note that browser->selection != NULL 3342bd315aabSWang Nan * when browser->he_selection is not NULL, 3343bd315aabSWang Nan * so we don't need to check browser->selection 3344bd315aabSWang Nan * before fetching browser->selection->sym like what 3345bd315aabSWang Nan * we do before fetching browser->selection->map. 3346bd315aabSWang Nan * 3347bd315aabSWang Nan * See hist_browser__show_entry. 3348bd315aabSWang Nan */ 33492e0453afSJiri Olsa if (hists__has(hists, sym) && browser->selection->sym) { 3350ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 3351ea7cd592SNamhyung Kim &actions[nr_options], 3352ea7cd592SNamhyung Kim &options[nr_options], 33536f3da20eSAndi Kleen NULL, browser->selection->sym, 33546f3da20eSAndi Kleen evsel); 3355cdbab7c2SFeng Tang } 3356c221acb0SNamhyung Kim } 3357ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, &actions[nr_options], 33586f3da20eSAndi Kleen &options[nr_options], NULL, NULL, evsel); 33594968ac8fSAndi Kleen nr_options += add_res_sample_opt(browser, &actions[nr_options], 33604968ac8fSAndi Kleen &options[nr_options], 3361d61cbb85SWei Li hist_browser__selected_res_sample(browser), 33624968ac8fSAndi Kleen evsel, A_NORMAL); 33634968ac8fSAndi Kleen nr_options += add_res_sample_opt(browser, &actions[nr_options], 33644968ac8fSAndi Kleen &options[nr_options], 3365d61cbb85SWei Li hist_browser__selected_res_sample(browser), 33664968ac8fSAndi Kleen evsel, A_ASM); 33674968ac8fSAndi Kleen nr_options += add_res_sample_opt(browser, &actions[nr_options], 33684968ac8fSAndi Kleen &options[nr_options], 3369d61cbb85SWei Li hist_browser__selected_res_sample(browser), 33704968ac8fSAndi Kleen evsel, A_SOURCE); 3371ea7cd592SNamhyung Kim nr_options += add_switch_opt(browser, &actions[nr_options], 3372ea7cd592SNamhyung Kim &options[nr_options]); 3373b1baae89SNamhyung Kim skip_scripting: 3374ea7cd592SNamhyung Kim nr_options += add_exit_opt(browser, &actions[nr_options], 3375ea7cd592SNamhyung Kim &options[nr_options]); 3376aca7a94dSNamhyung Kim 3377ea7cd592SNamhyung Kim do { 3378ea7cd592SNamhyung Kim struct popup_action *act; 3379ea7cd592SNamhyung Kim 33804c8b9c0fSArnaldo Carvalho de Melo choice = ui__popup_menu(nr_options, options, &key); 33814c8b9c0fSArnaldo Carvalho de Melo if (choice == -1) 3382aca7a94dSNamhyung Kim break; 3383aca7a94dSNamhyung Kim 33844c8b9c0fSArnaldo Carvalho de Melo if (choice == nr_options) 33854c8b9c0fSArnaldo Carvalho de Melo goto do_hotkey; 33864c8b9c0fSArnaldo Carvalho de Melo 3387ea7cd592SNamhyung Kim act = &actions[choice]; 3388ea7cd592SNamhyung Kim key = act->fn(browser, act); 3389ea7cd592SNamhyung Kim } while (key == 1); 3390aca7a94dSNamhyung Kim 3391bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 3392341487abSFeng Tang break; 3393341487abSFeng Tang } 3394aca7a94dSNamhyung Kim out_free_stack: 339501f00a1cSNamhyung Kim pstack__delete(browser->pstack); 3396aca7a94dSNamhyung Kim out: 3397aca7a94dSNamhyung Kim hist_browser__delete(browser); 3398f2b487dbSNamhyung Kim free_popup_options(options, MAX_OPTIONS); 3399aca7a94dSNamhyung Kim return key; 3400aca7a94dSNamhyung Kim } 3401aca7a94dSNamhyung Kim 340232dcd021SJiri Olsa struct evsel_menu { 3403aca7a94dSNamhyung Kim struct ui_browser b; 340432dcd021SJiri Olsa struct evsel *selection; 3405cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *annotation_opts; 3406aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 3407064f1981SNamhyung Kim float min_pcnt; 3408ce80d3beSKan Liang struct perf_env *env; 3409aca7a94dSNamhyung Kim }; 3410aca7a94dSNamhyung Kim 3411aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 3412aca7a94dSNamhyung Kim void *entry, int row) 3413aca7a94dSNamhyung Kim { 341432dcd021SJiri Olsa struct evsel_menu *menu = container_of(browser, 341532dcd021SJiri Olsa struct evsel_menu, b); 3416b27c4eceSJiri Olsa struct evsel *evsel = list_entry(entry, struct evsel, core.node); 34174ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 3418aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 34194ea062edSArnaldo Carvalho de Melo unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 34208ab2e96dSArnaldo Carvalho de Melo const char *ev_name = evsel__name(evsel); 3421aca7a94dSNamhyung Kim char bf[256], unit; 3422aca7a94dSNamhyung Kim const char *warn = " "; 3423aca7a94dSNamhyung Kim size_t printed; 3424aca7a94dSNamhyung Kim 3425aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 3426aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 3427aca7a94dSNamhyung Kim 3428c754c382SArnaldo Carvalho de Melo if (evsel__is_group_event(evsel)) { 342932dcd021SJiri Olsa struct evsel *pos; 3430717e263fSNamhyung Kim 34318ab2e96dSArnaldo Carvalho de Melo ev_name = evsel__group_name(evsel); 3432717e263fSNamhyung Kim 3433717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 34344ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 34354ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 3436717e263fSNamhyung Kim } 3437717e263fSNamhyung Kim } 3438717e263fSNamhyung Kim 3439aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3440aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 3441aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 3442517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%s", bf); 3443aca7a94dSNamhyung Kim 34444ea062edSArnaldo Carvalho de Melo nr_events = hists->stats.nr_events[PERF_RECORD_LOST]; 3445aca7a94dSNamhyung Kim if (nr_events != 0) { 3446aca7a94dSNamhyung Kim menu->lost_events = true; 3447aca7a94dSNamhyung Kim if (!current_entry) 3448aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 3449aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3450aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 3451aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 3452aca7a94dSNamhyung Kim warn = bf; 3453aca7a94dSNamhyung Kim } 3454aca7a94dSNamhyung Kim 345526270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, warn, browser->width - printed); 3456aca7a94dSNamhyung Kim 3457aca7a94dSNamhyung Kim if (current_entry) 3458aca7a94dSNamhyung Kim menu->selection = evsel; 3459aca7a94dSNamhyung Kim } 3460aca7a94dSNamhyung Kim 346132dcd021SJiri Olsa static int perf_evsel_menu__run(struct evsel_menu *menu, 3462aca7a94dSNamhyung Kim int nr_events, const char *help, 346306cc1a47SKan Liang struct hist_browser_timer *hbt, 346406cc1a47SKan Liang bool warn_lost_event) 3465aca7a94dSNamhyung Kim { 346663503dbaSJiri Olsa struct evlist *evlist = menu->b.priv; 346732dcd021SJiri Olsa struct evsel *pos; 3468dd00d486SJiri Olsa const char *title = "Available samples"; 34699783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 3470aca7a94dSNamhyung Kim int key; 3471aca7a94dSNamhyung Kim 3472aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 3473aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 3474aca7a94dSNamhyung Kim return -1; 3475aca7a94dSNamhyung Kim 3476aca7a94dSNamhyung Kim while (1) { 3477aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 3478aca7a94dSNamhyung Kim 3479aca7a94dSNamhyung Kim switch (key) { 3480aca7a94dSNamhyung Kim case K_TIMER: 3481ceb75476SLeo Yan if (hbt) 34829783adf7SNamhyung Kim hbt->timer(hbt->arg); 3483aca7a94dSNamhyung Kim 348406cc1a47SKan Liang if (!menu->lost_events_warned && 348506cc1a47SKan Liang menu->lost_events && 348606cc1a47SKan Liang warn_lost_event) { 3487aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 3488aca7a94dSNamhyung Kim menu->lost_events_warned = true; 3489aca7a94dSNamhyung Kim } 3490aca7a94dSNamhyung Kim continue; 3491aca7a94dSNamhyung Kim case K_RIGHT: 3492aca7a94dSNamhyung Kim case K_ENTER: 3493aca7a94dSNamhyung Kim if (!menu->selection) 3494aca7a94dSNamhyung Kim continue; 3495aca7a94dSNamhyung Kim pos = menu->selection; 3496aca7a94dSNamhyung Kim browse_hists: 3497aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 3498aca7a94dSNamhyung Kim /* 3499aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 3500aca7a94dSNamhyung Kim * default evsel resorted hists tree. 3501aca7a94dSNamhyung Kim */ 35029783adf7SNamhyung Kim if (hbt) 35039783adf7SNamhyung Kim hbt->timer(hbt->arg); 350456933029SArnaldo Carvalho de Melo key = evsel__hists_browse(pos, nr_events, help, true, hbt, 350556933029SArnaldo Carvalho de Melo menu->min_pcnt, menu->env, 3506cd0cccbaSArnaldo Carvalho de Melo warn_lost_event, 3507cd0cccbaSArnaldo Carvalho de Melo menu->annotation_opts); 3508aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 3509aca7a94dSNamhyung Kim switch (key) { 3510aca7a94dSNamhyung Kim case K_TAB: 3511ce9036a6SJiri Olsa if (pos->core.node.next == &evlist->core.entries) 3512515dbe48SJiri Olsa pos = evlist__first(evlist); 3513aca7a94dSNamhyung Kim else 3514e470daeaSArnaldo Carvalho de Melo pos = evsel__next(pos); 3515aca7a94dSNamhyung Kim goto browse_hists; 3516aca7a94dSNamhyung Kim case K_UNTAB: 3517ce9036a6SJiri Olsa if (pos->core.node.prev == &evlist->core.entries) 3518515dbe48SJiri Olsa pos = evlist__last(evlist); 3519aca7a94dSNamhyung Kim else 3520e470daeaSArnaldo Carvalho de Melo pos = evsel__prev(pos); 3521aca7a94dSNamhyung Kim goto browse_hists; 3522341487abSFeng Tang case K_SWITCH_INPUT_DATA: 35235e3b810aSJin Yao case K_RELOAD: 3524aca7a94dSNamhyung Kim case 'q': 3525aca7a94dSNamhyung Kim case CTRL('c'): 3526aca7a94dSNamhyung Kim goto out; 352763ab1749SArnaldo Carvalho de Melo case K_ESC: 3528aca7a94dSNamhyung Kim default: 3529aca7a94dSNamhyung Kim continue; 3530aca7a94dSNamhyung Kim } 3531aca7a94dSNamhyung Kim case K_LEFT: 3532aca7a94dSNamhyung Kim continue; 3533aca7a94dSNamhyung Kim case K_ESC: 3534aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 3535aca7a94dSNamhyung Kim "Do you really want to exit?")) 3536aca7a94dSNamhyung Kim continue; 3537aca7a94dSNamhyung Kim /* Fall thru */ 3538aca7a94dSNamhyung Kim case 'q': 3539aca7a94dSNamhyung Kim case CTRL('c'): 3540aca7a94dSNamhyung Kim goto out; 3541aca7a94dSNamhyung Kim default: 3542aca7a94dSNamhyung Kim continue; 3543aca7a94dSNamhyung Kim } 3544aca7a94dSNamhyung Kim } 3545aca7a94dSNamhyung Kim 3546aca7a94dSNamhyung Kim out: 3547aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 3548aca7a94dSNamhyung Kim return key; 3549aca7a94dSNamhyung Kim } 3550aca7a94dSNamhyung Kim 3551316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 3552fc24d7c2SNamhyung Kim void *entry) 3553fc24d7c2SNamhyung Kim { 3554b27c4eceSJiri Olsa struct evsel *evsel = list_entry(entry, struct evsel, core.node); 3555fc24d7c2SNamhyung Kim 3556c754c382SArnaldo Carvalho de Melo if (symbol_conf.event_group && !evsel__is_group_leader(evsel)) 3557fc24d7c2SNamhyung Kim return true; 3558fc24d7c2SNamhyung Kim 3559fc24d7c2SNamhyung Kim return false; 3560fc24d7c2SNamhyung Kim } 3561fc24d7c2SNamhyung Kim 3562*f4bd0b4aSArnaldo Carvalho de Melo static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, const char *help, 3563*f4bd0b4aSArnaldo Carvalho de Melo struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, 3564*f4bd0b4aSArnaldo Carvalho de Melo bool warn_lost_event, struct annotation_options *annotation_opts) 3565aca7a94dSNamhyung Kim { 356632dcd021SJiri Olsa struct evsel *pos; 356732dcd021SJiri Olsa struct evsel_menu menu = { 3568aca7a94dSNamhyung Kim .b = { 3569ce9036a6SJiri Olsa .entries = &evlist->core.entries, 3570aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 3571aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 3572aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 3573fc24d7c2SNamhyung Kim .filter = filter_group_entries, 3574fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 3575aca7a94dSNamhyung Kim .priv = evlist, 3576aca7a94dSNamhyung Kim }, 3577064f1981SNamhyung Kim .min_pcnt = min_pcnt, 357868d80758SNamhyung Kim .env = env, 3579cd0cccbaSArnaldo Carvalho de Melo .annotation_opts = annotation_opts, 3580aca7a94dSNamhyung Kim }; 3581aca7a94dSNamhyung Kim 3582aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 3583aca7a94dSNamhyung Kim 3584e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, pos) { 35858ab2e96dSArnaldo Carvalho de Melo const char *ev_name = evsel__name(pos); 3586aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 3587aca7a94dSNamhyung Kim 3588aca7a94dSNamhyung Kim if (menu.b.width < line_len) 3589aca7a94dSNamhyung Kim menu.b.width = line_len; 3590aca7a94dSNamhyung Kim } 3591aca7a94dSNamhyung Kim 359206cc1a47SKan Liang return perf_evsel_menu__run(&menu, nr_entries, help, 359306cc1a47SKan Liang hbt, warn_lost_event); 3594aca7a94dSNamhyung Kim } 3595aca7a94dSNamhyung Kim 3596bee9ca1cSArnaldo Carvalho de Melo static bool perf_evlist__single_entry(struct evlist *evlist) 3597bee9ca1cSArnaldo Carvalho de Melo { 3598bee9ca1cSArnaldo Carvalho de Melo int nr_entries = evlist->core.nr_entries; 3599bee9ca1cSArnaldo Carvalho de Melo 3600bee9ca1cSArnaldo Carvalho de Melo if (nr_entries == 1) 3601bee9ca1cSArnaldo Carvalho de Melo return true; 3602bee9ca1cSArnaldo Carvalho de Melo 3603bee9ca1cSArnaldo Carvalho de Melo if (nr_entries == 2) { 3604bee9ca1cSArnaldo Carvalho de Melo struct evsel *last = evlist__last(evlist); 3605bee9ca1cSArnaldo Carvalho de Melo 3606bee9ca1cSArnaldo Carvalho de Melo if (evsel__is_dummy_event(last)) 3607bee9ca1cSArnaldo Carvalho de Melo return true; 3608bee9ca1cSArnaldo Carvalho de Melo } 3609bee9ca1cSArnaldo Carvalho de Melo 3610bee9ca1cSArnaldo Carvalho de Melo return false; 3611bee9ca1cSArnaldo Carvalho de Melo } 3612bee9ca1cSArnaldo Carvalho de Melo 3613*f4bd0b4aSArnaldo Carvalho de Melo int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, 3614*f4bd0b4aSArnaldo Carvalho de Melo float min_pcnt, struct perf_env *env, bool warn_lost_event, 3615cd0cccbaSArnaldo Carvalho de Melo struct annotation_options *annotation_opts) 3616aca7a94dSNamhyung Kim { 36176484d2f9SJiri Olsa int nr_entries = evlist->core.nr_entries; 3618fc24d7c2SNamhyung Kim 3619bee9ca1cSArnaldo Carvalho de Melo if (perf_evlist__single_entry(evlist)) { 3620d4ccbacbSArnaldo Carvalho de Melo single_entry: { 3621515dbe48SJiri Olsa struct evsel *first = evlist__first(evlist); 3622fc24d7c2SNamhyung Kim 362356933029SArnaldo Carvalho de Melo return evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt, 362456933029SArnaldo Carvalho de Melo env, warn_lost_event, annotation_opts); 3625aca7a94dSNamhyung Kim } 3626d4ccbacbSArnaldo Carvalho de Melo } 3627aca7a94dSNamhyung Kim 3628fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 362932dcd021SJiri Olsa struct evsel *pos; 3630fc24d7c2SNamhyung Kim 3631fc24d7c2SNamhyung Kim nr_entries = 0; 3632e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, pos) { 3633c754c382SArnaldo Carvalho de Melo if (evsel__is_group_leader(pos)) 3634fc24d7c2SNamhyung Kim nr_entries++; 36350050f7aaSArnaldo Carvalho de Melo } 3636fc24d7c2SNamhyung Kim 3637fc24d7c2SNamhyung Kim if (nr_entries == 1) 3638fc24d7c2SNamhyung Kim goto single_entry; 3639fc24d7c2SNamhyung Kim } 3640fc24d7c2SNamhyung Kim 3641*f4bd0b4aSArnaldo Carvalho de Melo return __evlist__tui_browse_hists(evlist, nr_entries, help, hbt, min_pcnt, env, 3642*f4bd0b4aSArnaldo Carvalho de Melo warn_lost_event, annotation_opts); 3643aca7a94dSNamhyung Kim } 36445cb456afSJin Yao 36455cb456afSJin Yao static int block_hists_browser__title(struct hist_browser *browser, char *bf, 36465cb456afSJin Yao size_t size) 36475cb456afSJin Yao { 36485cb456afSJin Yao struct hists *hists = evsel__hists(browser->block_evsel); 36498ab2e96dSArnaldo Carvalho de Melo const char *evname = evsel__name(browser->block_evsel); 36505cb456afSJin Yao unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 36515cb456afSJin Yao int ret; 36525cb456afSJin Yao 36535cb456afSJin Yao ret = scnprintf(bf, size, "# Samples: %lu", nr_samples); 36545cb456afSJin Yao if (evname) 36555cb456afSJin Yao scnprintf(bf + ret, size - ret, " of event '%s'", evname); 36565cb456afSJin Yao 36575cb456afSJin Yao return 0; 36585cb456afSJin Yao } 36595cb456afSJin Yao 36605cb456afSJin Yao int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel, 3661848a5e50SJin Yao float min_percent, struct perf_env *env, 3662848a5e50SJin Yao struct annotation_options *annotation_opts) 36635cb456afSJin Yao { 36645cb456afSJin Yao struct hists *hists = &bh->block_hists; 36655cb456afSJin Yao struct hist_browser *browser; 36665cb456afSJin Yao int key = -1; 3667848a5e50SJin Yao struct popup_action action; 36685cb456afSJin Yao static const char help[] = 36695cb456afSJin Yao " q Quit \n"; 36705cb456afSJin Yao 36715cb456afSJin Yao browser = hist_browser__new(hists); 36725cb456afSJin Yao if (!browser) 36735cb456afSJin Yao return -1; 36745cb456afSJin Yao 36755cb456afSJin Yao browser->block_evsel = evsel; 36765cb456afSJin Yao browser->title = block_hists_browser__title; 36775cb456afSJin Yao browser->min_pcnt = min_percent; 3678848a5e50SJin Yao browser->env = env; 3679848a5e50SJin Yao browser->annotation_opts = annotation_opts; 36805cb456afSJin Yao 36815cb456afSJin Yao /* reset abort key so that it can get Ctrl-C as a key */ 36825cb456afSJin Yao SLang_reset_tty(); 36835cb456afSJin Yao SLang_init_tty(0, 0, 0); 36845cb456afSJin Yao 3685848a5e50SJin Yao memset(&action, 0, sizeof(action)); 3686848a5e50SJin Yao 36875cb456afSJin Yao while (1) { 3688d10ec006SArnaldo Carvalho de Melo key = hist_browser__run(browser, "? - help", true, 0); 36895cb456afSJin Yao 36905cb456afSJin Yao switch (key) { 36915cb456afSJin Yao case 'q': 36925cb456afSJin Yao goto out; 36935cb456afSJin Yao case '?': 36945cb456afSJin Yao ui_browser__help_window(&browser->b, help); 36955cb456afSJin Yao break; 3696848a5e50SJin Yao case 'a': 3697848a5e50SJin Yao case K_ENTER: 3698848a5e50SJin Yao if (!browser->selection || 3699848a5e50SJin Yao !browser->selection->sym) { 3700848a5e50SJin Yao continue; 3701848a5e50SJin Yao } 3702848a5e50SJin Yao 3703848a5e50SJin Yao action.ms.map = browser->selection->map; 3704848a5e50SJin Yao action.ms.sym = browser->selection->sym; 3705848a5e50SJin Yao do_annotate(browser, &action); 3706848a5e50SJin Yao continue; 37075cb456afSJin Yao default: 37085cb456afSJin Yao break; 37095cb456afSJin Yao } 37105cb456afSJin Yao } 37115cb456afSJin Yao 37125cb456afSJin Yao out: 37135cb456afSJin Yao hist_browser__delete(browser); 37145cb456afSJin Yao return 0; 37155cb456afSJin Yao } 3716