1aca7a94dSNamhyung Kim #include <stdio.h> 2aca7a94dSNamhyung Kim #include <stdlib.h> 3aca7a94dSNamhyung Kim #include <string.h> 4aca7a94dSNamhyung Kim #include <linux/rbtree.h> 5aca7a94dSNamhyung Kim 6aca7a94dSNamhyung Kim #include "../../util/evsel.h" 7aca7a94dSNamhyung Kim #include "../../util/evlist.h" 8aca7a94dSNamhyung Kim #include "../../util/hist.h" 9aca7a94dSNamhyung Kim #include "../../util/pstack.h" 10aca7a94dSNamhyung Kim #include "../../util/sort.h" 11aca7a94dSNamhyung Kim #include "../../util/util.h" 1242337a22SNamhyung Kim #include "../../util/top.h" 1368d80758SNamhyung Kim #include "../../arch/common.h" 14aca7a94dSNamhyung Kim 15f758990fSJiri Olsa #include "../browsers/hists.h" 16aca7a94dSNamhyung Kim #include "../helpline.h" 17aca7a94dSNamhyung Kim #include "../util.h" 18aca7a94dSNamhyung Kim #include "../ui.h" 19aca7a94dSNamhyung Kim #include "map.h" 20d755330cSJiri Olsa #include "annotate.h" 21aca7a94dSNamhyung Kim 22f5951d56SNamhyung Kim extern void hist_browser__init_hpp(void); 23f5951d56SNamhyung Kim 241e378ebdSTaeung Song static int hists__browser_title(struct hists *hists, 251e378ebdSTaeung Song struct hist_browser_timer *hbt, 261e378ebdSTaeung Song char *bf, size_t size); 27112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb); 28aca7a94dSNamhyung Kim 29c3b78952SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 30c3b78952SNamhyung Kim float min_pcnt); 31c3b78952SNamhyung Kim 32268397cbSNamhyung Kim static bool hist_browser__has_filter(struct hist_browser *hb) 33268397cbSNamhyung Kim { 349c0fa8ddSArnaldo Carvalho de Melo return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter; 35268397cbSNamhyung Kim } 36268397cbSNamhyung Kim 374fabf3d1SHe Kuang static int hist_browser__get_folding(struct hist_browser *browser) 384fabf3d1SHe Kuang { 394fabf3d1SHe Kuang struct rb_node *nd; 404fabf3d1SHe Kuang struct hists *hists = browser->hists; 414fabf3d1SHe Kuang int unfolded_rows = 0; 424fabf3d1SHe Kuang 434fabf3d1SHe Kuang for (nd = rb_first(&hists->entries); 444fabf3d1SHe Kuang (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 45f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd)) { 464fabf3d1SHe Kuang struct hist_entry *he = 474fabf3d1SHe Kuang rb_entry(nd, struct hist_entry, rb_node); 484fabf3d1SHe Kuang 49f5b763feSNamhyung Kim if (he->leaf && he->unfolded) 504fabf3d1SHe Kuang unfolded_rows += he->nr_rows; 514fabf3d1SHe Kuang } 524fabf3d1SHe Kuang return unfolded_rows; 534fabf3d1SHe Kuang } 544fabf3d1SHe Kuang 55c3b78952SNamhyung Kim static u32 hist_browser__nr_entries(struct hist_browser *hb) 56c3b78952SNamhyung Kim { 57c3b78952SNamhyung Kim u32 nr_entries; 58c3b78952SNamhyung Kim 59f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 60f5b763feSNamhyung Kim nr_entries = hb->nr_hierarchy_entries; 61f5b763feSNamhyung Kim else if (hist_browser__has_filter(hb)) 62c3b78952SNamhyung Kim nr_entries = hb->nr_non_filtered_entries; 63c3b78952SNamhyung Kim else 64c3b78952SNamhyung Kim nr_entries = hb->hists->nr_entries; 65c3b78952SNamhyung Kim 664fabf3d1SHe Kuang hb->nr_callchain_rows = hist_browser__get_folding(hb); 67c3b78952SNamhyung Kim return nr_entries + hb->nr_callchain_rows; 68c3b78952SNamhyung Kim } 69c3b78952SNamhyung Kim 70025bf7eaSArnaldo Carvalho de Melo static void hist_browser__update_rows(struct hist_browser *hb) 71025bf7eaSArnaldo Carvalho de Melo { 72025bf7eaSArnaldo Carvalho de Melo struct ui_browser *browser = &hb->b; 73025bf7eaSArnaldo Carvalho de Melo u16 header_offset = hb->show_headers ? 1 : 0, index_row; 74025bf7eaSArnaldo Carvalho de Melo 75025bf7eaSArnaldo Carvalho de Melo browser->rows = browser->height - header_offset; 76025bf7eaSArnaldo Carvalho de Melo /* 77025bf7eaSArnaldo Carvalho de Melo * Verify if we were at the last line and that line isn't 78025bf7eaSArnaldo Carvalho de Melo * visibe because we now show the header line(s). 79025bf7eaSArnaldo Carvalho de Melo */ 80025bf7eaSArnaldo Carvalho de Melo index_row = browser->index - browser->top_idx; 81025bf7eaSArnaldo Carvalho de Melo if (index_row >= browser->rows) 82025bf7eaSArnaldo Carvalho de Melo browser->index -= index_row - browser->rows + 1; 83025bf7eaSArnaldo Carvalho de Melo } 84025bf7eaSArnaldo Carvalho de Melo 85357cfff1SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct ui_browser *browser) 86aca7a94dSNamhyung Kim { 87357cfff1SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 88357cfff1SArnaldo Carvalho de Melo 89aca7a94dSNamhyung Kim /* 3 == +/- toggle symbol before actual hist_entry rendering */ 90357cfff1SArnaldo Carvalho de Melo browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]")); 91357cfff1SArnaldo Carvalho de Melo /* 92357cfff1SArnaldo Carvalho de Melo * FIXME: Just keeping existing behaviour, but this really should be 93357cfff1SArnaldo Carvalho de Melo * before updating browser->width, as it will invalidate the 94357cfff1SArnaldo Carvalho de Melo * calculation above. Fix this and the fallout in another 95357cfff1SArnaldo Carvalho de Melo * changeset. 96357cfff1SArnaldo Carvalho de Melo */ 97357cfff1SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(browser); 98025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(hb); 99aca7a94dSNamhyung Kim } 100aca7a94dSNamhyung Kim 101ca3ff33bSArnaldo Carvalho de Melo static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) 102ca3ff33bSArnaldo Carvalho de Melo { 103025bf7eaSArnaldo Carvalho de Melo u16 header_offset = browser->show_headers ? 1 : 0; 104025bf7eaSArnaldo Carvalho de Melo 105025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row + header_offset, column); 106ca3ff33bSArnaldo Carvalho de Melo } 107ca3ff33bSArnaldo Carvalho de Melo 10805e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser) 109aca7a94dSNamhyung Kim { 110c3b78952SNamhyung Kim /* 111c3b78952SNamhyung Kim * The hists__remove_entry_filter() already folds non-filtered 112c3b78952SNamhyung Kim * entries so we can assume it has 0 callchain rows. 113c3b78952SNamhyung Kim */ 114c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 115c3b78952SNamhyung Kim 116268397cbSNamhyung Kim hist_browser__update_nr_entries(browser); 117c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 118357cfff1SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(&browser->b); 11905e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 120aca7a94dSNamhyung Kim } 121aca7a94dSNamhyung Kim 122aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded) 123aca7a94dSNamhyung Kim { 124aca7a94dSNamhyung Kim return unfolded ? '-' : '+'; 125aca7a94dSNamhyung Kim } 126aca7a94dSNamhyung Kim 12705e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he) 128aca7a94dSNamhyung Kim { 1293698dab1SNamhyung Kim return he->has_children ? tree__folded_sign(he->unfolded) : ' '; 130aca7a94dSNamhyung Kim } 131aca7a94dSNamhyung Kim 13205e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl) 133aca7a94dSNamhyung Kim { 1343698dab1SNamhyung Kim return cl->has_children ? tree__folded_sign(cl->unfolded) : ' '; 135aca7a94dSNamhyung Kim } 136aca7a94dSNamhyung Kim 1373698dab1SNamhyung Kim static void callchain_list__set_folding(struct callchain_list *cl, bool unfold) 138aca7a94dSNamhyung Kim { 1393698dab1SNamhyung Kim cl->unfolded = unfold ? cl->has_children : false; 140aca7a94dSNamhyung Kim } 141aca7a94dSNamhyung Kim 14205e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 143aca7a94dSNamhyung Kim { 144aca7a94dSNamhyung Kim int n = 0; 145aca7a94dSNamhyung Kim struct rb_node *nd; 146aca7a94dSNamhyung Kim 14705e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 148aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 149aca7a94dSNamhyung Kim struct callchain_list *chain; 150aca7a94dSNamhyung Kim char folded_sign = ' '; /* No children */ 151aca7a94dSNamhyung Kim 152aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 153aca7a94dSNamhyung Kim ++n; 154aca7a94dSNamhyung Kim /* We need this because we may not have children */ 155aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 156aca7a94dSNamhyung Kim if (folded_sign == '+') 157aca7a94dSNamhyung Kim break; 158aca7a94dSNamhyung Kim } 159aca7a94dSNamhyung Kim 160aca7a94dSNamhyung Kim if (folded_sign == '-') /* Have children and they're unfolded */ 161aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(child); 162aca7a94dSNamhyung Kim } 163aca7a94dSNamhyung Kim 164aca7a94dSNamhyung Kim return n; 165aca7a94dSNamhyung Kim } 166aca7a94dSNamhyung Kim 1674b3a3212SNamhyung Kim static int callchain_node__count_flat_rows(struct callchain_node *node) 1684b3a3212SNamhyung Kim { 1694b3a3212SNamhyung Kim struct callchain_list *chain; 1704b3a3212SNamhyung Kim char folded_sign = 0; 1714b3a3212SNamhyung Kim int n = 0; 1724b3a3212SNamhyung Kim 1734b3a3212SNamhyung Kim list_for_each_entry(chain, &node->parent_val, list) { 1744b3a3212SNamhyung Kim if (!folded_sign) { 1754b3a3212SNamhyung Kim /* only check first chain list entry */ 1764b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 1774b3a3212SNamhyung Kim if (folded_sign == '+') 1784b3a3212SNamhyung Kim return 1; 1794b3a3212SNamhyung Kim } 1804b3a3212SNamhyung Kim n++; 1814b3a3212SNamhyung Kim } 1824b3a3212SNamhyung Kim 1834b3a3212SNamhyung Kim list_for_each_entry(chain, &node->val, list) { 1844b3a3212SNamhyung Kim if (!folded_sign) { 1854b3a3212SNamhyung Kim /* node->parent_val list might be empty */ 1864b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 1874b3a3212SNamhyung Kim if (folded_sign == '+') 1884b3a3212SNamhyung Kim return 1; 1894b3a3212SNamhyung Kim } 1904b3a3212SNamhyung Kim n++; 1914b3a3212SNamhyung Kim } 1924b3a3212SNamhyung Kim 1934b3a3212SNamhyung Kim return n; 1944b3a3212SNamhyung Kim } 1954b3a3212SNamhyung Kim 1968c430a34SNamhyung Kim static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused) 1978c430a34SNamhyung Kim { 1988c430a34SNamhyung Kim return 1; 1998c430a34SNamhyung Kim } 2008c430a34SNamhyung Kim 201aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 202aca7a94dSNamhyung Kim { 203aca7a94dSNamhyung Kim struct callchain_list *chain; 204aca7a94dSNamhyung Kim bool unfolded = false; 205aca7a94dSNamhyung Kim int n = 0; 206aca7a94dSNamhyung Kim 2074b3a3212SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) 2084b3a3212SNamhyung Kim return callchain_node__count_flat_rows(node); 2098c430a34SNamhyung Kim else if (callchain_param.mode == CHAIN_FOLDED) 2108c430a34SNamhyung Kim return callchain_node__count_folded_rows(node); 2114b3a3212SNamhyung Kim 212aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 213aca7a94dSNamhyung Kim ++n; 2143698dab1SNamhyung Kim unfolded = chain->unfolded; 215aca7a94dSNamhyung Kim } 216aca7a94dSNamhyung Kim 217aca7a94dSNamhyung Kim if (unfolded) 218aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 219aca7a94dSNamhyung Kim 220aca7a94dSNamhyung Kim return n; 221aca7a94dSNamhyung Kim } 222aca7a94dSNamhyung Kim 223aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 224aca7a94dSNamhyung Kim { 225aca7a94dSNamhyung Kim struct rb_node *nd; 226aca7a94dSNamhyung Kim int n = 0; 227aca7a94dSNamhyung Kim 228aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 229aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 230aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 231aca7a94dSNamhyung Kim } 232aca7a94dSNamhyung Kim 233aca7a94dSNamhyung Kim return n; 234aca7a94dSNamhyung Kim } 235aca7a94dSNamhyung Kim 236f5b763feSNamhyung Kim static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he, 237f5b763feSNamhyung Kim bool include_children) 238f5b763feSNamhyung Kim { 239f5b763feSNamhyung Kim int count = 0; 240f5b763feSNamhyung Kim struct rb_node *node; 241f5b763feSNamhyung Kim struct hist_entry *child; 242f5b763feSNamhyung Kim 243f5b763feSNamhyung Kim if (he->leaf) 244f5b763feSNamhyung Kim return callchain__count_rows(&he->sorted_chain); 245f5b763feSNamhyung Kim 24679dded87SNamhyung Kim if (he->has_no_entry) 24779dded87SNamhyung Kim return 1; 24879dded87SNamhyung Kim 249f5b763feSNamhyung Kim node = rb_first(&he->hroot_out); 250f5b763feSNamhyung Kim while (node) { 251f5b763feSNamhyung Kim float percent; 252f5b763feSNamhyung Kim 253f5b763feSNamhyung Kim child = rb_entry(node, struct hist_entry, rb_node); 254f5b763feSNamhyung Kim percent = hist_entry__get_percent_limit(child); 255f5b763feSNamhyung Kim 256f5b763feSNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) { 257f5b763feSNamhyung Kim count++; 258f5b763feSNamhyung Kim 259f5b763feSNamhyung Kim if (include_children && child->unfolded) 260f5b763feSNamhyung Kim count += hierarchy_count_rows(hb, child, true); 261f5b763feSNamhyung Kim } 262f5b763feSNamhyung Kim 263f5b763feSNamhyung Kim node = rb_next(node); 264f5b763feSNamhyung Kim } 265f5b763feSNamhyung Kim return count; 266f5b763feSNamhyung Kim } 267f5b763feSNamhyung Kim 2683698dab1SNamhyung Kim static bool hist_entry__toggle_fold(struct hist_entry *he) 269aca7a94dSNamhyung Kim { 2703698dab1SNamhyung Kim if (!he) 271aca7a94dSNamhyung Kim return false; 272aca7a94dSNamhyung Kim 2733698dab1SNamhyung Kim if (!he->has_children) 274aca7a94dSNamhyung Kim return false; 275aca7a94dSNamhyung Kim 2763698dab1SNamhyung Kim he->unfolded = !he->unfolded; 2773698dab1SNamhyung Kim return true; 2783698dab1SNamhyung Kim } 2793698dab1SNamhyung Kim 2803698dab1SNamhyung Kim static bool callchain_list__toggle_fold(struct callchain_list *cl) 2813698dab1SNamhyung Kim { 2823698dab1SNamhyung Kim if (!cl) 2833698dab1SNamhyung Kim return false; 2843698dab1SNamhyung Kim 2853698dab1SNamhyung Kim if (!cl->has_children) 2863698dab1SNamhyung Kim return false; 2873698dab1SNamhyung Kim 2883698dab1SNamhyung Kim cl->unfolded = !cl->unfolded; 289aca7a94dSNamhyung Kim return true; 290aca7a94dSNamhyung Kim } 291aca7a94dSNamhyung Kim 29205e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 293aca7a94dSNamhyung Kim { 29405e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 295aca7a94dSNamhyung Kim 29605e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 297aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 298aca7a94dSNamhyung Kim struct callchain_list *chain; 299aca7a94dSNamhyung Kim bool first = true; 300aca7a94dSNamhyung Kim 301aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 302aca7a94dSNamhyung Kim if (first) { 303aca7a94dSNamhyung Kim first = false; 3043698dab1SNamhyung Kim chain->has_children = chain->list.next != &child->val || 305aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 306aca7a94dSNamhyung Kim } else 3073698dab1SNamhyung Kim chain->has_children = chain->list.next == &child->val && 308aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 309aca7a94dSNamhyung Kim } 310aca7a94dSNamhyung Kim 311aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 312aca7a94dSNamhyung Kim } 313aca7a94dSNamhyung Kim } 314aca7a94dSNamhyung Kim 315a7444af6SNamhyung Kim static void callchain_node__init_have_children(struct callchain_node *node, 316a7444af6SNamhyung Kim bool has_sibling) 317aca7a94dSNamhyung Kim { 318aca7a94dSNamhyung Kim struct callchain_list *chain; 319aca7a94dSNamhyung Kim 320a7444af6SNamhyung Kim chain = list_entry(node->val.next, struct callchain_list, list); 3213698dab1SNamhyung Kim chain->has_children = has_sibling; 322a7444af6SNamhyung Kim 32390989035SAndres Freund if (!list_empty(&node->val)) { 32482162b5aSNamhyung Kim chain = list_entry(node->val.prev, struct callchain_list, list); 3253698dab1SNamhyung Kim chain->has_children = !RB_EMPTY_ROOT(&node->rb_root); 32682162b5aSNamhyung Kim } 327aca7a94dSNamhyung Kim 32805e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 329aca7a94dSNamhyung Kim } 330aca7a94dSNamhyung Kim 33105e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 332aca7a94dSNamhyung Kim { 333a7444af6SNamhyung Kim struct rb_node *nd = rb_first(root); 334a7444af6SNamhyung Kim bool has_sibling = nd && rb_next(nd); 335aca7a94dSNamhyung Kim 33605e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 337aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 338a7444af6SNamhyung Kim callchain_node__init_have_children(node, has_sibling); 3398c430a34SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT || 3408c430a34SNamhyung Kim callchain_param.mode == CHAIN_FOLDED) 3414b3a3212SNamhyung Kim callchain_node__make_parent_list(node); 342aca7a94dSNamhyung Kim } 343aca7a94dSNamhyung Kim } 344aca7a94dSNamhyung Kim 34505e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 346aca7a94dSNamhyung Kim { 347f5b763feSNamhyung Kim if (he->init_have_children) 348f5b763feSNamhyung Kim return; 349f5b763feSNamhyung Kim 350f5b763feSNamhyung Kim if (he->leaf) { 3513698dab1SNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 35205e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 353f5b763feSNamhyung Kim } else { 354f5b763feSNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->hroot_out); 355aca7a94dSNamhyung Kim } 356f5b763feSNamhyung Kim 357f5b763feSNamhyung Kim he->init_have_children = true; 358aca7a94dSNamhyung Kim } 359aca7a94dSNamhyung Kim 36005e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 361aca7a94dSNamhyung Kim { 36205e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 3633698dab1SNamhyung Kim struct map_symbol *ms = browser->selection; 3643698dab1SNamhyung Kim struct callchain_list *cl = container_of(ms, struct callchain_list, ms); 3653698dab1SNamhyung Kim bool has_children; 366aca7a94dSNamhyung Kim 3674938cf0cSWang Nan if (!he || !ms) 3684938cf0cSWang Nan return false; 3694938cf0cSWang Nan 3703698dab1SNamhyung Kim if (ms == &he->ms) 3713698dab1SNamhyung Kim has_children = hist_entry__toggle_fold(he); 3723698dab1SNamhyung Kim else 3733698dab1SNamhyung Kim has_children = callchain_list__toggle_fold(cl); 3743698dab1SNamhyung Kim 3753698dab1SNamhyung Kim if (has_children) { 376f5b763feSNamhyung Kim int child_rows = 0; 377f5b763feSNamhyung Kim 378aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 379c3b78952SNamhyung Kim browser->b.nr_entries -= he->nr_rows; 380aca7a94dSNamhyung Kim 381f5b763feSNamhyung Kim if (he->leaf) 382f5b763feSNamhyung Kim browser->nr_callchain_rows -= he->nr_rows; 383f5b763feSNamhyung Kim else 384f5b763feSNamhyung Kim browser->nr_hierarchy_entries -= he->nr_rows; 385f5b763feSNamhyung Kim 386f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 387f5b763feSNamhyung Kim child_rows = hierarchy_count_rows(browser, he, true); 388f5b763feSNamhyung Kim 389f5b763feSNamhyung Kim if (he->unfolded) { 390f5b763feSNamhyung Kim if (he->leaf) 391aca7a94dSNamhyung Kim he->nr_rows = callchain__count_rows(&he->sorted_chain); 392aca7a94dSNamhyung Kim else 393f5b763feSNamhyung Kim he->nr_rows = hierarchy_count_rows(browser, he, false); 394f5b763feSNamhyung Kim 395f5b763feSNamhyung Kim /* account grand children */ 396f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 397f5b763feSNamhyung Kim browser->b.nr_entries += child_rows - he->nr_rows; 39879dded87SNamhyung Kim 39979dded87SNamhyung Kim if (!he->leaf && he->nr_rows == 0) { 40079dded87SNamhyung Kim he->has_no_entry = true; 40179dded87SNamhyung Kim he->nr_rows = 1; 40279dded87SNamhyung Kim } 403f5b763feSNamhyung Kim } else { 404f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 405f5b763feSNamhyung Kim browser->b.nr_entries -= child_rows - he->nr_rows; 406f5b763feSNamhyung Kim 40779dded87SNamhyung Kim if (he->has_no_entry) 40879dded87SNamhyung Kim he->has_no_entry = false; 40979dded87SNamhyung Kim 410aca7a94dSNamhyung Kim he->nr_rows = 0; 411f5b763feSNamhyung Kim } 412c3b78952SNamhyung Kim 413c3b78952SNamhyung Kim browser->b.nr_entries += he->nr_rows; 414f5b763feSNamhyung Kim 415f5b763feSNamhyung Kim if (he->leaf) 416c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 417f5b763feSNamhyung Kim else 418f5b763feSNamhyung Kim browser->nr_hierarchy_entries += he->nr_rows; 419aca7a94dSNamhyung Kim 420aca7a94dSNamhyung Kim return true; 421aca7a94dSNamhyung Kim } 422aca7a94dSNamhyung Kim 423aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 424aca7a94dSNamhyung Kim return false; 425aca7a94dSNamhyung Kim } 426aca7a94dSNamhyung Kim 42705e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 428aca7a94dSNamhyung Kim { 429aca7a94dSNamhyung Kim int n = 0; 430aca7a94dSNamhyung Kim struct rb_node *nd; 431aca7a94dSNamhyung Kim 43205e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 433aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 434aca7a94dSNamhyung Kim struct callchain_list *chain; 435aca7a94dSNamhyung Kim bool has_children = false; 436aca7a94dSNamhyung Kim 437aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 438aca7a94dSNamhyung Kim ++n; 4393698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 4403698dab1SNamhyung Kim has_children = chain->has_children; 441aca7a94dSNamhyung Kim } 442aca7a94dSNamhyung Kim 443aca7a94dSNamhyung Kim if (has_children) 444aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 445aca7a94dSNamhyung Kim } 446aca7a94dSNamhyung Kim 447aca7a94dSNamhyung Kim return n; 448aca7a94dSNamhyung Kim } 449aca7a94dSNamhyung Kim 450aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 451aca7a94dSNamhyung Kim { 452aca7a94dSNamhyung Kim struct callchain_list *chain; 453aca7a94dSNamhyung Kim bool has_children = false; 454aca7a94dSNamhyung Kim int n = 0; 455aca7a94dSNamhyung Kim 456aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 457aca7a94dSNamhyung Kim ++n; 4583698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 4593698dab1SNamhyung Kim has_children = chain->has_children; 460aca7a94dSNamhyung Kim } 461aca7a94dSNamhyung Kim 462aca7a94dSNamhyung Kim if (has_children) 463aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 464aca7a94dSNamhyung Kim 465aca7a94dSNamhyung Kim return n; 466aca7a94dSNamhyung Kim } 467aca7a94dSNamhyung Kim 468aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 469aca7a94dSNamhyung Kim { 470aca7a94dSNamhyung Kim struct rb_node *nd; 471aca7a94dSNamhyung Kim int n = 0; 472aca7a94dSNamhyung Kim 473aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 474aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 475aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 476aca7a94dSNamhyung Kim } 477aca7a94dSNamhyung Kim 478aca7a94dSNamhyung Kim return n; 479aca7a94dSNamhyung Kim } 480aca7a94dSNamhyung Kim 481492b1010SNamhyung Kim static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he, 482492b1010SNamhyung Kim bool unfold __maybe_unused) 483492b1010SNamhyung Kim { 484492b1010SNamhyung Kim float percent; 485492b1010SNamhyung Kim struct rb_node *nd; 486492b1010SNamhyung Kim struct hist_entry *child; 487492b1010SNamhyung Kim int n = 0; 488492b1010SNamhyung Kim 489492b1010SNamhyung Kim for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) { 490492b1010SNamhyung Kim child = rb_entry(nd, struct hist_entry, rb_node); 491492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(child); 492492b1010SNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) 493492b1010SNamhyung Kim n++; 494492b1010SNamhyung Kim } 495492b1010SNamhyung Kim 496492b1010SNamhyung Kim return n; 497492b1010SNamhyung Kim } 498492b1010SNamhyung Kim 499492b1010SNamhyung Kim static void hist_entry__set_folding(struct hist_entry *he, 500492b1010SNamhyung Kim struct hist_browser *hb, bool unfold) 501aca7a94dSNamhyung Kim { 50205e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 5033698dab1SNamhyung Kim he->unfolded = unfold ? he->has_children : false; 504aca7a94dSNamhyung Kim 5053698dab1SNamhyung Kim if (he->has_children) { 506492b1010SNamhyung Kim int n; 507492b1010SNamhyung Kim 508492b1010SNamhyung Kim if (he->leaf) 509492b1010SNamhyung Kim n = callchain__set_folding(&he->sorted_chain, unfold); 510492b1010SNamhyung Kim else 511492b1010SNamhyung Kim n = hierarchy_set_folding(hb, he, unfold); 512492b1010SNamhyung Kim 51305e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 514aca7a94dSNamhyung Kim } else 51505e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 516aca7a94dSNamhyung Kim } 517aca7a94dSNamhyung Kim 518c3b78952SNamhyung Kim static void 519c3b78952SNamhyung Kim __hist_browser__set_folding(struct hist_browser *browser, bool unfold) 520aca7a94dSNamhyung Kim { 521aca7a94dSNamhyung Kim struct rb_node *nd; 522492b1010SNamhyung Kim struct hist_entry *he; 523492b1010SNamhyung Kim double percent; 524aca7a94dSNamhyung Kim 525492b1010SNamhyung Kim nd = rb_first(&browser->hists->entries); 526492b1010SNamhyung Kim while (nd) { 527492b1010SNamhyung Kim he = rb_entry(nd, struct hist_entry, rb_node); 528492b1010SNamhyung Kim 529492b1010SNamhyung Kim /* set folding state even if it's currently folded */ 530492b1010SNamhyung Kim nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 531492b1010SNamhyung Kim 532492b1010SNamhyung Kim hist_entry__set_folding(he, browser, unfold); 533492b1010SNamhyung Kim 534492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(he); 535492b1010SNamhyung Kim if (he->filtered || percent < browser->min_pcnt) 536492b1010SNamhyung Kim continue; 537492b1010SNamhyung Kim 538492b1010SNamhyung Kim if (!he->depth || unfold) 539492b1010SNamhyung Kim browser->nr_hierarchy_entries++; 540492b1010SNamhyung Kim if (he->leaf) 541c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 54279dded87SNamhyung Kim else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) { 54379dded87SNamhyung Kim browser->nr_hierarchy_entries++; 54479dded87SNamhyung Kim he->has_no_entry = true; 54579dded87SNamhyung Kim he->nr_rows = 1; 54679dded87SNamhyung Kim } else 54779dded87SNamhyung Kim he->has_no_entry = false; 548aca7a94dSNamhyung Kim } 549aca7a94dSNamhyung Kim } 550aca7a94dSNamhyung Kim 55105e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 552aca7a94dSNamhyung Kim { 553492b1010SNamhyung Kim browser->nr_hierarchy_entries = 0; 554c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 555c3b78952SNamhyung Kim __hist_browser__set_folding(browser, unfold); 556c3b78952SNamhyung Kim 557c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 558aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 55905e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 560aca7a94dSNamhyung Kim } 561aca7a94dSNamhyung Kim 562aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 563aca7a94dSNamhyung Kim { 564aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 565aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 566aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 567aca7a94dSNamhyung Kim " perf top -r 80\n\n" 568aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 569aca7a94dSNamhyung Kim } 570aca7a94dSNamhyung Kim 571*dabd2012SJiri Olsa int hist_browser__run(struct hist_browser *browser, const char *help) 572aca7a94dSNamhyung Kim { 573aca7a94dSNamhyung Kim int key; 574aca7a94dSNamhyung Kim char title[160]; 575c2a51ab8SNamhyung Kim struct hist_browser_timer *hbt = browser->hbt; 5769783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 577aca7a94dSNamhyung Kim 57805e8b080SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 579c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 580aca7a94dSNamhyung Kim 5811e378ebdSTaeung Song hists__browser_title(browser->hists, hbt, title, sizeof(title)); 582aca7a94dSNamhyung Kim 583090cff3eSNamhyung Kim if (ui_browser__show(&browser->b, title, "%s", help) < 0) 584aca7a94dSNamhyung Kim return -1; 585aca7a94dSNamhyung Kim 586aca7a94dSNamhyung Kim while (1) { 58705e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 588aca7a94dSNamhyung Kim 589aca7a94dSNamhyung Kim switch (key) { 590fa5df943SNamhyung Kim case K_TIMER: { 591fa5df943SNamhyung Kim u64 nr_entries; 5929783adf7SNamhyung Kim hbt->timer(hbt->arg); 593fa5df943SNamhyung Kim 594c3b78952SNamhyung Kim if (hist_browser__has_filter(browser)) 595112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 596fa5df943SNamhyung Kim 597c3b78952SNamhyung Kim nr_entries = hist_browser__nr_entries(browser); 598fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 599aca7a94dSNamhyung Kim 60005e8b080SArnaldo Carvalho de Melo if (browser->hists->stats.nr_lost_warned != 60105e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]) { 60205e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 60305e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 60405e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 605aca7a94dSNamhyung Kim } 606aca7a94dSNamhyung Kim 6071e378ebdSTaeung Song hists__browser_title(browser->hists, 6081e378ebdSTaeung Song hbt, title, sizeof(title)); 60905e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 610aca7a94dSNamhyung Kim continue; 611fa5df943SNamhyung Kim } 612aca7a94dSNamhyung Kim case 'D': { /* Debug */ 613aca7a94dSNamhyung Kim static int seq; 61405e8b080SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, 615aca7a94dSNamhyung Kim struct hist_entry, rb_node); 616aca7a94dSNamhyung Kim ui_helpline__pop(); 61762c95ae3SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 61805e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 61905e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries, 62062c95ae3SArnaldo Carvalho de Melo browser->b.rows, 62105e8b080SArnaldo Carvalho de Melo browser->b.index, 62205e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 623aca7a94dSNamhyung Kim h->row_offset, h->nr_rows); 624aca7a94dSNamhyung Kim } 625aca7a94dSNamhyung Kim break; 626aca7a94dSNamhyung Kim case 'C': 627aca7a94dSNamhyung Kim /* Collapse the whole world. */ 62805e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 629aca7a94dSNamhyung Kim break; 630aca7a94dSNamhyung Kim case 'E': 631aca7a94dSNamhyung Kim /* Expand the whole world. */ 63205e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 633aca7a94dSNamhyung Kim break; 634025bf7eaSArnaldo Carvalho de Melo case 'H': 635025bf7eaSArnaldo Carvalho de Melo browser->show_headers = !browser->show_headers; 636025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(browser); 637025bf7eaSArnaldo Carvalho de Melo break; 638aca7a94dSNamhyung Kim case K_ENTER: 63905e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 640aca7a94dSNamhyung Kim break; 641aca7a94dSNamhyung Kim /* fall thru */ 642aca7a94dSNamhyung Kim default: 643aca7a94dSNamhyung Kim goto out; 644aca7a94dSNamhyung Kim } 645aca7a94dSNamhyung Kim } 646aca7a94dSNamhyung Kim out: 64705e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 648aca7a94dSNamhyung Kim return key; 649aca7a94dSNamhyung Kim } 650aca7a94dSNamhyung Kim 65139ee533fSNamhyung Kim struct callchain_print_arg { 65239ee533fSNamhyung Kim /* for hists browser */ 65339ee533fSNamhyung Kim off_t row_offset; 65439ee533fSNamhyung Kim bool is_current_entry; 65539ee533fSNamhyung Kim 65639ee533fSNamhyung Kim /* for file dump */ 65739ee533fSNamhyung Kim FILE *fp; 65839ee533fSNamhyung Kim int printed; 65939ee533fSNamhyung Kim }; 66039ee533fSNamhyung Kim 66139ee533fSNamhyung Kim typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, 66239ee533fSNamhyung Kim struct callchain_list *chain, 66339ee533fSNamhyung Kim const char *str, int offset, 66439ee533fSNamhyung Kim unsigned short row, 66539ee533fSNamhyung Kim struct callchain_print_arg *arg); 66639ee533fSNamhyung Kim 667f4536dddSNamhyung Kim static void hist_browser__show_callchain_entry(struct hist_browser *browser, 668f4536dddSNamhyung Kim struct callchain_list *chain, 66939ee533fSNamhyung Kim const char *str, int offset, 67039ee533fSNamhyung Kim unsigned short row, 67139ee533fSNamhyung Kim struct callchain_print_arg *arg) 672f4536dddSNamhyung Kim { 673f4536dddSNamhyung Kim int color, width; 67439ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 67570e97278SArnaldo Carvalho de Melo bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src; 676f4536dddSNamhyung Kim 677f4536dddSNamhyung Kim color = HE_COLORSET_NORMAL; 678f4536dddSNamhyung Kim width = browser->b.width - (offset + 2); 679f4536dddSNamhyung Kim if (ui_browser__is_current_entry(&browser->b, row)) { 680f4536dddSNamhyung Kim browser->selection = &chain->ms; 681f4536dddSNamhyung Kim color = HE_COLORSET_SELECTED; 68239ee533fSNamhyung Kim arg->is_current_entry = true; 683f4536dddSNamhyung Kim } 684f4536dddSNamhyung Kim 685f4536dddSNamhyung Kim ui_browser__set_color(&browser->b, color); 686f4536dddSNamhyung Kim hist_browser__gotorc(browser, row, 0); 68726270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, " ", offset); 688517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c", folded_sign); 68970e97278SArnaldo Carvalho de Melo ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); 69026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, str, width); 691f4536dddSNamhyung Kim } 692f4536dddSNamhyung Kim 69339ee533fSNamhyung Kim static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, 69439ee533fSNamhyung Kim struct callchain_list *chain, 69539ee533fSNamhyung Kim const char *str, int offset, 69639ee533fSNamhyung Kim unsigned short row __maybe_unused, 69739ee533fSNamhyung Kim struct callchain_print_arg *arg) 69839ee533fSNamhyung Kim { 69939ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 70039ee533fSNamhyung Kim 70139ee533fSNamhyung Kim arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", 70239ee533fSNamhyung Kim folded_sign, str); 70339ee533fSNamhyung Kim } 70439ee533fSNamhyung Kim 70539ee533fSNamhyung Kim typedef bool (*check_output_full_fn)(struct hist_browser *browser, 70639ee533fSNamhyung Kim unsigned short row); 70739ee533fSNamhyung Kim 70839ee533fSNamhyung Kim static bool hist_browser__check_output_full(struct hist_browser *browser, 70939ee533fSNamhyung Kim unsigned short row) 71039ee533fSNamhyung Kim { 71139ee533fSNamhyung Kim return browser->b.rows == row; 71239ee533fSNamhyung Kim } 71339ee533fSNamhyung Kim 71439ee533fSNamhyung Kim static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, 71539ee533fSNamhyung Kim unsigned short row __maybe_unused) 71639ee533fSNamhyung Kim { 71739ee533fSNamhyung Kim return false; 71839ee533fSNamhyung Kim } 71939ee533fSNamhyung Kim 720aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 721aca7a94dSNamhyung Kim 72218bb8381SNamhyung Kim static int hist_browser__show_callchain_list(struct hist_browser *browser, 72318bb8381SNamhyung Kim struct callchain_node *node, 72418bb8381SNamhyung Kim struct callchain_list *chain, 72518bb8381SNamhyung Kim unsigned short row, u64 total, 72618bb8381SNamhyung Kim bool need_percent, int offset, 72718bb8381SNamhyung Kim print_callchain_entry_fn print, 72818bb8381SNamhyung Kim struct callchain_print_arg *arg) 72918bb8381SNamhyung Kim { 73018bb8381SNamhyung Kim char bf[1024], *alloc_str; 73118bb8381SNamhyung Kim const char *str; 73218bb8381SNamhyung Kim 73318bb8381SNamhyung Kim if (arg->row_offset != 0) { 73418bb8381SNamhyung Kim arg->row_offset--; 73518bb8381SNamhyung Kim return 0; 73618bb8381SNamhyung Kim } 73718bb8381SNamhyung Kim 73818bb8381SNamhyung Kim alloc_str = NULL; 73918bb8381SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 74018bb8381SNamhyung Kim browser->show_dso); 74118bb8381SNamhyung Kim 74218bb8381SNamhyung Kim if (need_percent) { 74318bb8381SNamhyung Kim char buf[64]; 74418bb8381SNamhyung Kim 74518bb8381SNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), 74618bb8381SNamhyung Kim total); 74718bb8381SNamhyung Kim 74818bb8381SNamhyung Kim if (asprintf(&alloc_str, "%s %s", buf, str) < 0) 74918bb8381SNamhyung Kim str = "Not enough memory!"; 75018bb8381SNamhyung Kim else 75118bb8381SNamhyung Kim str = alloc_str; 75218bb8381SNamhyung Kim } 75318bb8381SNamhyung Kim 75418bb8381SNamhyung Kim print(browser, chain, str, offset, row, arg); 75518bb8381SNamhyung Kim 75618bb8381SNamhyung Kim free(alloc_str); 75718bb8381SNamhyung Kim return 1; 75818bb8381SNamhyung Kim } 75918bb8381SNamhyung Kim 76059c624e2SNamhyung Kim static bool check_percent_display(struct rb_node *node, u64 parent_total) 76159c624e2SNamhyung Kim { 76259c624e2SNamhyung Kim struct callchain_node *child; 76359c624e2SNamhyung Kim 76459c624e2SNamhyung Kim if (node == NULL) 76559c624e2SNamhyung Kim return false; 76659c624e2SNamhyung Kim 76759c624e2SNamhyung Kim if (rb_next(node)) 76859c624e2SNamhyung Kim return true; 76959c624e2SNamhyung Kim 77059c624e2SNamhyung Kim child = rb_entry(node, struct callchain_node, rb_node); 77159c624e2SNamhyung Kim return callchain_cumul_hits(child) != parent_total; 77259c624e2SNamhyung Kim } 77359c624e2SNamhyung Kim 7744b3a3212SNamhyung Kim static int hist_browser__show_callchain_flat(struct hist_browser *browser, 7754b3a3212SNamhyung Kim struct rb_root *root, 7764b3a3212SNamhyung Kim unsigned short row, u64 total, 77759c624e2SNamhyung Kim u64 parent_total, 7784b3a3212SNamhyung Kim print_callchain_entry_fn print, 7794b3a3212SNamhyung Kim struct callchain_print_arg *arg, 7804b3a3212SNamhyung Kim check_output_full_fn is_output_full) 7814b3a3212SNamhyung Kim { 7824b3a3212SNamhyung Kim struct rb_node *node; 7834b3a3212SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 7844b3a3212SNamhyung Kim bool need_percent; 7854b3a3212SNamhyung Kim 7864b3a3212SNamhyung Kim node = rb_first(root); 78759c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 7884b3a3212SNamhyung Kim 7894b3a3212SNamhyung Kim while (node) { 7904b3a3212SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 7914b3a3212SNamhyung Kim struct rb_node *next = rb_next(node); 7924b3a3212SNamhyung Kim struct callchain_list *chain; 7934b3a3212SNamhyung Kim char folded_sign = ' '; 7944b3a3212SNamhyung Kim int first = true; 7954b3a3212SNamhyung Kim int extra_offset = 0; 7964b3a3212SNamhyung Kim 7974b3a3212SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 7984b3a3212SNamhyung Kim bool was_first = first; 7994b3a3212SNamhyung Kim 8004b3a3212SNamhyung Kim if (first) 8014b3a3212SNamhyung Kim first = false; 8024b3a3212SNamhyung Kim else if (need_percent) 8034b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 8044b3a3212SNamhyung Kim 8054b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 8064b3a3212SNamhyung Kim 8074b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 8084b3a3212SNamhyung Kim chain, row, total, 8094b3a3212SNamhyung Kim was_first && need_percent, 8104b3a3212SNamhyung Kim offset + extra_offset, 8114b3a3212SNamhyung Kim print, arg); 8124b3a3212SNamhyung Kim 8134b3a3212SNamhyung Kim if (is_output_full(browser, row)) 8144b3a3212SNamhyung Kim goto out; 8154b3a3212SNamhyung Kim 8164b3a3212SNamhyung Kim if (folded_sign == '+') 8174b3a3212SNamhyung Kim goto next; 8184b3a3212SNamhyung Kim } 8194b3a3212SNamhyung Kim 8204b3a3212SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 8214b3a3212SNamhyung Kim bool was_first = first; 8224b3a3212SNamhyung Kim 8234b3a3212SNamhyung Kim if (first) 8244b3a3212SNamhyung Kim first = false; 8254b3a3212SNamhyung Kim else if (need_percent) 8264b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 8274b3a3212SNamhyung Kim 8284b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 8294b3a3212SNamhyung Kim 8304b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 8314b3a3212SNamhyung Kim chain, row, total, 8324b3a3212SNamhyung Kim was_first && need_percent, 8334b3a3212SNamhyung Kim offset + extra_offset, 8344b3a3212SNamhyung Kim print, arg); 8354b3a3212SNamhyung Kim 8364b3a3212SNamhyung Kim if (is_output_full(browser, row)) 8374b3a3212SNamhyung Kim goto out; 8384b3a3212SNamhyung Kim 8394b3a3212SNamhyung Kim if (folded_sign == '+') 8404b3a3212SNamhyung Kim break; 8414b3a3212SNamhyung Kim } 8424b3a3212SNamhyung Kim 8434b3a3212SNamhyung Kim next: 8444b3a3212SNamhyung Kim if (is_output_full(browser, row)) 8454b3a3212SNamhyung Kim break; 8464b3a3212SNamhyung Kim node = next; 8474b3a3212SNamhyung Kim } 8484b3a3212SNamhyung Kim out: 8494b3a3212SNamhyung Kim return row - first_row; 8504b3a3212SNamhyung Kim } 8514b3a3212SNamhyung Kim 8528c430a34SNamhyung Kim static char *hist_browser__folded_callchain_str(struct hist_browser *browser, 8538c430a34SNamhyung Kim struct callchain_list *chain, 8548c430a34SNamhyung Kim char *value_str, char *old_str) 8558c430a34SNamhyung Kim { 8568c430a34SNamhyung Kim char bf[1024]; 8578c430a34SNamhyung Kim const char *str; 8588c430a34SNamhyung Kim char *new; 8598c430a34SNamhyung Kim 8608c430a34SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 8618c430a34SNamhyung Kim browser->show_dso); 8628c430a34SNamhyung Kim if (old_str) { 8638c430a34SNamhyung Kim if (asprintf(&new, "%s%s%s", old_str, 8648c430a34SNamhyung Kim symbol_conf.field_sep ?: ";", str) < 0) 8658c430a34SNamhyung Kim new = NULL; 8668c430a34SNamhyung Kim } else { 8678c430a34SNamhyung Kim if (value_str) { 8688c430a34SNamhyung Kim if (asprintf(&new, "%s %s", value_str, str) < 0) 8698c430a34SNamhyung Kim new = NULL; 8708c430a34SNamhyung Kim } else { 8718c430a34SNamhyung Kim if (asprintf(&new, "%s", str) < 0) 8728c430a34SNamhyung Kim new = NULL; 8738c430a34SNamhyung Kim } 8748c430a34SNamhyung Kim } 8758c430a34SNamhyung Kim return new; 8768c430a34SNamhyung Kim } 8778c430a34SNamhyung Kim 8788c430a34SNamhyung Kim static int hist_browser__show_callchain_folded(struct hist_browser *browser, 8798c430a34SNamhyung Kim struct rb_root *root, 8808c430a34SNamhyung Kim unsigned short row, u64 total, 88159c624e2SNamhyung Kim u64 parent_total, 8828c430a34SNamhyung Kim print_callchain_entry_fn print, 8838c430a34SNamhyung Kim struct callchain_print_arg *arg, 8848c430a34SNamhyung Kim check_output_full_fn is_output_full) 8858c430a34SNamhyung Kim { 8868c430a34SNamhyung Kim struct rb_node *node; 8878c430a34SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 8888c430a34SNamhyung Kim bool need_percent; 8898c430a34SNamhyung Kim 8908c430a34SNamhyung Kim node = rb_first(root); 89159c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 8928c430a34SNamhyung Kim 8938c430a34SNamhyung Kim while (node) { 8948c430a34SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 8958c430a34SNamhyung Kim struct rb_node *next = rb_next(node); 8968c430a34SNamhyung Kim struct callchain_list *chain, *first_chain = NULL; 8978c430a34SNamhyung Kim int first = true; 8988c430a34SNamhyung Kim char *value_str = NULL, *value_str_alloc = NULL; 8998c430a34SNamhyung Kim char *chain_str = NULL, *chain_str_alloc = NULL; 9008c430a34SNamhyung Kim 9018c430a34SNamhyung Kim if (arg->row_offset != 0) { 9028c430a34SNamhyung Kim arg->row_offset--; 9038c430a34SNamhyung Kim goto next; 9048c430a34SNamhyung Kim } 9058c430a34SNamhyung Kim 9068c430a34SNamhyung Kim if (need_percent) { 9078c430a34SNamhyung Kim char buf[64]; 9088c430a34SNamhyung Kim 9098c430a34SNamhyung Kim callchain_node__scnprintf_value(child, buf, sizeof(buf), total); 9108c430a34SNamhyung Kim if (asprintf(&value_str, "%s", buf) < 0) { 9118c430a34SNamhyung Kim value_str = (char *)"<...>"; 9128c430a34SNamhyung Kim goto do_print; 9138c430a34SNamhyung Kim } 9148c430a34SNamhyung Kim value_str_alloc = value_str; 9158c430a34SNamhyung Kim } 9168c430a34SNamhyung Kim 9178c430a34SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 9188c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 9198c430a34SNamhyung Kim chain, value_str, chain_str); 9208c430a34SNamhyung Kim if (first) { 9218c430a34SNamhyung Kim first = false; 9228c430a34SNamhyung Kim first_chain = chain; 9238c430a34SNamhyung Kim } 9248c430a34SNamhyung Kim 9258c430a34SNamhyung Kim if (chain_str == NULL) { 9268c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 9278c430a34SNamhyung Kim goto do_print; 9288c430a34SNamhyung Kim } 9298c430a34SNamhyung Kim 9308c430a34SNamhyung Kim chain_str_alloc = chain_str; 9318c430a34SNamhyung Kim } 9328c430a34SNamhyung Kim 9338c430a34SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 9348c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 9358c430a34SNamhyung Kim chain, value_str, chain_str); 9368c430a34SNamhyung Kim if (first) { 9378c430a34SNamhyung Kim first = false; 9388c430a34SNamhyung Kim first_chain = chain; 9398c430a34SNamhyung Kim } 9408c430a34SNamhyung Kim 9418c430a34SNamhyung Kim if (chain_str == NULL) { 9428c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 9438c430a34SNamhyung Kim goto do_print; 9448c430a34SNamhyung Kim } 9458c430a34SNamhyung Kim 9468c430a34SNamhyung Kim chain_str_alloc = chain_str; 9478c430a34SNamhyung Kim } 9488c430a34SNamhyung Kim 9498c430a34SNamhyung Kim do_print: 9508c430a34SNamhyung Kim print(browser, first_chain, chain_str, offset, row++, arg); 9518c430a34SNamhyung Kim free(value_str_alloc); 9528c430a34SNamhyung Kim free(chain_str_alloc); 9538c430a34SNamhyung Kim 9548c430a34SNamhyung Kim next: 9558c430a34SNamhyung Kim if (is_output_full(browser, row)) 9568c430a34SNamhyung Kim break; 9578c430a34SNamhyung Kim node = next; 9588c430a34SNamhyung Kim } 9598c430a34SNamhyung Kim 9608c430a34SNamhyung Kim return row - first_row; 9618c430a34SNamhyung Kim } 9628c430a34SNamhyung Kim 9630c841c6cSNamhyung Kim static int hist_browser__show_callchain_graph(struct hist_browser *browser, 964c09a7e75SNamhyung Kim struct rb_root *root, int level, 96539ee533fSNamhyung Kim unsigned short row, u64 total, 9665eca104eSNamhyung Kim u64 parent_total, 96739ee533fSNamhyung Kim print_callchain_entry_fn print, 96839ee533fSNamhyung Kim struct callchain_print_arg *arg, 96939ee533fSNamhyung Kim check_output_full_fn is_output_full) 970aca7a94dSNamhyung Kim { 971aca7a94dSNamhyung Kim struct rb_node *node; 972f4536dddSNamhyung Kim int first_row = row, offset = level * LEVEL_OFFSET_STEP; 9734087d11cSNamhyung Kim bool need_percent; 9745eca104eSNamhyung Kim u64 percent_total = total; 9755eca104eSNamhyung Kim 9765eca104eSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 9775eca104eSNamhyung Kim percent_total = parent_total; 978aca7a94dSNamhyung Kim 979c09a7e75SNamhyung Kim node = rb_first(root); 98059c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 9814087d11cSNamhyung Kim 982aca7a94dSNamhyung Kim while (node) { 983aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 984aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 985aca7a94dSNamhyung Kim struct callchain_list *chain; 986aca7a94dSNamhyung Kim char folded_sign = ' '; 987aca7a94dSNamhyung Kim int first = true; 988aca7a94dSNamhyung Kim int extra_offset = 0; 989aca7a94dSNamhyung Kim 990aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 991aca7a94dSNamhyung Kim bool was_first = first; 992aca7a94dSNamhyung Kim 993aca7a94dSNamhyung Kim if (first) 994aca7a94dSNamhyung Kim first = false; 9954087d11cSNamhyung Kim else if (need_percent) 996aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 997aca7a94dSNamhyung Kim 998aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 999aca7a94dSNamhyung Kim 100018bb8381SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 10015eca104eSNamhyung Kim chain, row, percent_total, 100218bb8381SNamhyung Kim was_first && need_percent, 100318bb8381SNamhyung Kim offset + extra_offset, 100418bb8381SNamhyung Kim print, arg); 1005c09a7e75SNamhyung Kim 100618bb8381SNamhyung Kim if (is_output_full(browser, row)) 1007aca7a94dSNamhyung Kim goto out; 100818bb8381SNamhyung Kim 1009aca7a94dSNamhyung Kim if (folded_sign == '+') 1010aca7a94dSNamhyung Kim break; 1011aca7a94dSNamhyung Kim } 1012aca7a94dSNamhyung Kim 1013aca7a94dSNamhyung Kim if (folded_sign == '-') { 1014aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 1015c09a7e75SNamhyung Kim 10160c841c6cSNamhyung Kim row += hist_browser__show_callchain_graph(browser, &child->rb_root, 10175eca104eSNamhyung Kim new_level, row, total, 10185eca104eSNamhyung Kim child->children_hit, 101939ee533fSNamhyung Kim print, arg, is_output_full); 1020aca7a94dSNamhyung Kim } 102139ee533fSNamhyung Kim if (is_output_full(browser, row)) 1022c09a7e75SNamhyung Kim break; 1023aca7a94dSNamhyung Kim node = next; 1024aca7a94dSNamhyung Kim } 1025aca7a94dSNamhyung Kim out: 1026aca7a94dSNamhyung Kim return row - first_row; 1027aca7a94dSNamhyung Kim } 1028aca7a94dSNamhyung Kim 10290c841c6cSNamhyung Kim static int hist_browser__show_callchain(struct hist_browser *browser, 10300c841c6cSNamhyung Kim struct hist_entry *entry, int level, 10310c841c6cSNamhyung Kim unsigned short row, 10320c841c6cSNamhyung Kim print_callchain_entry_fn print, 10330c841c6cSNamhyung Kim struct callchain_print_arg *arg, 10340c841c6cSNamhyung Kim check_output_full_fn is_output_full) 10350c841c6cSNamhyung Kim { 10360c841c6cSNamhyung Kim u64 total = hists__total_period(entry->hists); 10375eca104eSNamhyung Kim u64 parent_total; 10380c841c6cSNamhyung Kim int printed; 10390c841c6cSNamhyung Kim 10400c841c6cSNamhyung Kim if (symbol_conf.cumulate_callchain) 10415eca104eSNamhyung Kim parent_total = entry->stat_acc->period; 10420c841c6cSNamhyung Kim else 10435eca104eSNamhyung Kim parent_total = entry->stat.period; 10440c841c6cSNamhyung Kim 10450c841c6cSNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) { 10460c841c6cSNamhyung Kim printed = hist_browser__show_callchain_flat(browser, 10475eca104eSNamhyung Kim &entry->sorted_chain, row, 10485eca104eSNamhyung Kim total, parent_total, print, arg, 10495eca104eSNamhyung Kim is_output_full); 10500c841c6cSNamhyung Kim } else if (callchain_param.mode == CHAIN_FOLDED) { 10510c841c6cSNamhyung Kim printed = hist_browser__show_callchain_folded(browser, 10525eca104eSNamhyung Kim &entry->sorted_chain, row, 10535eca104eSNamhyung Kim total, parent_total, print, arg, 10545eca104eSNamhyung Kim is_output_full); 10550c841c6cSNamhyung Kim } else { 10560c841c6cSNamhyung Kim printed = hist_browser__show_callchain_graph(browser, 10575eca104eSNamhyung Kim &entry->sorted_chain, level, row, 10585eca104eSNamhyung Kim total, parent_total, print, arg, 10595eca104eSNamhyung Kim is_output_full); 10600c841c6cSNamhyung Kim } 10610c841c6cSNamhyung Kim 10620c841c6cSNamhyung Kim if (arg->is_current_entry) 10630c841c6cSNamhyung Kim browser->he_selection = entry; 10640c841c6cSNamhyung Kim 10650c841c6cSNamhyung Kim return printed; 10660c841c6cSNamhyung Kim } 10670c841c6cSNamhyung Kim 106889701460SNamhyung Kim struct hpp_arg { 106989701460SNamhyung Kim struct ui_browser *b; 107089701460SNamhyung Kim char folded_sign; 107189701460SNamhyung Kim bool current_entry; 107289701460SNamhyung Kim }; 107389701460SNamhyung Kim 10742f6d9009SNamhyung Kim static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 10752f6d9009SNamhyung Kim { 10762f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 1077d675107cSNamhyung Kim int ret, len; 10782f6d9009SNamhyung Kim va_list args; 10792f6d9009SNamhyung Kim double percent; 10802f6d9009SNamhyung Kim 10812f6d9009SNamhyung Kim va_start(args, fmt); 1082d675107cSNamhyung Kim len = va_arg(args, int); 10832f6d9009SNamhyung Kim percent = va_arg(args, double); 10842f6d9009SNamhyung Kim va_end(args); 10855aed9d24SNamhyung Kim 108689701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 10875aed9d24SNamhyung Kim 1088d675107cSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); 1089517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); 109089701460SNamhyung Kim 10912f6d9009SNamhyung Kim advance_hpp(hpp, ret); 10925aed9d24SNamhyung Kim return ret; 1093f5951d56SNamhyung Kim } 1094f5951d56SNamhyung Kim 1095fb821c9eSNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field) \ 10965aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 10975aed9d24SNamhyung Kim { \ 10985aed9d24SNamhyung Kim return he->stat._field; \ 10995aed9d24SNamhyung Kim } \ 11005aed9d24SNamhyung Kim \ 11012c5d4b4aSJiri Olsa static int \ 11025b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 11032c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 11045aed9d24SNamhyung Kim struct hist_entry *he) \ 11055aed9d24SNamhyung Kim { \ 11065b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \ 11072f6d9009SNamhyung Kim __hpp__slsmg_color_printf, true); \ 11085aed9d24SNamhyung Kim } 1109f5951d56SNamhyung Kim 11100434ddd2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 11110434ddd2SNamhyung Kim static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ 11120434ddd2SNamhyung Kim { \ 11130434ddd2SNamhyung Kim return he->stat_acc->_field; \ 11140434ddd2SNamhyung Kim } \ 11150434ddd2SNamhyung Kim \ 11160434ddd2SNamhyung Kim static int \ 11175b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 11180434ddd2SNamhyung Kim struct perf_hpp *hpp, \ 11190434ddd2SNamhyung Kim struct hist_entry *he) \ 11200434ddd2SNamhyung Kim { \ 11210434ddd2SNamhyung Kim if (!symbol_conf.cumulate_callchain) { \ 1122517dfdb3SArnaldo Carvalho de Melo struct hpp_arg *arg = hpp->ptr; \ 11235b591669SNamhyung Kim int len = fmt->user_len ?: fmt->len; \ 1124d675107cSNamhyung Kim int ret = scnprintf(hpp->buf, hpp->size, \ 11255b591669SNamhyung Kim "%*s", len, "N/A"); \ 1126517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); \ 11270434ddd2SNamhyung Kim \ 11280434ddd2SNamhyung Kim return ret; \ 11290434ddd2SNamhyung Kim } \ 11305b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \ 11315b591669SNamhyung Kim " %*.2f%%", __hpp__slsmg_color_printf, true); \ 11320434ddd2SNamhyung Kim } 11330434ddd2SNamhyung Kim 1134fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period) 1135fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 1136fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us) 1137fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 1138fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 11390434ddd2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period) 11405aed9d24SNamhyung Kim 11415aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 11420434ddd2SNamhyung Kim #undef __HPP_COLOR_ACC_PERCENT_FN 1143f5951d56SNamhyung Kim 1144f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 1145f5951d56SNamhyung Kim { 1146f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 1147f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 1148f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 1149f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 1150f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 1151f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 1152f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 1153f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 1154f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 1155f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 11560434ddd2SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = 11570434ddd2SNamhyung Kim hist_browser__hpp_color_overhead_acc; 1158f5951d56SNamhyung Kim } 1159f5951d56SNamhyung Kim 116005e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 1161aca7a94dSNamhyung Kim struct hist_entry *entry, 1162aca7a94dSNamhyung Kim unsigned short row) 1163aca7a94dSNamhyung Kim { 11641240005eSJiri Olsa int printed = 0; 116567d25916SNamhyung Kim int width = browser->b.width; 1166aca7a94dSNamhyung Kim char folded_sign = ' '; 116705e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1168aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 116963a1a3d8SNamhyung Kim bool first = true; 11701240005eSJiri Olsa struct perf_hpp_fmt *fmt; 1171aca7a94dSNamhyung Kim 1172aca7a94dSNamhyung Kim if (current_entry) { 117305e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 117405e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 1175aca7a94dSNamhyung Kim } 1176aca7a94dSNamhyung Kim 1177aca7a94dSNamhyung Kim if (symbol_conf.use_callchain) { 1178aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 1179aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 1180aca7a94dSNamhyung Kim } 1181aca7a94dSNamhyung Kim 1182aca7a94dSNamhyung Kim if (row_offset == 0) { 118389701460SNamhyung Kim struct hpp_arg arg = { 118489701460SNamhyung Kim .b = &browser->b, 118589701460SNamhyung Kim .folded_sign = folded_sign, 118689701460SNamhyung Kim .current_entry = current_entry, 118789701460SNamhyung Kim }; 1188c6c3c02dSArnaldo Carvalho de Melo int column = 0; 1189f5951d56SNamhyung Kim 1190ca3ff33bSArnaldo Carvalho de Melo hist_browser__gotorc(browser, row, 0); 1191f5951d56SNamhyung Kim 1192f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 119389fee709SArnaldo Carvalho de Melo char s[2048]; 119489fee709SArnaldo Carvalho de Melo struct perf_hpp hpp = { 119589fee709SArnaldo Carvalho de Melo .buf = s, 119689fee709SArnaldo Carvalho de Melo .size = sizeof(s), 119789fee709SArnaldo Carvalho de Melo .ptr = &arg, 119889fee709SArnaldo Carvalho de Melo }; 119989fee709SArnaldo Carvalho de Melo 1200361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1201361459f1SNamhyung Kim column++ < browser->b.horiz_scroll) 1202e67d49a7SNamhyung Kim continue; 1203e67d49a7SNamhyung Kim 1204fb821c9eSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1205fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1206fb821c9eSNamhyung Kim HE_COLORSET_SELECTED); 1207fb821c9eSNamhyung Kim } else { 1208fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1209fb821c9eSNamhyung Kim HE_COLORSET_NORMAL); 1210fb821c9eSNamhyung Kim } 1211fb821c9eSNamhyung Kim 1212fb821c9eSNamhyung Kim if (first) { 1213fb821c9eSNamhyung Kim if (symbol_conf.use_callchain) { 1214517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c ", folded_sign); 1215f5951d56SNamhyung Kim width -= 2; 1216f5951d56SNamhyung Kim } 121763a1a3d8SNamhyung Kim first = false; 1218fb821c9eSNamhyung Kim } else { 1219517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, " "); 1220fb821c9eSNamhyung Kim width -= 2; 1221fb821c9eSNamhyung Kim } 1222f5951d56SNamhyung Kim 12231240005eSJiri Olsa if (fmt->color) { 122489fee709SArnaldo Carvalho de Melo int ret = fmt->color(fmt, &hpp, entry); 122589fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 122689fee709SArnaldo Carvalho de Melo /* 122789fee709SArnaldo Carvalho de Melo * fmt->color() already used ui_browser to 122889fee709SArnaldo Carvalho de Melo * print the non alignment bits, skip it (+ret): 122989fee709SArnaldo Carvalho de Melo */ 123089fee709SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s + ret); 1231f5951d56SNamhyung Kim } else { 123289fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry)); 1233517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s); 1234f5951d56SNamhyung Kim } 123589fee709SArnaldo Carvalho de Melo width -= hpp.buf - s; 1236f5951d56SNamhyung Kim } 1237aca7a94dSNamhyung Kim 1238aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 123905e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 1240aca7a94dSNamhyung Kim width += 1; 1241aca7a94dSNamhyung Kim 124226270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, "", width); 124326d8b338SNamhyung Kim 1244aca7a94dSNamhyung Kim ++row; 1245aca7a94dSNamhyung Kim ++printed; 1246aca7a94dSNamhyung Kim } else 1247aca7a94dSNamhyung Kim --row_offset; 1248aca7a94dSNamhyung Kim 124962c95ae3SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.rows) { 125039ee533fSNamhyung Kim struct callchain_print_arg arg = { 125139ee533fSNamhyung Kim .row_offset = row_offset, 125239ee533fSNamhyung Kim .is_current_entry = current_entry, 125339ee533fSNamhyung Kim }; 1254c09a7e75SNamhyung Kim 12550c841c6cSNamhyung Kim printed += hist_browser__show_callchain(browser, entry, 1, row, 12564b3a3212SNamhyung Kim hist_browser__show_callchain_entry, &arg, 12574b3a3212SNamhyung Kim hist_browser__check_output_full); 1258aca7a94dSNamhyung Kim } 1259aca7a94dSNamhyung Kim 1260aca7a94dSNamhyung Kim return printed; 1261aca7a94dSNamhyung Kim } 1262aca7a94dSNamhyung Kim 1263d0506edbSNamhyung Kim static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, 1264d0506edbSNamhyung Kim struct hist_entry *entry, 1265d0506edbSNamhyung Kim unsigned short row, 12662dbbe9f2SNamhyung Kim int level) 1267d0506edbSNamhyung Kim { 1268d0506edbSNamhyung Kim int printed = 0; 1269d0506edbSNamhyung Kim int width = browser->b.width; 1270d0506edbSNamhyung Kim char folded_sign = ' '; 1271d0506edbSNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1272d0506edbSNamhyung Kim off_t row_offset = entry->row_offset; 1273d0506edbSNamhyung Kim bool first = true; 1274d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 1275a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1276d0506edbSNamhyung Kim struct hpp_arg arg = { 1277d0506edbSNamhyung Kim .b = &browser->b, 1278d0506edbSNamhyung Kim .current_entry = current_entry, 1279d0506edbSNamhyung Kim }; 1280d0506edbSNamhyung Kim int column = 0; 12812dbbe9f2SNamhyung Kim int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 1282d0506edbSNamhyung Kim 1283d0506edbSNamhyung Kim if (current_entry) { 1284d0506edbSNamhyung Kim browser->he_selection = entry; 1285d0506edbSNamhyung Kim browser->selection = &entry->ms; 1286d0506edbSNamhyung Kim } 1287d0506edbSNamhyung Kim 1288d0506edbSNamhyung Kim hist_entry__init_have_children(entry); 1289d0506edbSNamhyung Kim folded_sign = hist_entry__folded(entry); 1290d0506edbSNamhyung Kim arg.folded_sign = folded_sign; 1291d0506edbSNamhyung Kim 1292d0506edbSNamhyung Kim if (entry->leaf && row_offset) { 1293d0506edbSNamhyung Kim row_offset--; 1294d0506edbSNamhyung Kim goto show_callchain; 1295d0506edbSNamhyung Kim } 1296d0506edbSNamhyung Kim 1297d0506edbSNamhyung Kim hist_browser__gotorc(browser, row, 0); 1298d0506edbSNamhyung Kim 1299d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) 1300d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 1301d0506edbSNamhyung Kim else 1302d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 1303d0506edbSNamhyung Kim 1304d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 1305d0506edbSNamhyung Kim width -= level * HIERARCHY_INDENT; 1306d0506edbSNamhyung Kim 1307a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1308a61a22f6SNamhyung Kim fmt_node = list_first_entry(&entry->hists->hpp_formats, 1309a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1310a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1311d0506edbSNamhyung Kim char s[2048]; 1312d0506edbSNamhyung Kim struct perf_hpp hpp = { 1313d0506edbSNamhyung Kim .buf = s, 1314d0506edbSNamhyung Kim .size = sizeof(s), 1315d0506edbSNamhyung Kim .ptr = &arg, 1316d0506edbSNamhyung Kim }; 1317d0506edbSNamhyung Kim 1318d0506edbSNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1319d0506edbSNamhyung Kim column++ < browser->b.horiz_scroll) 1320d0506edbSNamhyung Kim continue; 1321d0506edbSNamhyung Kim 1322d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1323d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1324d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1325d0506edbSNamhyung Kim } else { 1326d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1327d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1328d0506edbSNamhyung Kim } 1329d0506edbSNamhyung Kim 1330d0506edbSNamhyung Kim if (first) { 1331d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%c", folded_sign); 1332d0506edbSNamhyung Kim width--; 1333d0506edbSNamhyung Kim first = false; 1334d0506edbSNamhyung Kim } else { 1335d0506edbSNamhyung Kim ui_browser__printf(&browser->b, " "); 1336d0506edbSNamhyung Kim width -= 2; 1337d0506edbSNamhyung Kim } 1338d0506edbSNamhyung Kim 1339d0506edbSNamhyung Kim if (fmt->color) { 1340d0506edbSNamhyung Kim int ret = fmt->color(fmt, &hpp, entry); 1341d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1342d0506edbSNamhyung Kim /* 1343d0506edbSNamhyung Kim * fmt->color() already used ui_browser to 1344d0506edbSNamhyung Kim * print the non alignment bits, skip it (+ret): 1345d0506edbSNamhyung Kim */ 1346d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s + ret); 1347d0506edbSNamhyung Kim } else { 1348d0506edbSNamhyung Kim int ret = fmt->entry(fmt, &hpp, entry); 1349d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1350d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s); 1351d0506edbSNamhyung Kim } 1352d0506edbSNamhyung Kim width -= hpp.buf - s; 1353d0506edbSNamhyung Kim } 1354d0506edbSNamhyung Kim 1355d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", hierarchy_indent); 1356d0506edbSNamhyung Kim width -= hierarchy_indent; 1357d0506edbSNamhyung Kim 1358d0506edbSNamhyung Kim if (column >= browser->b.horiz_scroll) { 1359d0506edbSNamhyung Kim char s[2048]; 1360d0506edbSNamhyung Kim struct perf_hpp hpp = { 1361d0506edbSNamhyung Kim .buf = s, 1362d0506edbSNamhyung Kim .size = sizeof(s), 1363d0506edbSNamhyung Kim .ptr = &arg, 1364d0506edbSNamhyung Kim }; 1365d0506edbSNamhyung Kim 1366d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1367d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1368d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1369d0506edbSNamhyung Kim } else { 1370d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1371d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1372d0506edbSNamhyung Kim } 1373d0506edbSNamhyung Kim 13741b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(entry->hpp_list, fmt) { 1375d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", 2); 1376d0506edbSNamhyung Kim width -= 2; 1377d0506edbSNamhyung Kim 1378d0506edbSNamhyung Kim /* 1379d0506edbSNamhyung Kim * No need to call hist_entry__snprintf_alignment() 1380d0506edbSNamhyung Kim * since this fmt is always the last column in the 1381d0506edbSNamhyung Kim * hierarchy mode. 1382d0506edbSNamhyung Kim */ 1383d0506edbSNamhyung Kim if (fmt->color) { 1384d0506edbSNamhyung Kim width -= fmt->color(fmt, &hpp, entry); 1385d0506edbSNamhyung Kim } else { 1386cb1fab91SNamhyung Kim int i = 0; 1387cb1fab91SNamhyung Kim 1388d0506edbSNamhyung Kim width -= fmt->entry(fmt, &hpp, entry); 1389cb1fab91SNamhyung Kim ui_browser__printf(&browser->b, "%s", ltrim(s)); 1390cb1fab91SNamhyung Kim 1391cb1fab91SNamhyung Kim while (isspace(s[i++])) 1392cb1fab91SNamhyung Kim width++; 1393d0506edbSNamhyung Kim } 1394d0506edbSNamhyung Kim } 13951b2dbbf4SNamhyung Kim } 1396d0506edbSNamhyung Kim 1397d0506edbSNamhyung Kim /* The scroll bar isn't being used */ 1398d0506edbSNamhyung Kim if (!browser->b.navkeypressed) 1399d0506edbSNamhyung Kim width += 1; 1400d0506edbSNamhyung Kim 1401d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 1402d0506edbSNamhyung Kim 1403d0506edbSNamhyung Kim ++row; 1404d0506edbSNamhyung Kim ++printed; 1405d0506edbSNamhyung Kim 1406d0506edbSNamhyung Kim show_callchain: 1407d0506edbSNamhyung Kim if (entry->leaf && folded_sign == '-' && row != browser->b.rows) { 1408d0506edbSNamhyung Kim struct callchain_print_arg carg = { 1409d0506edbSNamhyung Kim .row_offset = row_offset, 1410d0506edbSNamhyung Kim }; 1411d0506edbSNamhyung Kim 1412d0506edbSNamhyung Kim printed += hist_browser__show_callchain(browser, entry, 1413d0506edbSNamhyung Kim level + 1, row, 1414d0506edbSNamhyung Kim hist_browser__show_callchain_entry, &carg, 1415d0506edbSNamhyung Kim hist_browser__check_output_full); 1416d0506edbSNamhyung Kim } 1417d0506edbSNamhyung Kim 1418d0506edbSNamhyung Kim return printed; 1419d0506edbSNamhyung Kim } 1420d0506edbSNamhyung Kim 142179dded87SNamhyung Kim static int hist_browser__show_no_entry(struct hist_browser *browser, 14222dbbe9f2SNamhyung Kim unsigned short row, int level) 142379dded87SNamhyung Kim { 142479dded87SNamhyung Kim int width = browser->b.width; 142579dded87SNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 142679dded87SNamhyung Kim bool first = true; 142779dded87SNamhyung Kim int column = 0; 142879dded87SNamhyung Kim int ret; 142979dded87SNamhyung Kim struct perf_hpp_fmt *fmt; 1430a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 14312dbbe9f2SNamhyung Kim int indent = browser->hists->nr_hpp_node - 2; 143279dded87SNamhyung Kim 143379dded87SNamhyung Kim if (current_entry) { 143479dded87SNamhyung Kim browser->he_selection = NULL; 143579dded87SNamhyung Kim browser->selection = NULL; 143679dded87SNamhyung Kim } 143779dded87SNamhyung Kim 143879dded87SNamhyung Kim hist_browser__gotorc(browser, row, 0); 143979dded87SNamhyung Kim 144079dded87SNamhyung Kim if (current_entry && browser->b.navkeypressed) 144179dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 144279dded87SNamhyung Kim else 144379dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 144479dded87SNamhyung Kim 144579dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 144679dded87SNamhyung Kim width -= level * HIERARCHY_INDENT; 144779dded87SNamhyung Kim 1448a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1449a61a22f6SNamhyung Kim fmt_node = list_first_entry(&browser->hists->hpp_formats, 1450a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1451a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 145279dded87SNamhyung Kim if (perf_hpp__should_skip(fmt, browser->hists) || 145379dded87SNamhyung Kim column++ < browser->b.horiz_scroll) 145479dded87SNamhyung Kim continue; 145579dded87SNamhyung Kim 1456da1b0407SJiri Olsa ret = fmt->width(fmt, NULL, browser->hists); 145779dded87SNamhyung Kim 145879dded87SNamhyung Kim if (first) { 145979dded87SNamhyung Kim /* for folded sign */ 146079dded87SNamhyung Kim first = false; 146179dded87SNamhyung Kim ret++; 146279dded87SNamhyung Kim } else { 146379dded87SNamhyung Kim /* space between columns */ 146479dded87SNamhyung Kim ret += 2; 146579dded87SNamhyung Kim } 146679dded87SNamhyung Kim 146779dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", ret); 146879dded87SNamhyung Kim width -= ret; 146979dded87SNamhyung Kim } 147079dded87SNamhyung Kim 14712dbbe9f2SNamhyung Kim ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT); 14722dbbe9f2SNamhyung Kim width -= indent * HIERARCHY_INDENT; 147379dded87SNamhyung Kim 147479dded87SNamhyung Kim if (column >= browser->b.horiz_scroll) { 147579dded87SNamhyung Kim char buf[32]; 147679dded87SNamhyung Kim 147779dded87SNamhyung Kim ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt); 147879dded87SNamhyung Kim ui_browser__printf(&browser->b, " %s", buf); 147979dded87SNamhyung Kim width -= ret + 2; 148079dded87SNamhyung Kim } 148179dded87SNamhyung Kim 148279dded87SNamhyung Kim /* The scroll bar isn't being used */ 148379dded87SNamhyung Kim if (!browser->b.navkeypressed) 148479dded87SNamhyung Kim width += 1; 148579dded87SNamhyung Kim 148679dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 148779dded87SNamhyung Kim return 1; 148879dded87SNamhyung Kim } 148979dded87SNamhyung Kim 149081a888feSJiri Olsa static int advance_hpp_check(struct perf_hpp *hpp, int inc) 149181a888feSJiri Olsa { 149281a888feSJiri Olsa advance_hpp(hpp, inc); 149381a888feSJiri Olsa return hpp->size <= 0; 149481a888feSJiri Olsa } 149581a888feSJiri Olsa 1496c6c3c02dSArnaldo Carvalho de Melo static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size) 149781a888feSJiri Olsa { 1498c6c3c02dSArnaldo Carvalho de Melo struct hists *hists = browser->hists; 149981a888feSJiri Olsa struct perf_hpp dummy_hpp = { 150081a888feSJiri Olsa .buf = buf, 150181a888feSJiri Olsa .size = size, 150281a888feSJiri Olsa }; 150381a888feSJiri Olsa struct perf_hpp_fmt *fmt; 150481a888feSJiri Olsa size_t ret = 0; 1505c6c3c02dSArnaldo Carvalho de Melo int column = 0; 150681a888feSJiri Olsa 150781a888feSJiri Olsa if (symbol_conf.use_callchain) { 150881a888feSJiri Olsa ret = scnprintf(buf, size, " "); 150981a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 151081a888feSJiri Olsa return ret; 151181a888feSJiri Olsa } 151281a888feSJiri Olsa 1513f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 1514361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) 151581a888feSJiri Olsa continue; 151681a888feSJiri Olsa 151705372173SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists); 151881a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 151981a888feSJiri Olsa break; 152081a888feSJiri Olsa 152181a888feSJiri Olsa ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 152281a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 152381a888feSJiri Olsa break; 152481a888feSJiri Olsa } 152581a888feSJiri Olsa 152681a888feSJiri Olsa return ret; 152781a888feSJiri Olsa } 152881a888feSJiri Olsa 1529d8b92400SNamhyung Kim static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size) 1530d8b92400SNamhyung Kim { 1531d8b92400SNamhyung Kim struct hists *hists = browser->hists; 1532d8b92400SNamhyung Kim struct perf_hpp dummy_hpp = { 1533d8b92400SNamhyung Kim .buf = buf, 1534d8b92400SNamhyung Kim .size = size, 1535d8b92400SNamhyung Kim }; 1536d8b92400SNamhyung Kim struct perf_hpp_fmt *fmt; 1537a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1538d8b92400SNamhyung Kim size_t ret = 0; 1539d8b92400SNamhyung Kim int column = 0; 15402dbbe9f2SNamhyung Kim int indent = hists->nr_hpp_node - 2; 1541a61a22f6SNamhyung Kim bool first_node, first_col; 1542d8b92400SNamhyung Kim 1543d8b92400SNamhyung Kim ret = scnprintf(buf, size, " "); 1544d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1545d8b92400SNamhyung Kim return ret; 1546d8b92400SNamhyung Kim 1547a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1548a61a22f6SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 1549a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1550a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1551d8b92400SNamhyung Kim if (column++ < browser->b.horiz_scroll) 1552d8b92400SNamhyung Kim continue; 1553d8b92400SNamhyung Kim 155405372173SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists); 1555d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1556d8b92400SNamhyung Kim break; 1557d8b92400SNamhyung Kim 1558d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 1559d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1560d8b92400SNamhyung Kim break; 1561d8b92400SNamhyung Kim } 1562d8b92400SNamhyung Kim 1563d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s", 15642dbbe9f2SNamhyung Kim indent * HIERARCHY_INDENT, ""); 1565d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1566d8b92400SNamhyung Kim return ret; 1567d8b92400SNamhyung Kim 1568a61a22f6SNamhyung Kim first_node = true; 1569a61a22f6SNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) { 1570a61a22f6SNamhyung Kim if (!first_node) { 1571d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / "); 1572d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1573d8b92400SNamhyung Kim break; 1574d8b92400SNamhyung Kim } 1575a61a22f6SNamhyung Kim first_node = false; 1576a61a22f6SNamhyung Kim 1577a61a22f6SNamhyung Kim first_col = true; 1578a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1579a61a22f6SNamhyung Kim char *start; 1580a61a22f6SNamhyung Kim 1581a61a22f6SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 1582a61a22f6SNamhyung Kim continue; 1583a61a22f6SNamhyung Kim 1584a61a22f6SNamhyung Kim if (!first_col) { 1585a61a22f6SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+"); 1586a61a22f6SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1587a61a22f6SNamhyung Kim break; 1588a61a22f6SNamhyung Kim } 1589a61a22f6SNamhyung Kim first_col = false; 1590d8b92400SNamhyung Kim 159105372173SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists); 1592d8b92400SNamhyung Kim dummy_hpp.buf[ret] = '\0'; 1593d8b92400SNamhyung Kim 15947d6a7e78SJiri Olsa start = trim(dummy_hpp.buf); 1595cb1fab91SNamhyung Kim ret = strlen(start); 1596cb1fab91SNamhyung Kim 1597cb1fab91SNamhyung Kim if (start != dummy_hpp.buf) 1598cb1fab91SNamhyung Kim memmove(dummy_hpp.buf, start, ret + 1); 1599cb1fab91SNamhyung Kim 1600d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1601d8b92400SNamhyung Kim break; 1602d8b92400SNamhyung Kim } 1603a61a22f6SNamhyung Kim } 1604d8b92400SNamhyung Kim 1605d8b92400SNamhyung Kim return ret; 1606d8b92400SNamhyung Kim } 1607d8b92400SNamhyung Kim 160801b4770dSJiri Olsa static void hists_browser__hierarchy_headers(struct hist_browser *browser) 1609025bf7eaSArnaldo Carvalho de Melo { 161081a888feSJiri Olsa char headers[1024]; 161181a888feSJiri Olsa 1612d8b92400SNamhyung Kim hists_browser__scnprintf_hierarchy_headers(browser, headers, 1613d8b92400SNamhyung Kim sizeof(headers)); 161401b4770dSJiri Olsa 1615025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, 0, 0); 1616025bf7eaSArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 161726270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 1618025bf7eaSArnaldo Carvalho de Melo } 1619025bf7eaSArnaldo Carvalho de Melo 162001b4770dSJiri Olsa static void hists_browser__headers(struct hist_browser *browser) 162101b4770dSJiri Olsa { 162201b4770dSJiri Olsa char headers[1024]; 162301b4770dSJiri Olsa 162401b4770dSJiri Olsa hists_browser__scnprintf_headers(browser, headers, 162501b4770dSJiri Olsa sizeof(headers)); 162601b4770dSJiri Olsa 162701b4770dSJiri Olsa ui_browser__gotorc(&browser->b, 0, 0); 162801b4770dSJiri Olsa ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 162901b4770dSJiri Olsa ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 163001b4770dSJiri Olsa } 163101b4770dSJiri Olsa 163201b4770dSJiri Olsa static void hist_browser__show_headers(struct hist_browser *browser) 163301b4770dSJiri Olsa { 163401b4770dSJiri Olsa if (symbol_conf.report_hierarchy) 163501b4770dSJiri Olsa hists_browser__hierarchy_headers(browser); 163601b4770dSJiri Olsa else 163701b4770dSJiri Olsa hists_browser__headers(browser); 163801b4770dSJiri Olsa } 163901b4770dSJiri Olsa 1640aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 1641aca7a94dSNamhyung Kim { 1642aca7a94dSNamhyung Kim if (browser->top == NULL) { 1643aca7a94dSNamhyung Kim struct hist_browser *hb; 1644aca7a94dSNamhyung Kim 1645aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1646aca7a94dSNamhyung Kim browser->top = rb_first(&hb->hists->entries); 1647aca7a94dSNamhyung Kim } 1648aca7a94dSNamhyung Kim } 1649aca7a94dSNamhyung Kim 165005e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 1651aca7a94dSNamhyung Kim { 1652aca7a94dSNamhyung Kim unsigned row = 0; 1653025bf7eaSArnaldo Carvalho de Melo u16 header_offset = 0; 1654aca7a94dSNamhyung Kim struct rb_node *nd; 165505e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 1656aca7a94dSNamhyung Kim 1657025bf7eaSArnaldo Carvalho de Melo if (hb->show_headers) { 1658025bf7eaSArnaldo Carvalho de Melo hist_browser__show_headers(hb); 1659025bf7eaSArnaldo Carvalho de Melo header_offset = 1; 1660025bf7eaSArnaldo Carvalho de Melo } 1661025bf7eaSArnaldo Carvalho de Melo 166205e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1663979d2cacSWang Nan hb->he_selection = NULL; 1664979d2cacSWang Nan hb->selection = NULL; 1665aca7a94dSNamhyung Kim 1666d0506edbSNamhyung Kim for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) { 1667aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 166814135663SNamhyung Kim float percent; 1669aca7a94dSNamhyung Kim 1670d0506edbSNamhyung Kim if (h->filtered) { 1671d0506edbSNamhyung Kim /* let it move to sibling */ 1672d0506edbSNamhyung Kim h->unfolded = false; 1673aca7a94dSNamhyung Kim continue; 1674d0506edbSNamhyung Kim } 1675aca7a94dSNamhyung Kim 167614135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 1677064f1981SNamhyung Kim if (percent < hb->min_pcnt) 1678064f1981SNamhyung Kim continue; 1679064f1981SNamhyung Kim 1680d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 1681d0506edbSNamhyung Kim row += hist_browser__show_hierarchy_entry(hb, h, row, 16822dbbe9f2SNamhyung Kim h->depth); 168379dded87SNamhyung Kim if (row == browser->rows) 168479dded87SNamhyung Kim break; 168579dded87SNamhyung Kim 168679dded87SNamhyung Kim if (h->has_no_entry) { 1687a61a22f6SNamhyung Kim hist_browser__show_no_entry(hb, row, h->depth + 1); 168879dded87SNamhyung Kim row++; 168979dded87SNamhyung Kim } 1690d0506edbSNamhyung Kim } else { 1691aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 1692d0506edbSNamhyung Kim } 1693d0506edbSNamhyung Kim 169462c95ae3SArnaldo Carvalho de Melo if (row == browser->rows) 1695aca7a94dSNamhyung Kim break; 1696aca7a94dSNamhyung Kim } 1697aca7a94dSNamhyung Kim 1698025bf7eaSArnaldo Carvalho de Melo return row + header_offset; 1699aca7a94dSNamhyung Kim } 1700aca7a94dSNamhyung Kim 1701064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 1702064f1981SNamhyung Kim float min_pcnt) 1703aca7a94dSNamhyung Kim { 1704aca7a94dSNamhyung Kim while (nd != NULL) { 1705aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 170614135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1707064f1981SNamhyung Kim 1708c0f1527bSNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1709aca7a94dSNamhyung Kim return nd; 1710aca7a94dSNamhyung Kim 1711d0506edbSNamhyung Kim /* 1712d0506edbSNamhyung Kim * If it's filtered, its all children also were filtered. 1713d0506edbSNamhyung Kim * So move to sibling node. 1714d0506edbSNamhyung Kim */ 1715d0506edbSNamhyung Kim if (rb_next(nd)) 1716aca7a94dSNamhyung Kim nd = rb_next(nd); 1717d0506edbSNamhyung Kim else 1718d0506edbSNamhyung Kim nd = rb_hierarchy_next(nd); 1719aca7a94dSNamhyung Kim } 1720aca7a94dSNamhyung Kim 1721aca7a94dSNamhyung Kim return NULL; 1722aca7a94dSNamhyung Kim } 1723aca7a94dSNamhyung Kim 1724064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 1725064f1981SNamhyung Kim float min_pcnt) 1726aca7a94dSNamhyung Kim { 1727aca7a94dSNamhyung Kim while (nd != NULL) { 1728aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 172914135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1730064f1981SNamhyung Kim 1731064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1732aca7a94dSNamhyung Kim return nd; 1733aca7a94dSNamhyung Kim 1734d0506edbSNamhyung Kim nd = rb_hierarchy_prev(nd); 1735aca7a94dSNamhyung Kim } 1736aca7a94dSNamhyung Kim 1737aca7a94dSNamhyung Kim return NULL; 1738aca7a94dSNamhyung Kim } 1739aca7a94dSNamhyung Kim 174005e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 1741aca7a94dSNamhyung Kim off_t offset, int whence) 1742aca7a94dSNamhyung Kim { 1743aca7a94dSNamhyung Kim struct hist_entry *h; 1744aca7a94dSNamhyung Kim struct rb_node *nd; 1745aca7a94dSNamhyung Kim bool first = true; 1746064f1981SNamhyung Kim struct hist_browser *hb; 1747064f1981SNamhyung Kim 1748064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1749aca7a94dSNamhyung Kim 175005e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 1751aca7a94dSNamhyung Kim return; 1752aca7a94dSNamhyung Kim 175305e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1754aca7a94dSNamhyung Kim 1755aca7a94dSNamhyung Kim switch (whence) { 1756aca7a94dSNamhyung Kim case SEEK_SET: 1757064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 175814135663SNamhyung Kim hb->min_pcnt); 1759aca7a94dSNamhyung Kim break; 1760aca7a94dSNamhyung Kim case SEEK_CUR: 176105e8b080SArnaldo Carvalho de Melo nd = browser->top; 1762aca7a94dSNamhyung Kim goto do_offset; 1763aca7a94dSNamhyung Kim case SEEK_END: 1764d0506edbSNamhyung Kim nd = rb_hierarchy_last(rb_last(browser->entries)); 1765d0506edbSNamhyung Kim nd = hists__filter_prev_entries(nd, hb->min_pcnt); 1766aca7a94dSNamhyung Kim first = false; 1767aca7a94dSNamhyung Kim break; 1768aca7a94dSNamhyung Kim default: 1769aca7a94dSNamhyung Kim return; 1770aca7a94dSNamhyung Kim } 1771aca7a94dSNamhyung Kim 1772aca7a94dSNamhyung Kim /* 1773aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 1774aca7a94dSNamhyung Kim * row_offset: 1775aca7a94dSNamhyung Kim */ 177605e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 1777aca7a94dSNamhyung Kim h->row_offset = 0; 1778aca7a94dSNamhyung Kim 1779aca7a94dSNamhyung Kim /* 1780aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 1781aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 1782aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 1783aca7a94dSNamhyung Kim * 1784aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 1785aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 1786aca7a94dSNamhyung Kim * 1787aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 1788aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 1789aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 1790aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 1791aca7a94dSNamhyung Kim */ 1792aca7a94dSNamhyung Kim do_offset: 1793837eeb75SWang Nan if (!nd) 1794837eeb75SWang Nan return; 1795837eeb75SWang Nan 1796aca7a94dSNamhyung Kim if (offset > 0) { 1797aca7a94dSNamhyung Kim do { 1798aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1799d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1800aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 1801aca7a94dSNamhyung Kim if (offset > remaining) { 1802aca7a94dSNamhyung Kim offset -= remaining; 1803aca7a94dSNamhyung Kim h->row_offset = 0; 1804aca7a94dSNamhyung Kim } else { 1805aca7a94dSNamhyung Kim h->row_offset += offset; 1806aca7a94dSNamhyung Kim offset = 0; 180705e8b080SArnaldo Carvalho de Melo browser->top = nd; 1808aca7a94dSNamhyung Kim break; 1809aca7a94dSNamhyung Kim } 1810aca7a94dSNamhyung Kim } 1811d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 1812d0506edbSNamhyung Kim hb->min_pcnt); 1813aca7a94dSNamhyung Kim if (nd == NULL) 1814aca7a94dSNamhyung Kim break; 1815aca7a94dSNamhyung Kim --offset; 181605e8b080SArnaldo Carvalho de Melo browser->top = nd; 1817aca7a94dSNamhyung Kim } while (offset != 0); 1818aca7a94dSNamhyung Kim } else if (offset < 0) { 1819aca7a94dSNamhyung Kim while (1) { 1820aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1821d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1822aca7a94dSNamhyung Kim if (first) { 1823aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 1824aca7a94dSNamhyung Kim offset += h->row_offset; 1825aca7a94dSNamhyung Kim h->row_offset = 0; 1826aca7a94dSNamhyung Kim } else { 1827aca7a94dSNamhyung Kim h->row_offset += offset; 1828aca7a94dSNamhyung Kim offset = 0; 182905e8b080SArnaldo Carvalho de Melo browser->top = nd; 1830aca7a94dSNamhyung Kim break; 1831aca7a94dSNamhyung Kim } 1832aca7a94dSNamhyung Kim } else { 1833aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 1834aca7a94dSNamhyung Kim offset += h->nr_rows; 1835aca7a94dSNamhyung Kim h->row_offset = 0; 1836aca7a94dSNamhyung Kim } else { 1837aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 1838aca7a94dSNamhyung Kim offset = 0; 183905e8b080SArnaldo Carvalho de Melo browser->top = nd; 1840aca7a94dSNamhyung Kim break; 1841aca7a94dSNamhyung Kim } 1842aca7a94dSNamhyung Kim } 1843aca7a94dSNamhyung Kim } 1844aca7a94dSNamhyung Kim 1845d0506edbSNamhyung Kim nd = hists__filter_prev_entries(rb_hierarchy_prev(nd), 1846064f1981SNamhyung Kim hb->min_pcnt); 1847aca7a94dSNamhyung Kim if (nd == NULL) 1848aca7a94dSNamhyung Kim break; 1849aca7a94dSNamhyung Kim ++offset; 185005e8b080SArnaldo Carvalho de Melo browser->top = nd; 1851aca7a94dSNamhyung Kim if (offset == 0) { 1852aca7a94dSNamhyung Kim /* 1853aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 1854aca7a94dSNamhyung Kim * unfolded, if it is then we should have 1855aca7a94dSNamhyung Kim * row_offset at its last entry. 1856aca7a94dSNamhyung Kim */ 1857aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1858d0506edbSNamhyung Kim if (h->unfolded && h->leaf) 1859aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 1860aca7a94dSNamhyung Kim break; 1861aca7a94dSNamhyung Kim } 1862aca7a94dSNamhyung Kim first = false; 1863aca7a94dSNamhyung Kim } 1864aca7a94dSNamhyung Kim } else { 186505e8b080SArnaldo Carvalho de Melo browser->top = nd; 1866aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1867aca7a94dSNamhyung Kim h->row_offset = 0; 1868aca7a94dSNamhyung Kim } 1869aca7a94dSNamhyung Kim } 1870aca7a94dSNamhyung Kim 1871aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1872d0506edbSNamhyung Kim struct hist_entry *he, FILE *fp, 1873d0506edbSNamhyung Kim int level) 1874aff3f3f6SArnaldo Carvalho de Melo { 187539ee533fSNamhyung Kim struct callchain_print_arg arg = { 187639ee533fSNamhyung Kim .fp = fp, 187739ee533fSNamhyung Kim }; 1878aff3f3f6SArnaldo Carvalho de Melo 1879d0506edbSNamhyung Kim hist_browser__show_callchain(browser, he, level, 0, 188039ee533fSNamhyung Kim hist_browser__fprintf_callchain_entry, &arg, 188139ee533fSNamhyung Kim hist_browser__check_dump_full); 188239ee533fSNamhyung Kim return arg.printed; 1883aff3f3f6SArnaldo Carvalho de Melo } 1884aff3f3f6SArnaldo Carvalho de Melo 1885aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 1886aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 1887aff3f3f6SArnaldo Carvalho de Melo { 1888aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 1889aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1890aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 189126d8b338SNamhyung Kim struct perf_hpp hpp = { 189226d8b338SNamhyung Kim .buf = s, 189326d8b338SNamhyung Kim .size = sizeof(s), 189426d8b338SNamhyung Kim }; 189526d8b338SNamhyung Kim struct perf_hpp_fmt *fmt; 189626d8b338SNamhyung Kim bool first = true; 189726d8b338SNamhyung Kim int ret; 1898aff3f3f6SArnaldo Carvalho de Melo 18991b6b678eSArnaldo Carvalho de Melo if (symbol_conf.use_callchain) { 1900aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 1901aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 19021b6b678eSArnaldo Carvalho de Melo } 1903aff3f3f6SArnaldo Carvalho de Melo 1904f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 1905361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, he->hists)) 1906e67d49a7SNamhyung Kim continue; 1907e67d49a7SNamhyung Kim 190826d8b338SNamhyung Kim if (!first) { 190926d8b338SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 191026d8b338SNamhyung Kim advance_hpp(&hpp, ret); 191126d8b338SNamhyung Kim } else 191226d8b338SNamhyung Kim first = false; 1913aff3f3f6SArnaldo Carvalho de Melo 191426d8b338SNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 191589fee709SArnaldo Carvalho de Melo ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret); 191626d8b338SNamhyung Kim advance_hpp(&hpp, ret); 191726d8b338SNamhyung Kim } 191889fee709SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", s); 1919aff3f3f6SArnaldo Carvalho de Melo 1920aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 1921d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 1); 1922d0506edbSNamhyung Kim 1923d0506edbSNamhyung Kim return printed; 1924d0506edbSNamhyung Kim } 1925d0506edbSNamhyung Kim 1926d0506edbSNamhyung Kim 1927d0506edbSNamhyung Kim static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser, 1928d0506edbSNamhyung Kim struct hist_entry *he, 1929325a6283SNamhyung Kim FILE *fp, int level) 1930d0506edbSNamhyung Kim { 1931d0506edbSNamhyung Kim char s[8192]; 1932d0506edbSNamhyung Kim int printed = 0; 1933d0506edbSNamhyung Kim char folded_sign = ' '; 1934d0506edbSNamhyung Kim struct perf_hpp hpp = { 1935d0506edbSNamhyung Kim .buf = s, 1936d0506edbSNamhyung Kim .size = sizeof(s), 1937d0506edbSNamhyung Kim }; 1938d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 1939325a6283SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1940d0506edbSNamhyung Kim bool first = true; 1941d0506edbSNamhyung Kim int ret; 1942325a6283SNamhyung Kim int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 1943d0506edbSNamhyung Kim 1944d0506edbSNamhyung Kim printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, ""); 1945d0506edbSNamhyung Kim 1946d0506edbSNamhyung Kim folded_sign = hist_entry__folded(he); 1947d0506edbSNamhyung Kim printed += fprintf(fp, "%c", folded_sign); 1948d0506edbSNamhyung Kim 1949325a6283SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1950325a6283SNamhyung Kim fmt_node = list_first_entry(&he->hists->hpp_formats, 1951325a6283SNamhyung Kim struct perf_hpp_list_node, list); 1952325a6283SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1953d0506edbSNamhyung Kim if (!first) { 1954d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 1955d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 1956d0506edbSNamhyung Kim } else 1957d0506edbSNamhyung Kim first = false; 1958d0506edbSNamhyung Kim 1959d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 1960d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 1961d0506edbSNamhyung Kim } 1962d0506edbSNamhyung Kim 1963d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, ""); 1964d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 1965d0506edbSNamhyung Kim 19661b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(he->hpp_list, fmt) { 19671b2dbbf4SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 19681b2dbbf4SNamhyung Kim advance_hpp(&hpp, ret); 19691b2dbbf4SNamhyung Kim 1970d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 1971d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 19721b2dbbf4SNamhyung Kim } 1973d0506edbSNamhyung Kim 1974d0506edbSNamhyung Kim printed += fprintf(fp, "%s\n", rtrim(s)); 1975d0506edbSNamhyung Kim 1976d0506edbSNamhyung Kim if (he->leaf && folded_sign == '-') { 1977d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 1978d0506edbSNamhyung Kim he->depth + 1); 1979d0506edbSNamhyung Kim } 1980aff3f3f6SArnaldo Carvalho de Melo 1981aff3f3f6SArnaldo Carvalho de Melo return printed; 1982aff3f3f6SArnaldo Carvalho de Melo } 1983aff3f3f6SArnaldo Carvalho de Melo 1984aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1985aff3f3f6SArnaldo Carvalho de Melo { 1986064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1987064f1981SNamhyung Kim browser->min_pcnt); 1988aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1989aff3f3f6SArnaldo Carvalho de Melo 1990aff3f3f6SArnaldo Carvalho de Melo while (nd) { 1991aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1992aff3f3f6SArnaldo Carvalho de Melo 1993d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 1994d0506edbSNamhyung Kim printed += hist_browser__fprintf_hierarchy_entry(browser, 1995d0506edbSNamhyung Kim h, fp, 1996325a6283SNamhyung Kim h->depth); 1997d0506edbSNamhyung Kim } else { 1998aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 1999d0506edbSNamhyung Kim } 2000d0506edbSNamhyung Kim 2001d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 2002d0506edbSNamhyung Kim browser->min_pcnt); 2003aff3f3f6SArnaldo Carvalho de Melo } 2004aff3f3f6SArnaldo Carvalho de Melo 2005aff3f3f6SArnaldo Carvalho de Melo return printed; 2006aff3f3f6SArnaldo Carvalho de Melo } 2007aff3f3f6SArnaldo Carvalho de Melo 2008aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 2009aff3f3f6SArnaldo Carvalho de Melo { 2010aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 2011aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 2012aff3f3f6SArnaldo Carvalho de Melo 2013aff3f3f6SArnaldo Carvalho de Melo while (1) { 2014aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 2015aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 2016aff3f3f6SArnaldo Carvalho de Melo break; 2017aff3f3f6SArnaldo Carvalho de Melo /* 2018aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 2019aff3f3f6SArnaldo Carvalho de Melo */ 2020aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 2021aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 2022aff3f3f6SArnaldo Carvalho de Melo return -1; 2023aff3f3f6SArnaldo Carvalho de Melo } 2024aff3f3f6SArnaldo Carvalho de Melo } 2025aff3f3f6SArnaldo Carvalho de Melo 2026aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 2027aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 2028aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 20294cc49d4dSKirill A. Shutemov const char *err = strerror_r(errno, bf, sizeof(bf)); 20304cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 2031aff3f3f6SArnaldo Carvalho de Melo return -1; 2032aff3f3f6SArnaldo Carvalho de Melo } 2033aff3f3f6SArnaldo Carvalho de Melo 2034aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 2035aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 2036aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 2037aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 2038aff3f3f6SArnaldo Carvalho de Melo 2039aff3f3f6SArnaldo Carvalho de Melo return 0; 2040aff3f3f6SArnaldo Carvalho de Melo } 2041aff3f3f6SArnaldo Carvalho de Melo 2042*dabd2012SJiri Olsa struct hist_browser *hist_browser__new(struct hists *hists, 2043b1a9ceefSNamhyung Kim struct hist_browser_timer *hbt, 2044ce80d3beSKan Liang struct perf_env *env) 2045aca7a94dSNamhyung Kim { 204605e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = zalloc(sizeof(*browser)); 2047aca7a94dSNamhyung Kim 204805e8b080SArnaldo Carvalho de Melo if (browser) { 204905e8b080SArnaldo Carvalho de Melo browser->hists = hists; 205005e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 2051357cfff1SArnaldo Carvalho de Melo browser->b.refresh_dimensions = hist_browser__refresh_dimensions; 205205e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 205305e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 2054c8302367SJiri Olsa browser->show_headers = symbol_conf.show_hist_headers; 2055c2a51ab8SNamhyung Kim browser->hbt = hbt; 2056b1a9ceefSNamhyung Kim browser->env = env; 2057aca7a94dSNamhyung Kim } 2058aca7a94dSNamhyung Kim 205905e8b080SArnaldo Carvalho de Melo return browser; 2060aca7a94dSNamhyung Kim } 2061aca7a94dSNamhyung Kim 2062*dabd2012SJiri Olsa void hist_browser__delete(struct hist_browser *browser) 2063aca7a94dSNamhyung Kim { 206405e8b080SArnaldo Carvalho de Melo free(browser); 2065aca7a94dSNamhyung Kim } 2066aca7a94dSNamhyung Kim 206705e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 2068aca7a94dSNamhyung Kim { 206905e8b080SArnaldo Carvalho de Melo return browser->he_selection; 2070aca7a94dSNamhyung Kim } 2071aca7a94dSNamhyung Kim 207205e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 2073aca7a94dSNamhyung Kim { 207405e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 2075aca7a94dSNamhyung Kim } 2076aca7a94dSNamhyung Kim 20771e378ebdSTaeung Song /* Check whether the browser is for 'top' or 'report' */ 20781e378ebdSTaeung Song static inline bool is_report_browser(void *timer) 20791e378ebdSTaeung Song { 20801e378ebdSTaeung Song return timer == NULL; 20811e378ebdSTaeung Song } 20821e378ebdSTaeung Song 20831e378ebdSTaeung Song static int hists__browser_title(struct hists *hists, 20841e378ebdSTaeung Song struct hist_browser_timer *hbt, 20851e378ebdSTaeung Song char *bf, size_t size) 2086aca7a94dSNamhyung Kim { 2087aca7a94dSNamhyung Kim char unit; 2088aca7a94dSNamhyung Kim int printed; 208905e8b080SArnaldo Carvalho de Melo const struct dso *dso = hists->dso_filter; 209005e8b080SArnaldo Carvalho de Melo const struct thread *thread = hists->thread_filter; 209184734b06SKan Liang int socket_id = hists->socket_filter; 209205e8b080SArnaldo Carvalho de Melo unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 209305e8b080SArnaldo Carvalho de Melo u64 nr_events = hists->stats.total_period; 2094717e263fSNamhyung Kim struct perf_evsel *evsel = hists_to_evsel(hists); 2095dd00d486SJiri Olsa const char *ev_name = perf_evsel__name(evsel); 2096717e263fSNamhyung Kim char buf[512]; 2097717e263fSNamhyung Kim size_t buflen = sizeof(buf); 20989e207ddfSKan Liang char ref[30] = " show reference callgraph, "; 20999e207ddfSKan Liang bool enable_ref = false; 2100717e263fSNamhyung Kim 2101f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 2102f2148330SNamhyung Kim nr_samples = hists->stats.nr_non_filtered_samples; 2103f2148330SNamhyung Kim nr_events = hists->stats.total_non_filtered_period; 2104f2148330SNamhyung Kim } 2105f2148330SNamhyung Kim 2106759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 2107717e263fSNamhyung Kim struct perf_evsel *pos; 2108717e263fSNamhyung Kim 2109717e263fSNamhyung Kim perf_evsel__group_desc(evsel, buf, buflen); 2110717e263fSNamhyung Kim ev_name = buf; 2111717e263fSNamhyung Kim 2112717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 21134ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 21144ea062edSArnaldo Carvalho de Melo 2115f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 21164ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_non_filtered_samples; 21174ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_non_filtered_period; 2118f2148330SNamhyung Kim } else { 21194ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 21204ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_period; 2121717e263fSNamhyung Kim } 2122717e263fSNamhyung Kim } 2123f2148330SNamhyung Kim } 2124aca7a94dSNamhyung Kim 21259e207ddfSKan Liang if (symbol_conf.show_ref_callgraph && 21269e207ddfSKan Liang strstr(ev_name, "call-graph=no")) 21279e207ddfSKan Liang enable_ref = true; 2128aca7a94dSNamhyung Kim nr_samples = convert_unit(nr_samples, &unit); 2129aca7a94dSNamhyung Kim printed = scnprintf(bf, size, 21309e207ddfSKan Liang "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64, 21319e207ddfSKan Liang nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events); 2132aca7a94dSNamhyung Kim 2133aca7a94dSNamhyung Kim 213405e8b080SArnaldo Carvalho de Melo if (hists->uid_filter_str) 2135aca7a94dSNamhyung Kim printed += snprintf(bf + printed, size - printed, 213605e8b080SArnaldo Carvalho de Melo ", UID: %s", hists->uid_filter_str); 21376962ccb3SNamhyung Kim if (thread) { 2138fa82911aSJiri Olsa if (hists__has(hists, thread)) { 2139aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 2140aca7a94dSNamhyung Kim ", Thread: %s(%d)", 2141b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 214238051234SAdrian Hunter thread->tid); 21436962ccb3SNamhyung Kim } else { 21446962ccb3SNamhyung Kim printed += scnprintf(bf + printed, size - printed, 21456962ccb3SNamhyung Kim ", Thread: %s", 21466962ccb3SNamhyung Kim (thread->comm_set ? thread__comm_str(thread) : "")); 21476962ccb3SNamhyung Kim } 21486962ccb3SNamhyung Kim } 2149aca7a94dSNamhyung Kim if (dso) 2150aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 2151aca7a94dSNamhyung Kim ", DSO: %s", dso->short_name); 215284734b06SKan Liang if (socket_id > -1) 215321394d94SKan Liang printed += scnprintf(bf + printed, size - printed, 215484734b06SKan Liang ", Processor Socket: %d", socket_id); 21551e378ebdSTaeung Song if (!is_report_browser(hbt)) { 21561e378ebdSTaeung Song struct perf_top *top = hbt->arg; 21571e378ebdSTaeung Song 21581e378ebdSTaeung Song if (top->zero) 21591e378ebdSTaeung Song printed += scnprintf(bf + printed, size - printed, " [z]"); 21601e378ebdSTaeung Song } 21611e378ebdSTaeung Song 2162aca7a94dSNamhyung Kim return printed; 2163aca7a94dSNamhyung Kim } 2164aca7a94dSNamhyung Kim 2165aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 2166aca7a94dSNamhyung Kim { 2167aca7a94dSNamhyung Kim int i; 2168aca7a94dSNamhyung Kim 216904662523SArnaldo Carvalho de Melo for (i = 0; i < n; ++i) 217004662523SArnaldo Carvalho de Melo zfree(&options[i]); 2171aca7a94dSNamhyung Kim } 2172aca7a94dSNamhyung Kim 2173341487abSFeng Tang /* 2174341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 2175341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 2176341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 2177341487abSFeng Tang */ 2178341487abSFeng Tang static bool is_input_name_malloced = false; 2179341487abSFeng Tang 2180341487abSFeng Tang static int switch_data_file(void) 2181341487abSFeng Tang { 2182341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 2183341487abSFeng Tang DIR *pwd_dir; 2184341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 2185341487abSFeng Tang struct dirent *dent; 2186341487abSFeng Tang 2187341487abSFeng Tang pwd = getenv("PWD"); 2188341487abSFeng Tang if (!pwd) 2189341487abSFeng Tang return ret; 2190341487abSFeng Tang 2191341487abSFeng Tang pwd_dir = opendir(pwd); 2192341487abSFeng Tang if (!pwd_dir) 2193341487abSFeng Tang return ret; 2194341487abSFeng Tang 2195341487abSFeng Tang memset(options, 0, sizeof(options)); 2196341487abSFeng Tang memset(options, 0, sizeof(abs_path)); 2197341487abSFeng Tang 2198341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 2199341487abSFeng Tang char path[PATH_MAX]; 2200341487abSFeng Tang u64 magic; 2201341487abSFeng Tang char *name = dent->d_name; 2202341487abSFeng Tang FILE *file; 2203341487abSFeng Tang 2204341487abSFeng Tang if (!(dent->d_type == DT_REG)) 2205341487abSFeng Tang continue; 2206341487abSFeng Tang 2207341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 2208341487abSFeng Tang 2209341487abSFeng Tang file = fopen(path, "r"); 2210341487abSFeng Tang if (!file) 2211341487abSFeng Tang continue; 2212341487abSFeng Tang 2213341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 2214341487abSFeng Tang goto close_file_and_continue; 2215341487abSFeng Tang 2216341487abSFeng Tang if (is_perf_magic(magic)) { 2217341487abSFeng Tang options[nr_options] = strdup(name); 2218341487abSFeng Tang if (!options[nr_options]) 2219341487abSFeng Tang goto close_file_and_continue; 2220341487abSFeng Tang 2221341487abSFeng Tang abs_path[nr_options] = strdup(path); 2222341487abSFeng Tang if (!abs_path[nr_options]) { 222374cf249dSArnaldo Carvalho de Melo zfree(&options[nr_options]); 2224341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 2225341487abSFeng Tang fclose(file); 2226341487abSFeng Tang break; 2227341487abSFeng Tang } 2228341487abSFeng Tang 2229341487abSFeng Tang nr_options++; 2230341487abSFeng Tang } 2231341487abSFeng Tang 2232341487abSFeng Tang close_file_and_continue: 2233341487abSFeng Tang fclose(file); 2234341487abSFeng Tang if (nr_options >= 32) { 2235341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 2236341487abSFeng Tang "Only the first 32 files will be listed.\n"); 2237341487abSFeng Tang break; 2238341487abSFeng Tang } 2239341487abSFeng Tang } 2240341487abSFeng Tang closedir(pwd_dir); 2241341487abSFeng Tang 2242341487abSFeng Tang if (nr_options) { 2243341487abSFeng Tang choice = ui__popup_menu(nr_options, options); 2244341487abSFeng Tang if (choice < nr_options && choice >= 0) { 2245341487abSFeng Tang tmp = strdup(abs_path[choice]); 2246341487abSFeng Tang if (tmp) { 2247341487abSFeng Tang if (is_input_name_malloced) 2248341487abSFeng Tang free((void *)input_name); 2249341487abSFeng Tang input_name = tmp; 2250341487abSFeng Tang is_input_name_malloced = true; 2251341487abSFeng Tang ret = 0; 2252341487abSFeng Tang } else 2253341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 2254341487abSFeng Tang } 2255341487abSFeng Tang } 2256341487abSFeng Tang 2257341487abSFeng Tang free_popup_options(options, nr_options); 2258341487abSFeng Tang free_popup_options(abs_path, nr_options); 2259341487abSFeng Tang return ret; 2260341487abSFeng Tang } 2261341487abSFeng Tang 2262ea7cd592SNamhyung Kim struct popup_action { 2263ea7cd592SNamhyung Kim struct thread *thread; 2264ea7cd592SNamhyung Kim struct map_symbol ms; 226584734b06SKan Liang int socket; 2266ea7cd592SNamhyung Kim 2267ea7cd592SNamhyung Kim int (*fn)(struct hist_browser *browser, struct popup_action *act); 2268ea7cd592SNamhyung Kim }; 2269ea7cd592SNamhyung Kim 2270bc7cad42SNamhyung Kim static int 2271ea7cd592SNamhyung Kim do_annotate(struct hist_browser *browser, struct popup_action *act) 2272bc7cad42SNamhyung Kim { 2273bc7cad42SNamhyung Kim struct perf_evsel *evsel; 2274bc7cad42SNamhyung Kim struct annotation *notes; 2275bc7cad42SNamhyung Kim struct hist_entry *he; 2276bc7cad42SNamhyung Kim int err; 2277bc7cad42SNamhyung Kim 2278eebd0bfcSArnaldo Carvalho de Melo if (!objdump_path && perf_env__lookup_objdump(browser->env)) 2279bc7cad42SNamhyung Kim return 0; 2280bc7cad42SNamhyung Kim 2281ea7cd592SNamhyung Kim notes = symbol__annotation(act->ms.sym); 2282bc7cad42SNamhyung Kim if (!notes->src) 2283bc7cad42SNamhyung Kim return 0; 2284bc7cad42SNamhyung Kim 2285bc7cad42SNamhyung Kim evsel = hists_to_evsel(browser->hists); 2286ea7cd592SNamhyung Kim err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); 2287bc7cad42SNamhyung Kim he = hist_browser__selected_entry(browser); 2288bc7cad42SNamhyung Kim /* 2289bc7cad42SNamhyung Kim * offer option to annotate the other branch source or target 2290bc7cad42SNamhyung Kim * (if they exists) when returning from annotate 2291bc7cad42SNamhyung Kim */ 2292bc7cad42SNamhyung Kim if ((err == 'q' || err == CTRL('c')) && he->branch_info) 2293bc7cad42SNamhyung Kim return 1; 2294bc7cad42SNamhyung Kim 2295bc7cad42SNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 2296bc7cad42SNamhyung Kim if (err) 2297bc7cad42SNamhyung Kim ui_browser__handle_resize(&browser->b); 2298bc7cad42SNamhyung Kim return 0; 2299bc7cad42SNamhyung Kim } 2300bc7cad42SNamhyung Kim 2301bc7cad42SNamhyung Kim static int 2302ea7cd592SNamhyung Kim add_annotate_opt(struct hist_browser *browser __maybe_unused, 2303ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 2304ea7cd592SNamhyung Kim struct map *map, struct symbol *sym) 2305bc7cad42SNamhyung Kim { 2306ea7cd592SNamhyung Kim if (sym == NULL || map->dso->annotate_warned) 2307ea7cd592SNamhyung Kim return 0; 2308ea7cd592SNamhyung Kim 2309ea7cd592SNamhyung Kim if (asprintf(optstr, "Annotate %s", sym->name) < 0) 2310ea7cd592SNamhyung Kim return 0; 2311ea7cd592SNamhyung Kim 2312ea7cd592SNamhyung Kim act->ms.map = map; 2313ea7cd592SNamhyung Kim act->ms.sym = sym; 2314ea7cd592SNamhyung Kim act->fn = do_annotate; 2315ea7cd592SNamhyung Kim return 1; 2316ea7cd592SNamhyung Kim } 2317ea7cd592SNamhyung Kim 2318ea7cd592SNamhyung Kim static int 2319ea7cd592SNamhyung Kim do_zoom_thread(struct hist_browser *browser, struct popup_action *act) 2320ea7cd592SNamhyung Kim { 2321ea7cd592SNamhyung Kim struct thread *thread = act->thread; 2322ea7cd592SNamhyung Kim 23237cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 23247cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2325599a2f38SNamhyung Kim return 0; 2326599a2f38SNamhyung Kim 2327bc7cad42SNamhyung Kim if (browser->hists->thread_filter) { 2328bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->thread_filter); 2329bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2330bc7cad42SNamhyung Kim thread__zput(browser->hists->thread_filter); 2331bc7cad42SNamhyung Kim ui_helpline__pop(); 2332bc7cad42SNamhyung Kim } else { 2333fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 23347727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 2335bc7cad42SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 2336bc7cad42SNamhyung Kim thread->tid); 23376962ccb3SNamhyung Kim } else { 23386962ccb3SNamhyung Kim ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"", 23396962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 23406962ccb3SNamhyung Kim } 23416962ccb3SNamhyung Kim 2342bc7cad42SNamhyung Kim browser->hists->thread_filter = thread__get(thread); 2343bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2344bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->thread_filter); 2345bc7cad42SNamhyung Kim } 2346bc7cad42SNamhyung Kim 2347bc7cad42SNamhyung Kim hists__filter_by_thread(browser->hists); 2348bc7cad42SNamhyung Kim hist_browser__reset(browser); 2349bc7cad42SNamhyung Kim return 0; 2350bc7cad42SNamhyung Kim } 2351bc7cad42SNamhyung Kim 2352bc7cad42SNamhyung Kim static int 2353ea7cd592SNamhyung Kim add_thread_opt(struct hist_browser *browser, struct popup_action *act, 2354ea7cd592SNamhyung Kim char **optstr, struct thread *thread) 2355bc7cad42SNamhyung Kim { 23566962ccb3SNamhyung Kim int ret; 23576962ccb3SNamhyung Kim 23587cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 23597cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2360ea7cd592SNamhyung Kim return 0; 2361ea7cd592SNamhyung Kim 2362fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 23636962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s(%d) thread", 2364ea7cd592SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 2365ea7cd592SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 23666962ccb3SNamhyung Kim thread->tid); 23676962ccb3SNamhyung Kim } else { 23686962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s thread", 23696962ccb3SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 23706962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 23716962ccb3SNamhyung Kim } 23726962ccb3SNamhyung Kim if (ret < 0) 2373ea7cd592SNamhyung Kim return 0; 2374ea7cd592SNamhyung Kim 2375ea7cd592SNamhyung Kim act->thread = thread; 2376ea7cd592SNamhyung Kim act->fn = do_zoom_thread; 2377ea7cd592SNamhyung Kim return 1; 2378ea7cd592SNamhyung Kim } 2379ea7cd592SNamhyung Kim 2380ea7cd592SNamhyung Kim static int 2381ea7cd592SNamhyung Kim do_zoom_dso(struct hist_browser *browser, struct popup_action *act) 2382ea7cd592SNamhyung Kim { 2383045b80ddSArnaldo Carvalho de Melo struct map *map = act->ms.map; 2384ea7cd592SNamhyung Kim 238569849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2386599a2f38SNamhyung Kim return 0; 2387599a2f38SNamhyung Kim 2388bc7cad42SNamhyung Kim if (browser->hists->dso_filter) { 2389bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->dso_filter); 2390bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, false); 2391bc7cad42SNamhyung Kim browser->hists->dso_filter = NULL; 2392bc7cad42SNamhyung Kim ui_helpline__pop(); 2393bc7cad42SNamhyung Kim } else { 2394045b80ddSArnaldo Carvalho de Melo if (map == NULL) 2395bc7cad42SNamhyung Kim return 0; 23967727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", 2397045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); 2398045b80ddSArnaldo Carvalho de Melo browser->hists->dso_filter = map->dso; 2399bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, true); 2400bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->dso_filter); 2401bc7cad42SNamhyung Kim } 2402bc7cad42SNamhyung Kim 2403bc7cad42SNamhyung Kim hists__filter_by_dso(browser->hists); 2404bc7cad42SNamhyung Kim hist_browser__reset(browser); 2405bc7cad42SNamhyung Kim return 0; 2406bc7cad42SNamhyung Kim } 2407bc7cad42SNamhyung Kim 2408bc7cad42SNamhyung Kim static int 2409ea7cd592SNamhyung Kim add_dso_opt(struct hist_browser *browser, struct popup_action *act, 2410045b80ddSArnaldo Carvalho de Melo char **optstr, struct map *map) 2411bc7cad42SNamhyung Kim { 241269849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2413ea7cd592SNamhyung Kim return 0; 2414ea7cd592SNamhyung Kim 2415ea7cd592SNamhyung Kim if (asprintf(optstr, "Zoom %s %s DSO", 2416ea7cd592SNamhyung Kim browser->hists->dso_filter ? "out of" : "into", 2417045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) 2418ea7cd592SNamhyung Kim return 0; 2419ea7cd592SNamhyung Kim 2420045b80ddSArnaldo Carvalho de Melo act->ms.map = map; 2421ea7cd592SNamhyung Kim act->fn = do_zoom_dso; 2422ea7cd592SNamhyung Kim return 1; 2423ea7cd592SNamhyung Kim } 2424ea7cd592SNamhyung Kim 2425ea7cd592SNamhyung Kim static int 2426ea7cd592SNamhyung Kim do_browse_map(struct hist_browser *browser __maybe_unused, 2427ea7cd592SNamhyung Kim struct popup_action *act) 2428ea7cd592SNamhyung Kim { 2429ea7cd592SNamhyung Kim map__browse(act->ms.map); 2430bc7cad42SNamhyung Kim return 0; 2431bc7cad42SNamhyung Kim } 2432bc7cad42SNamhyung Kim 2433bc7cad42SNamhyung Kim static int 243469849fc5SJiri Olsa add_map_opt(struct hist_browser *browser, 2435ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, struct map *map) 2436ea7cd592SNamhyung Kim { 243769849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2438ea7cd592SNamhyung Kim return 0; 2439ea7cd592SNamhyung Kim 2440ea7cd592SNamhyung Kim if (asprintf(optstr, "Browse map details") < 0) 2441ea7cd592SNamhyung Kim return 0; 2442ea7cd592SNamhyung Kim 2443ea7cd592SNamhyung Kim act->ms.map = map; 2444ea7cd592SNamhyung Kim act->fn = do_browse_map; 2445ea7cd592SNamhyung Kim return 1; 2446ea7cd592SNamhyung Kim } 2447ea7cd592SNamhyung Kim 2448ea7cd592SNamhyung Kim static int 2449bc7cad42SNamhyung Kim do_run_script(struct hist_browser *browser __maybe_unused, 2450ea7cd592SNamhyung Kim struct popup_action *act) 2451bc7cad42SNamhyung Kim { 2452bc7cad42SNamhyung Kim char script_opt[64]; 2453bc7cad42SNamhyung Kim memset(script_opt, 0, sizeof(script_opt)); 2454bc7cad42SNamhyung Kim 2455ea7cd592SNamhyung Kim if (act->thread) { 2456bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -c %s ", 2457ea7cd592SNamhyung Kim thread__comm_str(act->thread)); 2458ea7cd592SNamhyung Kim } else if (act->ms.sym) { 2459bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -S %s ", 2460ea7cd592SNamhyung Kim act->ms.sym->name); 2461bc7cad42SNamhyung Kim } 2462bc7cad42SNamhyung Kim 2463bc7cad42SNamhyung Kim script_browse(script_opt); 2464bc7cad42SNamhyung Kim return 0; 2465bc7cad42SNamhyung Kim } 2466bc7cad42SNamhyung Kim 2467bc7cad42SNamhyung Kim static int 2468ea7cd592SNamhyung Kim add_script_opt(struct hist_browser *browser __maybe_unused, 2469ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 2470ea7cd592SNamhyung Kim struct thread *thread, struct symbol *sym) 2471ea7cd592SNamhyung Kim { 2472ea7cd592SNamhyung Kim if (thread) { 2473ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of thread [%s]", 2474ea7cd592SNamhyung Kim thread__comm_str(thread)) < 0) 2475ea7cd592SNamhyung Kim return 0; 2476ea7cd592SNamhyung Kim } else if (sym) { 2477ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of symbol [%s]", 2478ea7cd592SNamhyung Kim sym->name) < 0) 2479ea7cd592SNamhyung Kim return 0; 2480ea7cd592SNamhyung Kim } else { 2481ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for all samples") < 0) 2482ea7cd592SNamhyung Kim return 0; 2483ea7cd592SNamhyung Kim } 2484ea7cd592SNamhyung Kim 2485ea7cd592SNamhyung Kim act->thread = thread; 2486ea7cd592SNamhyung Kim act->ms.sym = sym; 2487ea7cd592SNamhyung Kim act->fn = do_run_script; 2488ea7cd592SNamhyung Kim return 1; 2489ea7cd592SNamhyung Kim } 2490ea7cd592SNamhyung Kim 2491ea7cd592SNamhyung Kim static int 2492ea7cd592SNamhyung Kim do_switch_data(struct hist_browser *browser __maybe_unused, 2493ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2494bc7cad42SNamhyung Kim { 2495bc7cad42SNamhyung Kim if (switch_data_file()) { 2496bc7cad42SNamhyung Kim ui__warning("Won't switch the data files due to\n" 2497bc7cad42SNamhyung Kim "no valid data file get selected!\n"); 2498ea7cd592SNamhyung Kim return 0; 2499bc7cad42SNamhyung Kim } 2500bc7cad42SNamhyung Kim 2501bc7cad42SNamhyung Kim return K_SWITCH_INPUT_DATA; 2502bc7cad42SNamhyung Kim } 2503bc7cad42SNamhyung Kim 2504ea7cd592SNamhyung Kim static int 2505ea7cd592SNamhyung Kim add_switch_opt(struct hist_browser *browser, 2506ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2507ea7cd592SNamhyung Kim { 2508ea7cd592SNamhyung Kim if (!is_report_browser(browser->hbt)) 2509ea7cd592SNamhyung Kim return 0; 2510ea7cd592SNamhyung Kim 2511ea7cd592SNamhyung Kim if (asprintf(optstr, "Switch to another data file in PWD") < 0) 2512ea7cd592SNamhyung Kim return 0; 2513ea7cd592SNamhyung Kim 2514ea7cd592SNamhyung Kim act->fn = do_switch_data; 2515ea7cd592SNamhyung Kim return 1; 2516ea7cd592SNamhyung Kim } 2517ea7cd592SNamhyung Kim 2518ea7cd592SNamhyung Kim static int 2519ea7cd592SNamhyung Kim do_exit_browser(struct hist_browser *browser __maybe_unused, 2520ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2521ea7cd592SNamhyung Kim { 2522ea7cd592SNamhyung Kim return 0; 2523ea7cd592SNamhyung Kim } 2524ea7cd592SNamhyung Kim 2525ea7cd592SNamhyung Kim static int 2526ea7cd592SNamhyung Kim add_exit_opt(struct hist_browser *browser __maybe_unused, 2527ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2528ea7cd592SNamhyung Kim { 2529ea7cd592SNamhyung Kim if (asprintf(optstr, "Exit") < 0) 2530ea7cd592SNamhyung Kim return 0; 2531ea7cd592SNamhyung Kim 2532ea7cd592SNamhyung Kim act->fn = do_exit_browser; 2533ea7cd592SNamhyung Kim return 1; 2534ea7cd592SNamhyung Kim } 2535ea7cd592SNamhyung Kim 253684734b06SKan Liang static int 253784734b06SKan Liang do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 253884734b06SKan Liang { 253935a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || act->socket < 0) 2540599a2f38SNamhyung Kim return 0; 2541599a2f38SNamhyung Kim 254284734b06SKan Liang if (browser->hists->socket_filter > -1) { 254384734b06SKan Liang pstack__remove(browser->pstack, &browser->hists->socket_filter); 254484734b06SKan Liang browser->hists->socket_filter = -1; 254584734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, false); 254684734b06SKan Liang } else { 254784734b06SKan Liang browser->hists->socket_filter = act->socket; 254884734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, true); 254984734b06SKan Liang pstack__push(browser->pstack, &browser->hists->socket_filter); 255084734b06SKan Liang } 255184734b06SKan Liang 255284734b06SKan Liang hists__filter_by_socket(browser->hists); 255384734b06SKan Liang hist_browser__reset(browser); 255484734b06SKan Liang return 0; 255584734b06SKan Liang } 255684734b06SKan Liang 255784734b06SKan Liang static int 255884734b06SKan Liang add_socket_opt(struct hist_browser *browser, struct popup_action *act, 255984734b06SKan Liang char **optstr, int socket_id) 256084734b06SKan Liang { 256135a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || socket_id < 0) 256284734b06SKan Liang return 0; 256384734b06SKan Liang 256484734b06SKan Liang if (asprintf(optstr, "Zoom %s Processor Socket %d", 256584734b06SKan Liang (browser->hists->socket_filter > -1) ? "out of" : "into", 256684734b06SKan Liang socket_id) < 0) 256784734b06SKan Liang return 0; 256884734b06SKan Liang 256984734b06SKan Liang act->socket = socket_id; 257084734b06SKan Liang act->fn = do_zoom_socket; 257184734b06SKan Liang return 1; 257284734b06SKan Liang } 257384734b06SKan Liang 2574112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb) 2575064f1981SNamhyung Kim { 2576064f1981SNamhyung Kim u64 nr_entries = 0; 2577064f1981SNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 2578064f1981SNamhyung Kim 2579f5b763feSNamhyung Kim if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) { 2580268397cbSNamhyung Kim hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 2581268397cbSNamhyung Kim return; 2582268397cbSNamhyung Kim } 2583268397cbSNamhyung Kim 258414135663SNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2585064f1981SNamhyung Kim nr_entries++; 2586f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd); 2587064f1981SNamhyung Kim } 2588064f1981SNamhyung Kim 2589112f761fSNamhyung Kim hb->nr_non_filtered_entries = nr_entries; 2590f5b763feSNamhyung Kim hb->nr_hierarchy_entries = nr_entries; 2591064f1981SNamhyung Kim } 2592341487abSFeng Tang 2593b62e8dfcSNamhyung Kim static void hist_browser__update_percent_limit(struct hist_browser *hb, 2594b62e8dfcSNamhyung Kim double percent) 2595b62e8dfcSNamhyung Kim { 2596b62e8dfcSNamhyung Kim struct hist_entry *he; 2597b62e8dfcSNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 2598b62e8dfcSNamhyung Kim u64 total = hists__total_period(hb->hists); 2599b62e8dfcSNamhyung Kim u64 min_callchain_hits = total * (percent / 100); 2600b62e8dfcSNamhyung Kim 2601b62e8dfcSNamhyung Kim hb->min_pcnt = callchain_param.min_percent = percent; 2602b62e8dfcSNamhyung Kim 2603b62e8dfcSNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2604b62e8dfcSNamhyung Kim he = rb_entry(nd, struct hist_entry, rb_node); 2605b62e8dfcSNamhyung Kim 260679dded87SNamhyung Kim if (he->has_no_entry) { 260779dded87SNamhyung Kim he->has_no_entry = false; 260879dded87SNamhyung Kim he->nr_rows = 0; 260979dded87SNamhyung Kim } 261079dded87SNamhyung Kim 2611d0506edbSNamhyung Kim if (!he->leaf || !symbol_conf.use_callchain) 2612d0506edbSNamhyung Kim goto next; 2613d0506edbSNamhyung Kim 2614b62e8dfcSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) { 2615b62e8dfcSNamhyung Kim total = he->stat.period; 2616b62e8dfcSNamhyung Kim 2617b62e8dfcSNamhyung Kim if (symbol_conf.cumulate_callchain) 2618b62e8dfcSNamhyung Kim total = he->stat_acc->period; 2619b62e8dfcSNamhyung Kim 2620b62e8dfcSNamhyung Kim min_callchain_hits = total * (percent / 100); 2621b62e8dfcSNamhyung Kim } 2622b62e8dfcSNamhyung Kim 2623b62e8dfcSNamhyung Kim callchain_param.sort(&he->sorted_chain, he->callchain, 2624b62e8dfcSNamhyung Kim min_callchain_hits, &callchain_param); 2625b62e8dfcSNamhyung Kim 2626d0506edbSNamhyung Kim next: 2627201fde73SNamhyung Kim nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 2628d0506edbSNamhyung Kim 2629b62e8dfcSNamhyung Kim /* force to re-evaluate folding state of callchains */ 2630b62e8dfcSNamhyung Kim he->init_have_children = false; 2631492b1010SNamhyung Kim hist_entry__set_folding(he, hb, false); 2632b62e8dfcSNamhyung Kim } 2633b62e8dfcSNamhyung Kim } 2634b62e8dfcSNamhyung Kim 2635aca7a94dSNamhyung Kim static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 2636dd00d486SJiri Olsa const char *helpline, 2637aca7a94dSNamhyung Kim bool left_exits, 263868d80758SNamhyung Kim struct hist_browser_timer *hbt, 2639064f1981SNamhyung Kim float min_pcnt, 2640ce80d3beSKan Liang struct perf_env *env) 2641aca7a94dSNamhyung Kim { 26424ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 2643b1a9ceefSNamhyung Kim struct hist_browser *browser = hist_browser__new(hists, hbt, env); 2644aca7a94dSNamhyung Kim struct branch_info *bi; 2645f2b487dbSNamhyung Kim #define MAX_OPTIONS 16 2646f2b487dbSNamhyung Kim char *options[MAX_OPTIONS]; 2647ea7cd592SNamhyung Kim struct popup_action actions[MAX_OPTIONS]; 2648aca7a94dSNamhyung Kim int nr_options = 0; 2649aca7a94dSNamhyung Kim int key = -1; 2650aca7a94dSNamhyung Kim char buf[64]; 26519783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 265259dc9f25SNamhyung Kim struct perf_hpp_fmt *fmt; 2653aca7a94dSNamhyung Kim 2654e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 2655e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 2656e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 2657e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 2658e8e684a5SNamhyung Kim "q/ESC/CTRL+C Exit browser\n\n" \ 2659e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 2660e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 2661e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 26627727a925SArnaldo Carvalho de Melo "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \ 26637727a925SArnaldo Carvalho de Melo "ESC Zoom out\n" \ 2664e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 2665e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 2666e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 2667e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 2668105eb30fSNamhyung Kim "F Toggle percentage of filtered entries\n" \ 2669025bf7eaSArnaldo Carvalho de Melo "H Display column headers\n" \ 2670b62e8dfcSNamhyung Kim "L Change percent limit\n" \ 267131eb4360SNamhyung Kim "m Display context menu\n" \ 267284734b06SKan Liang "S Zoom into current Processor Socket\n" \ 2673e8e684a5SNamhyung Kim 2674e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 2675e8e684a5SNamhyung Kim const char report_help[] = HIST_BROWSER_HELP_COMMON 26766dd60135SNamhyung Kim "i Show header information\n" 2677e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2678e8e684a5SNamhyung Kim "r Run available scripts\n" 2679e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 2680e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2681e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 2682e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2683e8e684a5SNamhyung Kim const char top_help[] = HIST_BROWSER_HELP_COMMON 2684e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2685e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2686e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 268742337a22SNamhyung Kim "z Toggle zeroing of samples\n" 2688fbb7997eSArnaldo Carvalho de Melo "f Enable/Disable events\n" 2689e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2690e8e684a5SNamhyung Kim 2691aca7a94dSNamhyung Kim if (browser == NULL) 2692aca7a94dSNamhyung Kim return -1; 2693aca7a94dSNamhyung Kim 2694ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 2695ed426915SNamhyung Kim SLang_reset_tty(); 2696ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 2697ed426915SNamhyung Kim 269803905048SNamhyung Kim if (min_pcnt) 2699064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 2700112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 2701064f1981SNamhyung Kim 270284734b06SKan Liang browser->pstack = pstack__new(3); 270301f00a1cSNamhyung Kim if (browser->pstack == NULL) 2704aca7a94dSNamhyung Kim goto out; 2705aca7a94dSNamhyung Kim 2706aca7a94dSNamhyung Kim ui_helpline__push(helpline); 2707aca7a94dSNamhyung Kim 2708aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 2709ea7cd592SNamhyung Kim memset(actions, 0, sizeof(actions)); 2710aca7a94dSNamhyung Kim 2711f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 271259dc9f25SNamhyung Kim perf_hpp__reset_width(fmt, hists); 2713c6c3c02dSArnaldo Carvalho de Melo /* 2714c6c3c02dSArnaldo Carvalho de Melo * This is done just once, and activates the horizontal scrolling 2715c6c3c02dSArnaldo Carvalho de Melo * code in the ui_browser code, it would be better to have a the 2716c6c3c02dSArnaldo Carvalho de Melo * counter in the perf_hpp code, but I couldn't find doing it here 2717c6c3c02dSArnaldo Carvalho de Melo * works, FIXME by setting this in hist_browser__new, for now, be 2718c6c3c02dSArnaldo Carvalho de Melo * clever 8-) 2719c6c3c02dSArnaldo Carvalho de Melo */ 2720c6c3c02dSArnaldo Carvalho de Melo ++browser->b.columns; 2721c6c3c02dSArnaldo Carvalho de Melo } 272259dc9f25SNamhyung Kim 27235b591669SNamhyung Kim if (symbol_conf.col_width_list_str) 27245b591669SNamhyung Kim perf_hpp__set_user_width(symbol_conf.col_width_list_str); 27255b591669SNamhyung Kim 2726aca7a94dSNamhyung Kim while (1) { 2727f3b623b8SArnaldo Carvalho de Melo struct thread *thread = NULL; 2728045b80ddSArnaldo Carvalho de Melo struct map *map = NULL; 2729ea7cd592SNamhyung Kim int choice = 0; 273084734b06SKan Liang int socked_id = -1; 2731aca7a94dSNamhyung Kim 2732aca7a94dSNamhyung Kim nr_options = 0; 2733aca7a94dSNamhyung Kim 27345f00b0f4SArnaldo Carvalho de Melo key = hist_browser__run(browser, helpline); 2735aca7a94dSNamhyung Kim 2736aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 2737aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 2738045b80ddSArnaldo Carvalho de Melo map = browser->selection->map; 273984734b06SKan Liang socked_id = browser->he_selection->socket; 2740aca7a94dSNamhyung Kim } 2741aca7a94dSNamhyung Kim switch (key) { 2742aca7a94dSNamhyung Kim case K_TAB: 2743aca7a94dSNamhyung Kim case K_UNTAB: 2744aca7a94dSNamhyung Kim if (nr_events == 1) 2745aca7a94dSNamhyung Kim continue; 2746aca7a94dSNamhyung Kim /* 2747aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 2748aca7a94dSNamhyung Kim * go to the next or previous 2749aca7a94dSNamhyung Kim */ 2750aca7a94dSNamhyung Kim goto out_free_stack; 2751aca7a94dSNamhyung Kim case 'a': 27522e0453afSJiri Olsa if (!hists__has(hists, sym)) { 2753aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 2754aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 2755aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 2756aca7a94dSNamhyung Kim continue; 2757aca7a94dSNamhyung Kim } 2758aca7a94dSNamhyung Kim 2759aca7a94dSNamhyung Kim if (browser->selection == NULL || 2760aca7a94dSNamhyung Kim browser->selection->sym == NULL || 2761aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 2762aca7a94dSNamhyung Kim continue; 2763bc7cad42SNamhyung Kim 2764ea7cd592SNamhyung Kim actions->ms.map = browser->selection->map; 2765ea7cd592SNamhyung Kim actions->ms.sym = browser->selection->sym; 2766ea7cd592SNamhyung Kim do_annotate(browser, actions); 2767bc7cad42SNamhyung Kim continue; 2768aff3f3f6SArnaldo Carvalho de Melo case 'P': 2769aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 2770aff3f3f6SArnaldo Carvalho de Melo continue; 2771aca7a94dSNamhyung Kim case 'd': 2772fae00650SArnaldo Carvalho de Melo actions->ms.map = map; 2773ea7cd592SNamhyung Kim do_zoom_dso(browser, actions); 2774bc7cad42SNamhyung Kim continue; 2775a7cb8863SArnaldo Carvalho de Melo case 'V': 2776a7cb8863SArnaldo Carvalho de Melo browser->show_dso = !browser->show_dso; 2777a7cb8863SArnaldo Carvalho de Melo continue; 2778aca7a94dSNamhyung Kim case 't': 2779ea7cd592SNamhyung Kim actions->thread = thread; 2780ea7cd592SNamhyung Kim do_zoom_thread(browser, actions); 2781bc7cad42SNamhyung Kim continue; 278284734b06SKan Liang case 'S': 278384734b06SKan Liang actions->socket = socked_id; 278484734b06SKan Liang do_zoom_socket(browser, actions); 278584734b06SKan Liang continue; 27865a5626b1SArnaldo Carvalho de Melo case '/': 2787aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 27884aa8e454SArnaldo Carvalho de Melo "Please enter the name of symbol you want to see.\n" 27894aa8e454SArnaldo Carvalho de Melo "To remove the filter later, press / + ENTER.", 2790aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 2791aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 279205e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 279305e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 2794aca7a94dSNamhyung Kim hist_browser__reset(browser); 2795aca7a94dSNamhyung Kim } 2796aca7a94dSNamhyung Kim continue; 2797cdbab7c2SFeng Tang case 'r': 2798ea7cd592SNamhyung Kim if (is_report_browser(hbt)) { 2799ea7cd592SNamhyung Kim actions->thread = NULL; 2800ea7cd592SNamhyung Kim actions->ms.sym = NULL; 2801ea7cd592SNamhyung Kim do_run_script(browser, actions); 2802ea7cd592SNamhyung Kim } 2803c77d8d70SFeng Tang continue; 2804341487abSFeng Tang case 's': 2805bc7cad42SNamhyung Kim if (is_report_browser(hbt)) { 2806ea7cd592SNamhyung Kim key = do_switch_data(browser, actions); 2807bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 2808bc7cad42SNamhyung Kim goto out_free_stack; 2809bc7cad42SNamhyung Kim } 2810341487abSFeng Tang continue; 28116dd60135SNamhyung Kim case 'i': 28126dd60135SNamhyung Kim /* env->arch is NULL for live-mode (i.e. perf top) */ 28136dd60135SNamhyung Kim if (env->arch) 28146dd60135SNamhyung Kim tui__header_window(env); 28156dd60135SNamhyung Kim continue; 2816105eb30fSNamhyung Kim case 'F': 2817105eb30fSNamhyung Kim symbol_conf.filter_relative ^= 1; 2818105eb30fSNamhyung Kim continue; 281942337a22SNamhyung Kim case 'z': 282042337a22SNamhyung Kim if (!is_report_browser(hbt)) { 282142337a22SNamhyung Kim struct perf_top *top = hbt->arg; 282242337a22SNamhyung Kim 282342337a22SNamhyung Kim top->zero = !top->zero; 282442337a22SNamhyung Kim } 282542337a22SNamhyung Kim continue; 2826b62e8dfcSNamhyung Kim case 'L': 2827b62e8dfcSNamhyung Kim if (ui_browser__input_window("Percent Limit", 2828b62e8dfcSNamhyung Kim "Please enter the value you want to hide entries under that percent.", 2829b62e8dfcSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 2830b62e8dfcSNamhyung Kim delay_secs * 2) == K_ENTER) { 2831b62e8dfcSNamhyung Kim char *end; 2832b62e8dfcSNamhyung Kim double new_percent = strtod(buf, &end); 2833b62e8dfcSNamhyung Kim 2834b62e8dfcSNamhyung Kim if (new_percent < 0 || new_percent > 100) { 2835b62e8dfcSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 2836b62e8dfcSNamhyung Kim "Invalid percent: %.2f", new_percent); 2837b62e8dfcSNamhyung Kim continue; 2838b62e8dfcSNamhyung Kim } 2839b62e8dfcSNamhyung Kim 2840b62e8dfcSNamhyung Kim hist_browser__update_percent_limit(browser, new_percent); 2841b62e8dfcSNamhyung Kim hist_browser__reset(browser); 2842b62e8dfcSNamhyung Kim } 2843b62e8dfcSNamhyung Kim continue; 2844aca7a94dSNamhyung Kim case K_F1: 2845aca7a94dSNamhyung Kim case 'h': 2846aca7a94dSNamhyung Kim case '?': 2847aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 2848e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 2849aca7a94dSNamhyung Kim continue; 2850aca7a94dSNamhyung Kim case K_ENTER: 2851aca7a94dSNamhyung Kim case K_RIGHT: 285231eb4360SNamhyung Kim case 'm': 2853aca7a94dSNamhyung Kim /* menu */ 2854aca7a94dSNamhyung Kim break; 285563ab1749SArnaldo Carvalho de Melo case K_ESC: 2856aca7a94dSNamhyung Kim case K_LEFT: { 2857aca7a94dSNamhyung Kim const void *top; 2858aca7a94dSNamhyung Kim 285901f00a1cSNamhyung Kim if (pstack__empty(browser->pstack)) { 2860aca7a94dSNamhyung Kim /* 2861aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 2862aca7a94dSNamhyung Kim */ 2863aca7a94dSNamhyung Kim if (left_exits) 2864aca7a94dSNamhyung Kim goto out_free_stack; 286563ab1749SArnaldo Carvalho de Melo 286663ab1749SArnaldo Carvalho de Melo if (key == K_ESC && 286763ab1749SArnaldo Carvalho de Melo ui_browser__dialog_yesno(&browser->b, 286863ab1749SArnaldo Carvalho de Melo "Do you really want to exit?")) 286963ab1749SArnaldo Carvalho de Melo goto out_free_stack; 287063ab1749SArnaldo Carvalho de Melo 2871aca7a94dSNamhyung Kim continue; 2872aca7a94dSNamhyung Kim } 28736422184bSNamhyung Kim top = pstack__peek(browser->pstack); 2874bc7cad42SNamhyung Kim if (top == &browser->hists->dso_filter) { 28756422184bSNamhyung Kim /* 28766422184bSNamhyung Kim * No need to set actions->dso here since 28776422184bSNamhyung Kim * it's just to remove the current filter. 28786422184bSNamhyung Kim * Ditto for thread below. 28796422184bSNamhyung Kim */ 28806422184bSNamhyung Kim do_zoom_dso(browser, actions); 288184734b06SKan Liang } else if (top == &browser->hists->thread_filter) { 28826422184bSNamhyung Kim do_zoom_thread(browser, actions); 288384734b06SKan Liang } else if (top == &browser->hists->socket_filter) { 288484734b06SKan Liang do_zoom_socket(browser, actions); 288584734b06SKan Liang } 2886aca7a94dSNamhyung Kim continue; 2887aca7a94dSNamhyung Kim } 2888aca7a94dSNamhyung Kim case 'q': 2889aca7a94dSNamhyung Kim case CTRL('c'): 2890516e5368SArnaldo Carvalho de Melo goto out_free_stack; 2891fbb7997eSArnaldo Carvalho de Melo case 'f': 289213d1e536SNamhyung Kim if (!is_report_browser(hbt)) { 289313d1e536SNamhyung Kim struct perf_top *top = hbt->arg; 289413d1e536SNamhyung Kim 289513d1e536SNamhyung Kim perf_evlist__toggle_enable(top->evlist); 289613d1e536SNamhyung Kim /* 289713d1e536SNamhyung Kim * No need to refresh, resort/decay histogram 289813d1e536SNamhyung Kim * entries if we are not collecting samples: 289913d1e536SNamhyung Kim */ 290013d1e536SNamhyung Kim if (top->evlist->enabled) { 290113d1e536SNamhyung Kim helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; 290213d1e536SNamhyung Kim hbt->refresh = delay_secs; 290313d1e536SNamhyung Kim } else { 290413d1e536SNamhyung Kim helpline = "Press 'f' again to re-enable the events"; 290513d1e536SNamhyung Kim hbt->refresh = 0; 290613d1e536SNamhyung Kim } 290713d1e536SNamhyung Kim continue; 290813d1e536SNamhyung Kim } 29093e323dc0SArnaldo Carvalho de Melo /* Fall thru */ 2910aca7a94dSNamhyung Kim default: 29113e323dc0SArnaldo Carvalho de Melo helpline = "Press '?' for help on key bindings"; 2912aca7a94dSNamhyung Kim continue; 2913aca7a94dSNamhyung Kim } 2914aca7a94dSNamhyung Kim 29152e0453afSJiri Olsa if (!hists__has(hists, sym) || browser->selection == NULL) 29160ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 29170ba332f7SArnaldo Carvalho de Melo 291855369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 2919aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 29200ba332f7SArnaldo Carvalho de Melo 29210ba332f7SArnaldo Carvalho de Melo if (bi == NULL) 29220ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 29230ba332f7SArnaldo Carvalho de Melo 2924ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2925ea7cd592SNamhyung Kim &actions[nr_options], 2926ea7cd592SNamhyung Kim &options[nr_options], 2927ea7cd592SNamhyung Kim bi->from.map, 2928ea7cd592SNamhyung Kim bi->from.sym); 2929ea7cd592SNamhyung Kim if (bi->to.sym != bi->from.sym) 2930ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2931ea7cd592SNamhyung Kim &actions[nr_options], 2932ea7cd592SNamhyung Kim &options[nr_options], 2933ea7cd592SNamhyung Kim bi->to.map, 2934ea7cd592SNamhyung Kim bi->to.sym); 2935aca7a94dSNamhyung Kim } else { 2936ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2937ea7cd592SNamhyung Kim &actions[nr_options], 2938ea7cd592SNamhyung Kim &options[nr_options], 2939ea7cd592SNamhyung Kim browser->selection->map, 2940ea7cd592SNamhyung Kim browser->selection->sym); 2941446fb96cSArnaldo Carvalho de Melo } 29420ba332f7SArnaldo Carvalho de Melo skip_annotation: 2943ea7cd592SNamhyung Kim nr_options += add_thread_opt(browser, &actions[nr_options], 2944ea7cd592SNamhyung Kim &options[nr_options], thread); 2945ea7cd592SNamhyung Kim nr_options += add_dso_opt(browser, &actions[nr_options], 2946045b80ddSArnaldo Carvalho de Melo &options[nr_options], map); 2947ea7cd592SNamhyung Kim nr_options += add_map_opt(browser, &actions[nr_options], 2948ea7cd592SNamhyung Kim &options[nr_options], 2949bd315aabSWang Nan browser->selection ? 2950bd315aabSWang Nan browser->selection->map : NULL); 295184734b06SKan Liang nr_options += add_socket_opt(browser, &actions[nr_options], 295284734b06SKan Liang &options[nr_options], 295384734b06SKan Liang socked_id); 2954cdbab7c2SFeng Tang /* perf script support */ 2955b1baae89SNamhyung Kim if (!is_report_browser(hbt)) 2956b1baae89SNamhyung Kim goto skip_scripting; 2957b1baae89SNamhyung Kim 2958cdbab7c2SFeng Tang if (browser->he_selection) { 2959fa82911aSJiri Olsa if (hists__has(hists, thread) && thread) { 2960ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 2961ea7cd592SNamhyung Kim &actions[nr_options], 2962ea7cd592SNamhyung Kim &options[nr_options], 2963ea7cd592SNamhyung Kim thread, NULL); 29642eafd410SNamhyung Kim } 2965bd315aabSWang Nan /* 2966bd315aabSWang Nan * Note that browser->selection != NULL 2967bd315aabSWang Nan * when browser->he_selection is not NULL, 2968bd315aabSWang Nan * so we don't need to check browser->selection 2969bd315aabSWang Nan * before fetching browser->selection->sym like what 2970bd315aabSWang Nan * we do before fetching browser->selection->map. 2971bd315aabSWang Nan * 2972bd315aabSWang Nan * See hist_browser__show_entry. 2973bd315aabSWang Nan */ 29742e0453afSJiri Olsa if (hists__has(hists, sym) && browser->selection->sym) { 2975ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 2976ea7cd592SNamhyung Kim &actions[nr_options], 2977ea7cd592SNamhyung Kim &options[nr_options], 2978ea7cd592SNamhyung Kim NULL, browser->selection->sym); 2979cdbab7c2SFeng Tang } 2980c221acb0SNamhyung Kim } 2981ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, &actions[nr_options], 2982ea7cd592SNamhyung Kim &options[nr_options], NULL, NULL); 2983ea7cd592SNamhyung Kim nr_options += add_switch_opt(browser, &actions[nr_options], 2984ea7cd592SNamhyung Kim &options[nr_options]); 2985b1baae89SNamhyung Kim skip_scripting: 2986ea7cd592SNamhyung Kim nr_options += add_exit_opt(browser, &actions[nr_options], 2987ea7cd592SNamhyung Kim &options[nr_options]); 2988aca7a94dSNamhyung Kim 2989ea7cd592SNamhyung Kim do { 2990ea7cd592SNamhyung Kim struct popup_action *act; 2991ea7cd592SNamhyung Kim 2992ea7cd592SNamhyung Kim choice = ui__popup_menu(nr_options, options); 2993ea7cd592SNamhyung Kim if (choice == -1 || choice >= nr_options) 2994aca7a94dSNamhyung Kim break; 2995aca7a94dSNamhyung Kim 2996ea7cd592SNamhyung Kim act = &actions[choice]; 2997ea7cd592SNamhyung Kim key = act->fn(browser, act); 2998ea7cd592SNamhyung Kim } while (key == 1); 2999aca7a94dSNamhyung Kim 3000bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 3001341487abSFeng Tang break; 3002341487abSFeng Tang } 3003aca7a94dSNamhyung Kim out_free_stack: 300401f00a1cSNamhyung Kim pstack__delete(browser->pstack); 3005aca7a94dSNamhyung Kim out: 3006aca7a94dSNamhyung Kim hist_browser__delete(browser); 3007f2b487dbSNamhyung Kim free_popup_options(options, MAX_OPTIONS); 3008aca7a94dSNamhyung Kim return key; 3009aca7a94dSNamhyung Kim } 3010aca7a94dSNamhyung Kim 3011aca7a94dSNamhyung Kim struct perf_evsel_menu { 3012aca7a94dSNamhyung Kim struct ui_browser b; 3013aca7a94dSNamhyung Kim struct perf_evsel *selection; 3014aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 3015064f1981SNamhyung Kim float min_pcnt; 3016ce80d3beSKan Liang struct perf_env *env; 3017aca7a94dSNamhyung Kim }; 3018aca7a94dSNamhyung Kim 3019aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 3020aca7a94dSNamhyung Kim void *entry, int row) 3021aca7a94dSNamhyung Kim { 3022aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 3023aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 3024aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 30254ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 3026aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 30274ea062edSArnaldo Carvalho de Melo unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 30287289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 3029aca7a94dSNamhyung Kim char bf[256], unit; 3030aca7a94dSNamhyung Kim const char *warn = " "; 3031aca7a94dSNamhyung Kim size_t printed; 3032aca7a94dSNamhyung Kim 3033aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 3034aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 3035aca7a94dSNamhyung Kim 3036759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 3037717e263fSNamhyung Kim struct perf_evsel *pos; 3038717e263fSNamhyung Kim 3039717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 3040717e263fSNamhyung Kim 3041717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 30424ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 30434ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 3044717e263fSNamhyung Kim } 3045717e263fSNamhyung Kim } 3046717e263fSNamhyung Kim 3047aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3048aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 3049aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 3050517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%s", bf); 3051aca7a94dSNamhyung Kim 30524ea062edSArnaldo Carvalho de Melo nr_events = hists->stats.nr_events[PERF_RECORD_LOST]; 3053aca7a94dSNamhyung Kim if (nr_events != 0) { 3054aca7a94dSNamhyung Kim menu->lost_events = true; 3055aca7a94dSNamhyung Kim if (!current_entry) 3056aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 3057aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3058aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 3059aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 3060aca7a94dSNamhyung Kim warn = bf; 3061aca7a94dSNamhyung Kim } 3062aca7a94dSNamhyung Kim 306326270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, warn, browser->width - printed); 3064aca7a94dSNamhyung Kim 3065aca7a94dSNamhyung Kim if (current_entry) 3066aca7a94dSNamhyung Kim menu->selection = evsel; 3067aca7a94dSNamhyung Kim } 3068aca7a94dSNamhyung Kim 3069aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 3070aca7a94dSNamhyung Kim int nr_events, const char *help, 30719783adf7SNamhyung Kim struct hist_browser_timer *hbt) 3072aca7a94dSNamhyung Kim { 3073aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 3074aca7a94dSNamhyung Kim struct perf_evsel *pos; 3075dd00d486SJiri Olsa const char *title = "Available samples"; 30769783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 3077aca7a94dSNamhyung Kim int key; 3078aca7a94dSNamhyung Kim 3079aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 3080aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 3081aca7a94dSNamhyung Kim return -1; 3082aca7a94dSNamhyung Kim 3083aca7a94dSNamhyung Kim while (1) { 3084aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 3085aca7a94dSNamhyung Kim 3086aca7a94dSNamhyung Kim switch (key) { 3087aca7a94dSNamhyung Kim case K_TIMER: 30889783adf7SNamhyung Kim hbt->timer(hbt->arg); 3089aca7a94dSNamhyung Kim 3090aca7a94dSNamhyung Kim if (!menu->lost_events_warned && menu->lost_events) { 3091aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 3092aca7a94dSNamhyung Kim menu->lost_events_warned = true; 3093aca7a94dSNamhyung Kim } 3094aca7a94dSNamhyung Kim continue; 3095aca7a94dSNamhyung Kim case K_RIGHT: 3096aca7a94dSNamhyung Kim case K_ENTER: 3097aca7a94dSNamhyung Kim if (!menu->selection) 3098aca7a94dSNamhyung Kim continue; 3099aca7a94dSNamhyung Kim pos = menu->selection; 3100aca7a94dSNamhyung Kim browse_hists: 3101aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 3102aca7a94dSNamhyung Kim /* 3103aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 3104aca7a94dSNamhyung Kim * default evsel resorted hists tree. 3105aca7a94dSNamhyung Kim */ 31069783adf7SNamhyung Kim if (hbt) 31079783adf7SNamhyung Kim hbt->timer(hbt->arg); 3108aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 3109dd00d486SJiri Olsa true, hbt, 3110064f1981SNamhyung Kim menu->min_pcnt, 311168d80758SNamhyung Kim menu->env); 3112aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 3113aca7a94dSNamhyung Kim switch (key) { 3114aca7a94dSNamhyung Kim case K_TAB: 3115aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 31169a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__first(evlist); 3117aca7a94dSNamhyung Kim else 31189a354cdcSArnaldo Carvalho de Melo pos = perf_evsel__next(pos); 3119aca7a94dSNamhyung Kim goto browse_hists; 3120aca7a94dSNamhyung Kim case K_UNTAB: 3121aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 31229a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__last(evlist); 3123aca7a94dSNamhyung Kim else 3124d87fcb4aSArnaldo Carvalho de Melo pos = perf_evsel__prev(pos); 3125aca7a94dSNamhyung Kim goto browse_hists; 3126341487abSFeng Tang case K_SWITCH_INPUT_DATA: 3127aca7a94dSNamhyung Kim case 'q': 3128aca7a94dSNamhyung Kim case CTRL('c'): 3129aca7a94dSNamhyung Kim goto out; 313063ab1749SArnaldo Carvalho de Melo case K_ESC: 3131aca7a94dSNamhyung Kim default: 3132aca7a94dSNamhyung Kim continue; 3133aca7a94dSNamhyung Kim } 3134aca7a94dSNamhyung Kim case K_LEFT: 3135aca7a94dSNamhyung Kim continue; 3136aca7a94dSNamhyung Kim case K_ESC: 3137aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 3138aca7a94dSNamhyung Kim "Do you really want to exit?")) 3139aca7a94dSNamhyung Kim continue; 3140aca7a94dSNamhyung Kim /* Fall thru */ 3141aca7a94dSNamhyung Kim case 'q': 3142aca7a94dSNamhyung Kim case CTRL('c'): 3143aca7a94dSNamhyung Kim goto out; 3144aca7a94dSNamhyung Kim default: 3145aca7a94dSNamhyung Kim continue; 3146aca7a94dSNamhyung Kim } 3147aca7a94dSNamhyung Kim } 3148aca7a94dSNamhyung Kim 3149aca7a94dSNamhyung Kim out: 3150aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 3151aca7a94dSNamhyung Kim return key; 3152aca7a94dSNamhyung Kim } 3153aca7a94dSNamhyung Kim 3154316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 3155fc24d7c2SNamhyung Kim void *entry) 3156fc24d7c2SNamhyung Kim { 3157fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 3158fc24d7c2SNamhyung Kim 3159fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 3160fc24d7c2SNamhyung Kim return true; 3161fc24d7c2SNamhyung Kim 3162fc24d7c2SNamhyung Kim return false; 3163fc24d7c2SNamhyung Kim } 3164fc24d7c2SNamhyung Kim 3165aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 3166fc24d7c2SNamhyung Kim int nr_entries, const char *help, 316768d80758SNamhyung Kim struct hist_browser_timer *hbt, 3168064f1981SNamhyung Kim float min_pcnt, 3169ce80d3beSKan Liang struct perf_env *env) 3170aca7a94dSNamhyung Kim { 3171aca7a94dSNamhyung Kim struct perf_evsel *pos; 3172aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 3173aca7a94dSNamhyung Kim .b = { 3174aca7a94dSNamhyung Kim .entries = &evlist->entries, 3175aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 3176aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 3177aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 3178fc24d7c2SNamhyung Kim .filter = filter_group_entries, 3179fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 3180aca7a94dSNamhyung Kim .priv = evlist, 3181aca7a94dSNamhyung Kim }, 3182064f1981SNamhyung Kim .min_pcnt = min_pcnt, 318368d80758SNamhyung Kim .env = env, 3184aca7a94dSNamhyung Kim }; 3185aca7a94dSNamhyung Kim 3186aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 3187aca7a94dSNamhyung Kim 31880050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 31897289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 3190aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 3191aca7a94dSNamhyung Kim 3192aca7a94dSNamhyung Kim if (menu.b.width < line_len) 3193aca7a94dSNamhyung Kim menu.b.width = line_len; 3194aca7a94dSNamhyung Kim } 3195aca7a94dSNamhyung Kim 3196fc24d7c2SNamhyung Kim return perf_evsel_menu__run(&menu, nr_entries, help, hbt); 3197aca7a94dSNamhyung Kim } 3198aca7a94dSNamhyung Kim 3199aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 320068d80758SNamhyung Kim struct hist_browser_timer *hbt, 3201064f1981SNamhyung Kim float min_pcnt, 3202ce80d3beSKan Liang struct perf_env *env) 3203aca7a94dSNamhyung Kim { 3204fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 3205fc24d7c2SNamhyung Kim 3206fc24d7c2SNamhyung Kim single_entry: 3207fc24d7c2SNamhyung Kim if (nr_entries == 1) { 32089a354cdcSArnaldo Carvalho de Melo struct perf_evsel *first = perf_evlist__first(evlist); 3209fc24d7c2SNamhyung Kim 3210fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 3211dd00d486SJiri Olsa false, hbt, min_pcnt, 3212064f1981SNamhyung Kim env); 3213aca7a94dSNamhyung Kim } 3214aca7a94dSNamhyung Kim 3215fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 3216fc24d7c2SNamhyung Kim struct perf_evsel *pos; 3217fc24d7c2SNamhyung Kim 3218fc24d7c2SNamhyung Kim nr_entries = 0; 32190050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 3220fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 3221fc24d7c2SNamhyung Kim nr_entries++; 32220050f7aaSArnaldo Carvalho de Melo } 3223fc24d7c2SNamhyung Kim 3224fc24d7c2SNamhyung Kim if (nr_entries == 1) 3225fc24d7c2SNamhyung Kim goto single_entry; 3226fc24d7c2SNamhyung Kim } 3227fc24d7c2SNamhyung Kim 3228fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 3229064f1981SNamhyung Kim hbt, min_pcnt, env); 3230aca7a94dSNamhyung Kim } 3231