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 24*5b91a86fSJiri Olsa static int perf_evsel_browser_title(struct hist_browser *browser, 251e378ebdSTaeung Song char *bf, size_t size); 26112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb); 27aca7a94dSNamhyung Kim 28c3b78952SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 29c3b78952SNamhyung Kim float min_pcnt); 30c3b78952SNamhyung Kim 31268397cbSNamhyung Kim static bool hist_browser__has_filter(struct hist_browser *hb) 32268397cbSNamhyung Kim { 339c0fa8ddSArnaldo Carvalho de Melo return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter; 34268397cbSNamhyung Kim } 35268397cbSNamhyung Kim 364fabf3d1SHe Kuang static int hist_browser__get_folding(struct hist_browser *browser) 374fabf3d1SHe Kuang { 384fabf3d1SHe Kuang struct rb_node *nd; 394fabf3d1SHe Kuang struct hists *hists = browser->hists; 404fabf3d1SHe Kuang int unfolded_rows = 0; 414fabf3d1SHe Kuang 424fabf3d1SHe Kuang for (nd = rb_first(&hists->entries); 434fabf3d1SHe Kuang (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 44f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd)) { 454fabf3d1SHe Kuang struct hist_entry *he = 464fabf3d1SHe Kuang rb_entry(nd, struct hist_entry, rb_node); 474fabf3d1SHe Kuang 48f5b763feSNamhyung Kim if (he->leaf && he->unfolded) 494fabf3d1SHe Kuang unfolded_rows += he->nr_rows; 504fabf3d1SHe Kuang } 514fabf3d1SHe Kuang return unfolded_rows; 524fabf3d1SHe Kuang } 534fabf3d1SHe Kuang 54c3b78952SNamhyung Kim static u32 hist_browser__nr_entries(struct hist_browser *hb) 55c3b78952SNamhyung Kim { 56c3b78952SNamhyung Kim u32 nr_entries; 57c3b78952SNamhyung Kim 58f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 59f5b763feSNamhyung Kim nr_entries = hb->nr_hierarchy_entries; 60f5b763feSNamhyung Kim else if (hist_browser__has_filter(hb)) 61c3b78952SNamhyung Kim nr_entries = hb->nr_non_filtered_entries; 62c3b78952SNamhyung Kim else 63c3b78952SNamhyung Kim nr_entries = hb->hists->nr_entries; 64c3b78952SNamhyung Kim 654fabf3d1SHe Kuang hb->nr_callchain_rows = hist_browser__get_folding(hb); 66c3b78952SNamhyung Kim return nr_entries + hb->nr_callchain_rows; 67c3b78952SNamhyung Kim } 68c3b78952SNamhyung Kim 69025bf7eaSArnaldo Carvalho de Melo static void hist_browser__update_rows(struct hist_browser *hb) 70025bf7eaSArnaldo Carvalho de Melo { 71025bf7eaSArnaldo Carvalho de Melo struct ui_browser *browser = &hb->b; 72025bf7eaSArnaldo Carvalho de Melo u16 header_offset = hb->show_headers ? 1 : 0, index_row; 73025bf7eaSArnaldo Carvalho de Melo 74025bf7eaSArnaldo Carvalho de Melo browser->rows = browser->height - header_offset; 75025bf7eaSArnaldo Carvalho de Melo /* 76025bf7eaSArnaldo Carvalho de Melo * Verify if we were at the last line and that line isn't 77025bf7eaSArnaldo Carvalho de Melo * visibe because we now show the header line(s). 78025bf7eaSArnaldo Carvalho de Melo */ 79025bf7eaSArnaldo Carvalho de Melo index_row = browser->index - browser->top_idx; 80025bf7eaSArnaldo Carvalho de Melo if (index_row >= browser->rows) 81025bf7eaSArnaldo Carvalho de Melo browser->index -= index_row - browser->rows + 1; 82025bf7eaSArnaldo Carvalho de Melo } 83025bf7eaSArnaldo Carvalho de Melo 84357cfff1SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct ui_browser *browser) 85aca7a94dSNamhyung Kim { 86357cfff1SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 87357cfff1SArnaldo Carvalho de Melo 88aca7a94dSNamhyung Kim /* 3 == +/- toggle symbol before actual hist_entry rendering */ 89357cfff1SArnaldo Carvalho de Melo browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]")); 90357cfff1SArnaldo Carvalho de Melo /* 91357cfff1SArnaldo Carvalho de Melo * FIXME: Just keeping existing behaviour, but this really should be 92357cfff1SArnaldo Carvalho de Melo * before updating browser->width, as it will invalidate the 93357cfff1SArnaldo Carvalho de Melo * calculation above. Fix this and the fallout in another 94357cfff1SArnaldo Carvalho de Melo * changeset. 95357cfff1SArnaldo Carvalho de Melo */ 96357cfff1SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(browser); 97025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(hb); 98aca7a94dSNamhyung Kim } 99aca7a94dSNamhyung Kim 100ca3ff33bSArnaldo Carvalho de Melo static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) 101ca3ff33bSArnaldo Carvalho de Melo { 102025bf7eaSArnaldo Carvalho de Melo u16 header_offset = browser->show_headers ? 1 : 0; 103025bf7eaSArnaldo Carvalho de Melo 104025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row + header_offset, column); 105ca3ff33bSArnaldo Carvalho de Melo } 106ca3ff33bSArnaldo Carvalho de Melo 10705e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser) 108aca7a94dSNamhyung Kim { 109c3b78952SNamhyung Kim /* 110c3b78952SNamhyung Kim * The hists__remove_entry_filter() already folds non-filtered 111c3b78952SNamhyung Kim * entries so we can assume it has 0 callchain rows. 112c3b78952SNamhyung Kim */ 113c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 114c3b78952SNamhyung Kim 115268397cbSNamhyung Kim hist_browser__update_nr_entries(browser); 116c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 117357cfff1SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(&browser->b); 11805e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 119aca7a94dSNamhyung Kim } 120aca7a94dSNamhyung Kim 121aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded) 122aca7a94dSNamhyung Kim { 123aca7a94dSNamhyung Kim return unfolded ? '-' : '+'; 124aca7a94dSNamhyung Kim } 125aca7a94dSNamhyung Kim 12605e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he) 127aca7a94dSNamhyung Kim { 1283698dab1SNamhyung Kim return he->has_children ? tree__folded_sign(he->unfolded) : ' '; 129aca7a94dSNamhyung Kim } 130aca7a94dSNamhyung Kim 13105e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl) 132aca7a94dSNamhyung Kim { 1333698dab1SNamhyung Kim return cl->has_children ? tree__folded_sign(cl->unfolded) : ' '; 134aca7a94dSNamhyung Kim } 135aca7a94dSNamhyung Kim 1363698dab1SNamhyung Kim static void callchain_list__set_folding(struct callchain_list *cl, bool unfold) 137aca7a94dSNamhyung Kim { 1383698dab1SNamhyung Kim cl->unfolded = unfold ? cl->has_children : false; 139aca7a94dSNamhyung Kim } 140aca7a94dSNamhyung Kim 14105e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 142aca7a94dSNamhyung Kim { 143aca7a94dSNamhyung Kim int n = 0; 144aca7a94dSNamhyung Kim struct rb_node *nd; 145aca7a94dSNamhyung Kim 14605e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 147aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 148aca7a94dSNamhyung Kim struct callchain_list *chain; 149aca7a94dSNamhyung Kim char folded_sign = ' '; /* No children */ 150aca7a94dSNamhyung Kim 151aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 152aca7a94dSNamhyung Kim ++n; 153aca7a94dSNamhyung Kim /* We need this because we may not have children */ 154aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 155aca7a94dSNamhyung Kim if (folded_sign == '+') 156aca7a94dSNamhyung Kim break; 157aca7a94dSNamhyung Kim } 158aca7a94dSNamhyung Kim 159aca7a94dSNamhyung Kim if (folded_sign == '-') /* Have children and they're unfolded */ 160aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(child); 161aca7a94dSNamhyung Kim } 162aca7a94dSNamhyung Kim 163aca7a94dSNamhyung Kim return n; 164aca7a94dSNamhyung Kim } 165aca7a94dSNamhyung Kim 1664b3a3212SNamhyung Kim static int callchain_node__count_flat_rows(struct callchain_node *node) 1674b3a3212SNamhyung Kim { 1684b3a3212SNamhyung Kim struct callchain_list *chain; 1694b3a3212SNamhyung Kim char folded_sign = 0; 1704b3a3212SNamhyung Kim int n = 0; 1714b3a3212SNamhyung Kim 1724b3a3212SNamhyung Kim list_for_each_entry(chain, &node->parent_val, list) { 1734b3a3212SNamhyung Kim if (!folded_sign) { 1744b3a3212SNamhyung Kim /* only check first chain list entry */ 1754b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 1764b3a3212SNamhyung Kim if (folded_sign == '+') 1774b3a3212SNamhyung Kim return 1; 1784b3a3212SNamhyung Kim } 1794b3a3212SNamhyung Kim n++; 1804b3a3212SNamhyung Kim } 1814b3a3212SNamhyung Kim 1824b3a3212SNamhyung Kim list_for_each_entry(chain, &node->val, list) { 1834b3a3212SNamhyung Kim if (!folded_sign) { 1844b3a3212SNamhyung Kim /* node->parent_val list might be empty */ 1854b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 1864b3a3212SNamhyung Kim if (folded_sign == '+') 1874b3a3212SNamhyung Kim return 1; 1884b3a3212SNamhyung Kim } 1894b3a3212SNamhyung Kim n++; 1904b3a3212SNamhyung Kim } 1914b3a3212SNamhyung Kim 1924b3a3212SNamhyung Kim return n; 1934b3a3212SNamhyung Kim } 1944b3a3212SNamhyung Kim 1958c430a34SNamhyung Kim static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused) 1968c430a34SNamhyung Kim { 1978c430a34SNamhyung Kim return 1; 1988c430a34SNamhyung Kim } 1998c430a34SNamhyung Kim 200aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 201aca7a94dSNamhyung Kim { 202aca7a94dSNamhyung Kim struct callchain_list *chain; 203aca7a94dSNamhyung Kim bool unfolded = false; 204aca7a94dSNamhyung Kim int n = 0; 205aca7a94dSNamhyung Kim 2064b3a3212SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) 2074b3a3212SNamhyung Kim return callchain_node__count_flat_rows(node); 2088c430a34SNamhyung Kim else if (callchain_param.mode == CHAIN_FOLDED) 2098c430a34SNamhyung Kim return callchain_node__count_folded_rows(node); 2104b3a3212SNamhyung Kim 211aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 212aca7a94dSNamhyung Kim ++n; 2133698dab1SNamhyung Kim unfolded = chain->unfolded; 214aca7a94dSNamhyung Kim } 215aca7a94dSNamhyung Kim 216aca7a94dSNamhyung Kim if (unfolded) 217aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 218aca7a94dSNamhyung Kim 219aca7a94dSNamhyung Kim return n; 220aca7a94dSNamhyung Kim } 221aca7a94dSNamhyung Kim 222aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 223aca7a94dSNamhyung Kim { 224aca7a94dSNamhyung Kim struct rb_node *nd; 225aca7a94dSNamhyung Kim int n = 0; 226aca7a94dSNamhyung Kim 227aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 228aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 229aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 230aca7a94dSNamhyung Kim } 231aca7a94dSNamhyung Kim 232aca7a94dSNamhyung Kim return n; 233aca7a94dSNamhyung Kim } 234aca7a94dSNamhyung Kim 235f5b763feSNamhyung Kim static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he, 236f5b763feSNamhyung Kim bool include_children) 237f5b763feSNamhyung Kim { 238f5b763feSNamhyung Kim int count = 0; 239f5b763feSNamhyung Kim struct rb_node *node; 240f5b763feSNamhyung Kim struct hist_entry *child; 241f5b763feSNamhyung Kim 242f5b763feSNamhyung Kim if (he->leaf) 243f5b763feSNamhyung Kim return callchain__count_rows(&he->sorted_chain); 244f5b763feSNamhyung Kim 24579dded87SNamhyung Kim if (he->has_no_entry) 24679dded87SNamhyung Kim return 1; 24779dded87SNamhyung Kim 248f5b763feSNamhyung Kim node = rb_first(&he->hroot_out); 249f5b763feSNamhyung Kim while (node) { 250f5b763feSNamhyung Kim float percent; 251f5b763feSNamhyung Kim 252f5b763feSNamhyung Kim child = rb_entry(node, struct hist_entry, rb_node); 253f5b763feSNamhyung Kim percent = hist_entry__get_percent_limit(child); 254f5b763feSNamhyung Kim 255f5b763feSNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) { 256f5b763feSNamhyung Kim count++; 257f5b763feSNamhyung Kim 258f5b763feSNamhyung Kim if (include_children && child->unfolded) 259f5b763feSNamhyung Kim count += hierarchy_count_rows(hb, child, true); 260f5b763feSNamhyung Kim } 261f5b763feSNamhyung Kim 262f5b763feSNamhyung Kim node = rb_next(node); 263f5b763feSNamhyung Kim } 264f5b763feSNamhyung Kim return count; 265f5b763feSNamhyung Kim } 266f5b763feSNamhyung Kim 2673698dab1SNamhyung Kim static bool hist_entry__toggle_fold(struct hist_entry *he) 268aca7a94dSNamhyung Kim { 2693698dab1SNamhyung Kim if (!he) 270aca7a94dSNamhyung Kim return false; 271aca7a94dSNamhyung Kim 2723698dab1SNamhyung Kim if (!he->has_children) 273aca7a94dSNamhyung Kim return false; 274aca7a94dSNamhyung Kim 2753698dab1SNamhyung Kim he->unfolded = !he->unfolded; 2763698dab1SNamhyung Kim return true; 2773698dab1SNamhyung Kim } 2783698dab1SNamhyung Kim 2793698dab1SNamhyung Kim static bool callchain_list__toggle_fold(struct callchain_list *cl) 2803698dab1SNamhyung Kim { 2813698dab1SNamhyung Kim if (!cl) 2823698dab1SNamhyung Kim return false; 2833698dab1SNamhyung Kim 2843698dab1SNamhyung Kim if (!cl->has_children) 2853698dab1SNamhyung Kim return false; 2863698dab1SNamhyung Kim 2873698dab1SNamhyung Kim cl->unfolded = !cl->unfolded; 288aca7a94dSNamhyung Kim return true; 289aca7a94dSNamhyung Kim } 290aca7a94dSNamhyung Kim 29105e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 292aca7a94dSNamhyung Kim { 29305e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 294aca7a94dSNamhyung Kim 29505e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 296aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 297aca7a94dSNamhyung Kim struct callchain_list *chain; 298aca7a94dSNamhyung Kim bool first = true; 299aca7a94dSNamhyung Kim 300aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 301aca7a94dSNamhyung Kim if (first) { 302aca7a94dSNamhyung Kim first = false; 3033698dab1SNamhyung Kim chain->has_children = chain->list.next != &child->val || 304aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 305aca7a94dSNamhyung Kim } else 3063698dab1SNamhyung Kim chain->has_children = chain->list.next == &child->val && 307aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 308aca7a94dSNamhyung Kim } 309aca7a94dSNamhyung Kim 310aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 311aca7a94dSNamhyung Kim } 312aca7a94dSNamhyung Kim } 313aca7a94dSNamhyung Kim 314a7444af6SNamhyung Kim static void callchain_node__init_have_children(struct callchain_node *node, 315a7444af6SNamhyung Kim bool has_sibling) 316aca7a94dSNamhyung Kim { 317aca7a94dSNamhyung Kim struct callchain_list *chain; 318aca7a94dSNamhyung Kim 319a7444af6SNamhyung Kim chain = list_entry(node->val.next, struct callchain_list, list); 3203698dab1SNamhyung Kim chain->has_children = has_sibling; 321a7444af6SNamhyung Kim 32290989035SAndres Freund if (!list_empty(&node->val)) { 32382162b5aSNamhyung Kim chain = list_entry(node->val.prev, struct callchain_list, list); 3243698dab1SNamhyung Kim chain->has_children = !RB_EMPTY_ROOT(&node->rb_root); 32582162b5aSNamhyung Kim } 326aca7a94dSNamhyung Kim 32705e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 328aca7a94dSNamhyung Kim } 329aca7a94dSNamhyung Kim 33005e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 331aca7a94dSNamhyung Kim { 332a7444af6SNamhyung Kim struct rb_node *nd = rb_first(root); 333a7444af6SNamhyung Kim bool has_sibling = nd && rb_next(nd); 334aca7a94dSNamhyung Kim 33505e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 336aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 337a7444af6SNamhyung Kim callchain_node__init_have_children(node, has_sibling); 3388c430a34SNamhyung Kim if (callchain_param.mode == CHAIN_FLAT || 3398c430a34SNamhyung Kim callchain_param.mode == CHAIN_FOLDED) 3404b3a3212SNamhyung Kim callchain_node__make_parent_list(node); 341aca7a94dSNamhyung Kim } 342aca7a94dSNamhyung Kim } 343aca7a94dSNamhyung Kim 34405e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 345aca7a94dSNamhyung Kim { 346f5b763feSNamhyung Kim if (he->init_have_children) 347f5b763feSNamhyung Kim return; 348f5b763feSNamhyung Kim 349f5b763feSNamhyung Kim if (he->leaf) { 3503698dab1SNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 35105e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 352f5b763feSNamhyung Kim } else { 353f5b763feSNamhyung Kim he->has_children = !RB_EMPTY_ROOT(&he->hroot_out); 354aca7a94dSNamhyung Kim } 355f5b763feSNamhyung Kim 356f5b763feSNamhyung Kim he->init_have_children = true; 357aca7a94dSNamhyung Kim } 358aca7a94dSNamhyung Kim 35905e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 360aca7a94dSNamhyung Kim { 36105e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 3623698dab1SNamhyung Kim struct map_symbol *ms = browser->selection; 3633698dab1SNamhyung Kim struct callchain_list *cl = container_of(ms, struct callchain_list, ms); 3643698dab1SNamhyung Kim bool has_children; 365aca7a94dSNamhyung Kim 3664938cf0cSWang Nan if (!he || !ms) 3674938cf0cSWang Nan return false; 3684938cf0cSWang Nan 3693698dab1SNamhyung Kim if (ms == &he->ms) 3703698dab1SNamhyung Kim has_children = hist_entry__toggle_fold(he); 3713698dab1SNamhyung Kim else 3723698dab1SNamhyung Kim has_children = callchain_list__toggle_fold(cl); 3733698dab1SNamhyung Kim 3743698dab1SNamhyung Kim if (has_children) { 375f5b763feSNamhyung Kim int child_rows = 0; 376f5b763feSNamhyung Kim 377aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 378c3b78952SNamhyung Kim browser->b.nr_entries -= he->nr_rows; 379aca7a94dSNamhyung Kim 380f5b763feSNamhyung Kim if (he->leaf) 381f5b763feSNamhyung Kim browser->nr_callchain_rows -= he->nr_rows; 382f5b763feSNamhyung Kim else 383f5b763feSNamhyung Kim browser->nr_hierarchy_entries -= he->nr_rows; 384f5b763feSNamhyung Kim 385f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 386f5b763feSNamhyung Kim child_rows = hierarchy_count_rows(browser, he, true); 387f5b763feSNamhyung Kim 388f5b763feSNamhyung Kim if (he->unfolded) { 389f5b763feSNamhyung Kim if (he->leaf) 390aca7a94dSNamhyung Kim he->nr_rows = callchain__count_rows(&he->sorted_chain); 391aca7a94dSNamhyung Kim else 392f5b763feSNamhyung Kim he->nr_rows = hierarchy_count_rows(browser, he, false); 393f5b763feSNamhyung Kim 394f5b763feSNamhyung Kim /* account grand children */ 395f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 396f5b763feSNamhyung Kim browser->b.nr_entries += child_rows - he->nr_rows; 39779dded87SNamhyung Kim 39879dded87SNamhyung Kim if (!he->leaf && he->nr_rows == 0) { 39979dded87SNamhyung Kim he->has_no_entry = true; 40079dded87SNamhyung Kim he->nr_rows = 1; 40179dded87SNamhyung Kim } 402f5b763feSNamhyung Kim } else { 403f5b763feSNamhyung Kim if (symbol_conf.report_hierarchy) 404f5b763feSNamhyung Kim browser->b.nr_entries -= child_rows - he->nr_rows; 405f5b763feSNamhyung Kim 40679dded87SNamhyung Kim if (he->has_no_entry) 40779dded87SNamhyung Kim he->has_no_entry = false; 40879dded87SNamhyung Kim 409aca7a94dSNamhyung Kim he->nr_rows = 0; 410f5b763feSNamhyung Kim } 411c3b78952SNamhyung Kim 412c3b78952SNamhyung Kim browser->b.nr_entries += he->nr_rows; 413f5b763feSNamhyung Kim 414f5b763feSNamhyung Kim if (he->leaf) 415c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 416f5b763feSNamhyung Kim else 417f5b763feSNamhyung Kim browser->nr_hierarchy_entries += he->nr_rows; 418aca7a94dSNamhyung Kim 419aca7a94dSNamhyung Kim return true; 420aca7a94dSNamhyung Kim } 421aca7a94dSNamhyung Kim 422aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 423aca7a94dSNamhyung Kim return false; 424aca7a94dSNamhyung Kim } 425aca7a94dSNamhyung Kim 42605e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 427aca7a94dSNamhyung Kim { 428aca7a94dSNamhyung Kim int n = 0; 429aca7a94dSNamhyung Kim struct rb_node *nd; 430aca7a94dSNamhyung Kim 43105e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 432aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 433aca7a94dSNamhyung Kim struct callchain_list *chain; 434aca7a94dSNamhyung Kim bool has_children = false; 435aca7a94dSNamhyung Kim 436aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 437aca7a94dSNamhyung Kim ++n; 4383698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 4393698dab1SNamhyung Kim has_children = chain->has_children; 440aca7a94dSNamhyung Kim } 441aca7a94dSNamhyung Kim 442aca7a94dSNamhyung Kim if (has_children) 443aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 444aca7a94dSNamhyung Kim } 445aca7a94dSNamhyung Kim 446aca7a94dSNamhyung Kim return n; 447aca7a94dSNamhyung Kim } 448aca7a94dSNamhyung Kim 449aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 450aca7a94dSNamhyung Kim { 451aca7a94dSNamhyung Kim struct callchain_list *chain; 452aca7a94dSNamhyung Kim bool has_children = false; 453aca7a94dSNamhyung Kim int n = 0; 454aca7a94dSNamhyung Kim 455aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 456aca7a94dSNamhyung Kim ++n; 4573698dab1SNamhyung Kim callchain_list__set_folding(chain, unfold); 4583698dab1SNamhyung Kim has_children = chain->has_children; 459aca7a94dSNamhyung Kim } 460aca7a94dSNamhyung Kim 461aca7a94dSNamhyung Kim if (has_children) 462aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 463aca7a94dSNamhyung Kim 464aca7a94dSNamhyung Kim return n; 465aca7a94dSNamhyung Kim } 466aca7a94dSNamhyung Kim 467aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 468aca7a94dSNamhyung Kim { 469aca7a94dSNamhyung Kim struct rb_node *nd; 470aca7a94dSNamhyung Kim int n = 0; 471aca7a94dSNamhyung Kim 472aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 473aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 474aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 475aca7a94dSNamhyung Kim } 476aca7a94dSNamhyung Kim 477aca7a94dSNamhyung Kim return n; 478aca7a94dSNamhyung Kim } 479aca7a94dSNamhyung Kim 480492b1010SNamhyung Kim static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he, 481492b1010SNamhyung Kim bool unfold __maybe_unused) 482492b1010SNamhyung Kim { 483492b1010SNamhyung Kim float percent; 484492b1010SNamhyung Kim struct rb_node *nd; 485492b1010SNamhyung Kim struct hist_entry *child; 486492b1010SNamhyung Kim int n = 0; 487492b1010SNamhyung Kim 488492b1010SNamhyung Kim for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) { 489492b1010SNamhyung Kim child = rb_entry(nd, struct hist_entry, rb_node); 490492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(child); 491492b1010SNamhyung Kim if (!child->filtered && percent >= hb->min_pcnt) 492492b1010SNamhyung Kim n++; 493492b1010SNamhyung Kim } 494492b1010SNamhyung Kim 495492b1010SNamhyung Kim return n; 496492b1010SNamhyung Kim } 497492b1010SNamhyung Kim 498492b1010SNamhyung Kim static void hist_entry__set_folding(struct hist_entry *he, 499492b1010SNamhyung Kim struct hist_browser *hb, bool unfold) 500aca7a94dSNamhyung Kim { 50105e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 5023698dab1SNamhyung Kim he->unfolded = unfold ? he->has_children : false; 503aca7a94dSNamhyung Kim 5043698dab1SNamhyung Kim if (he->has_children) { 505492b1010SNamhyung Kim int n; 506492b1010SNamhyung Kim 507492b1010SNamhyung Kim if (he->leaf) 508492b1010SNamhyung Kim n = callchain__set_folding(&he->sorted_chain, unfold); 509492b1010SNamhyung Kim else 510492b1010SNamhyung Kim n = hierarchy_set_folding(hb, he, unfold); 511492b1010SNamhyung Kim 51205e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 513aca7a94dSNamhyung Kim } else 51405e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 515aca7a94dSNamhyung Kim } 516aca7a94dSNamhyung Kim 517c3b78952SNamhyung Kim static void 518c3b78952SNamhyung Kim __hist_browser__set_folding(struct hist_browser *browser, bool unfold) 519aca7a94dSNamhyung Kim { 520aca7a94dSNamhyung Kim struct rb_node *nd; 521492b1010SNamhyung Kim struct hist_entry *he; 522492b1010SNamhyung Kim double percent; 523aca7a94dSNamhyung Kim 524492b1010SNamhyung Kim nd = rb_first(&browser->hists->entries); 525492b1010SNamhyung Kim while (nd) { 526492b1010SNamhyung Kim he = rb_entry(nd, struct hist_entry, rb_node); 527492b1010SNamhyung Kim 528492b1010SNamhyung Kim /* set folding state even if it's currently folded */ 529492b1010SNamhyung Kim nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 530492b1010SNamhyung Kim 531492b1010SNamhyung Kim hist_entry__set_folding(he, browser, unfold); 532492b1010SNamhyung Kim 533492b1010SNamhyung Kim percent = hist_entry__get_percent_limit(he); 534492b1010SNamhyung Kim if (he->filtered || percent < browser->min_pcnt) 535492b1010SNamhyung Kim continue; 536492b1010SNamhyung Kim 537492b1010SNamhyung Kim if (!he->depth || unfold) 538492b1010SNamhyung Kim browser->nr_hierarchy_entries++; 539492b1010SNamhyung Kim if (he->leaf) 540c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 54179dded87SNamhyung Kim else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) { 54279dded87SNamhyung Kim browser->nr_hierarchy_entries++; 54379dded87SNamhyung Kim he->has_no_entry = true; 54479dded87SNamhyung Kim he->nr_rows = 1; 54579dded87SNamhyung Kim } else 54679dded87SNamhyung Kim he->has_no_entry = false; 547aca7a94dSNamhyung Kim } 548aca7a94dSNamhyung Kim } 549aca7a94dSNamhyung Kim 55005e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 551aca7a94dSNamhyung Kim { 552492b1010SNamhyung Kim browser->nr_hierarchy_entries = 0; 553c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 554c3b78952SNamhyung Kim __hist_browser__set_folding(browser, unfold); 555c3b78952SNamhyung Kim 556c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 557aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 55805e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 559aca7a94dSNamhyung Kim } 560aca7a94dSNamhyung Kim 561aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 562aca7a94dSNamhyung Kim { 563aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 564aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 565aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 566aca7a94dSNamhyung Kim " perf top -r 80\n\n" 567aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 568aca7a94dSNamhyung Kim } 569aca7a94dSNamhyung Kim 570*5b91a86fSJiri Olsa static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size) 571*5b91a86fSJiri Olsa { 572*5b91a86fSJiri Olsa return browser->title ? browser->title(browser, bf, size) : 0; 573*5b91a86fSJiri Olsa } 574*5b91a86fSJiri Olsa 575dabd2012SJiri Olsa int hist_browser__run(struct hist_browser *browser, const char *help) 576aca7a94dSNamhyung Kim { 577aca7a94dSNamhyung Kim int key; 578aca7a94dSNamhyung Kim char title[160]; 579c2a51ab8SNamhyung Kim struct hist_browser_timer *hbt = browser->hbt; 5809783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 581aca7a94dSNamhyung Kim 58205e8b080SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 583c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 584aca7a94dSNamhyung Kim 585*5b91a86fSJiri Olsa hist_browser__title(browser, title, sizeof(title)); 586aca7a94dSNamhyung Kim 587090cff3eSNamhyung Kim if (ui_browser__show(&browser->b, title, "%s", help) < 0) 588aca7a94dSNamhyung Kim return -1; 589aca7a94dSNamhyung Kim 590aca7a94dSNamhyung Kim while (1) { 59105e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 592aca7a94dSNamhyung Kim 593aca7a94dSNamhyung Kim switch (key) { 594fa5df943SNamhyung Kim case K_TIMER: { 595fa5df943SNamhyung Kim u64 nr_entries; 5969783adf7SNamhyung Kim hbt->timer(hbt->arg); 597fa5df943SNamhyung Kim 598c3b78952SNamhyung Kim if (hist_browser__has_filter(browser)) 599112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 600fa5df943SNamhyung Kim 601c3b78952SNamhyung Kim nr_entries = hist_browser__nr_entries(browser); 602fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 603aca7a94dSNamhyung Kim 60405e8b080SArnaldo Carvalho de Melo if (browser->hists->stats.nr_lost_warned != 60505e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]) { 60605e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 60705e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 60805e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 609aca7a94dSNamhyung Kim } 610aca7a94dSNamhyung Kim 611*5b91a86fSJiri Olsa hist_browser__title(browser, title, sizeof(title)); 61205e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 613aca7a94dSNamhyung Kim continue; 614fa5df943SNamhyung Kim } 615aca7a94dSNamhyung Kim case 'D': { /* Debug */ 616aca7a94dSNamhyung Kim static int seq; 61705e8b080SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, 618aca7a94dSNamhyung Kim struct hist_entry, rb_node); 619aca7a94dSNamhyung Kim ui_helpline__pop(); 62062c95ae3SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 62105e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 62205e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries, 62362c95ae3SArnaldo Carvalho de Melo browser->b.rows, 62405e8b080SArnaldo Carvalho de Melo browser->b.index, 62505e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 626aca7a94dSNamhyung Kim h->row_offset, h->nr_rows); 627aca7a94dSNamhyung Kim } 628aca7a94dSNamhyung Kim break; 629aca7a94dSNamhyung Kim case 'C': 630aca7a94dSNamhyung Kim /* Collapse the whole world. */ 63105e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 632aca7a94dSNamhyung Kim break; 633aca7a94dSNamhyung Kim case 'E': 634aca7a94dSNamhyung Kim /* Expand the whole world. */ 63505e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 636aca7a94dSNamhyung Kim break; 637025bf7eaSArnaldo Carvalho de Melo case 'H': 638025bf7eaSArnaldo Carvalho de Melo browser->show_headers = !browser->show_headers; 639025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(browser); 640025bf7eaSArnaldo Carvalho de Melo break; 641aca7a94dSNamhyung Kim case K_ENTER: 64205e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 643aca7a94dSNamhyung Kim break; 644aca7a94dSNamhyung Kim /* fall thru */ 645aca7a94dSNamhyung Kim default: 646aca7a94dSNamhyung Kim goto out; 647aca7a94dSNamhyung Kim } 648aca7a94dSNamhyung Kim } 649aca7a94dSNamhyung Kim out: 65005e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 651aca7a94dSNamhyung Kim return key; 652aca7a94dSNamhyung Kim } 653aca7a94dSNamhyung Kim 65439ee533fSNamhyung Kim struct callchain_print_arg { 65539ee533fSNamhyung Kim /* for hists browser */ 65639ee533fSNamhyung Kim off_t row_offset; 65739ee533fSNamhyung Kim bool is_current_entry; 65839ee533fSNamhyung Kim 65939ee533fSNamhyung Kim /* for file dump */ 66039ee533fSNamhyung Kim FILE *fp; 66139ee533fSNamhyung Kim int printed; 66239ee533fSNamhyung Kim }; 66339ee533fSNamhyung Kim 66439ee533fSNamhyung Kim typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, 66539ee533fSNamhyung Kim struct callchain_list *chain, 66639ee533fSNamhyung Kim const char *str, int offset, 66739ee533fSNamhyung Kim unsigned short row, 66839ee533fSNamhyung Kim struct callchain_print_arg *arg); 66939ee533fSNamhyung Kim 670f4536dddSNamhyung Kim static void hist_browser__show_callchain_entry(struct hist_browser *browser, 671f4536dddSNamhyung Kim struct callchain_list *chain, 67239ee533fSNamhyung Kim const char *str, int offset, 67339ee533fSNamhyung Kim unsigned short row, 67439ee533fSNamhyung Kim struct callchain_print_arg *arg) 675f4536dddSNamhyung Kim { 676f4536dddSNamhyung Kim int color, width; 67739ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 67870e97278SArnaldo Carvalho de Melo bool show_annotated = browser->show_dso && chain->ms.sym && symbol__annotation(chain->ms.sym)->src; 679f4536dddSNamhyung Kim 680f4536dddSNamhyung Kim color = HE_COLORSET_NORMAL; 681f4536dddSNamhyung Kim width = browser->b.width - (offset + 2); 682f4536dddSNamhyung Kim if (ui_browser__is_current_entry(&browser->b, row)) { 683f4536dddSNamhyung Kim browser->selection = &chain->ms; 684f4536dddSNamhyung Kim color = HE_COLORSET_SELECTED; 68539ee533fSNamhyung Kim arg->is_current_entry = true; 686f4536dddSNamhyung Kim } 687f4536dddSNamhyung Kim 688f4536dddSNamhyung Kim ui_browser__set_color(&browser->b, color); 689f4536dddSNamhyung Kim hist_browser__gotorc(browser, row, 0); 69026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, " ", offset); 691517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c", folded_sign); 69270e97278SArnaldo Carvalho de Melo ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); 69326270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, str, width); 694f4536dddSNamhyung Kim } 695f4536dddSNamhyung Kim 69639ee533fSNamhyung Kim static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, 69739ee533fSNamhyung Kim struct callchain_list *chain, 69839ee533fSNamhyung Kim const char *str, int offset, 69939ee533fSNamhyung Kim unsigned short row __maybe_unused, 70039ee533fSNamhyung Kim struct callchain_print_arg *arg) 70139ee533fSNamhyung Kim { 70239ee533fSNamhyung Kim char folded_sign = callchain_list__folded(chain); 70339ee533fSNamhyung Kim 70439ee533fSNamhyung Kim arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", 70539ee533fSNamhyung Kim folded_sign, str); 70639ee533fSNamhyung Kim } 70739ee533fSNamhyung Kim 70839ee533fSNamhyung Kim typedef bool (*check_output_full_fn)(struct hist_browser *browser, 70939ee533fSNamhyung Kim unsigned short row); 71039ee533fSNamhyung Kim 71139ee533fSNamhyung Kim static bool hist_browser__check_output_full(struct hist_browser *browser, 71239ee533fSNamhyung Kim unsigned short row) 71339ee533fSNamhyung Kim { 71439ee533fSNamhyung Kim return browser->b.rows == row; 71539ee533fSNamhyung Kim } 71639ee533fSNamhyung Kim 71739ee533fSNamhyung Kim static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, 71839ee533fSNamhyung Kim unsigned short row __maybe_unused) 71939ee533fSNamhyung Kim { 72039ee533fSNamhyung Kim return false; 72139ee533fSNamhyung Kim } 72239ee533fSNamhyung Kim 723aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 724aca7a94dSNamhyung Kim 72518bb8381SNamhyung Kim static int hist_browser__show_callchain_list(struct hist_browser *browser, 72618bb8381SNamhyung Kim struct callchain_node *node, 72718bb8381SNamhyung Kim struct callchain_list *chain, 72818bb8381SNamhyung Kim unsigned short row, u64 total, 72918bb8381SNamhyung Kim bool need_percent, int offset, 73018bb8381SNamhyung Kim print_callchain_entry_fn print, 73118bb8381SNamhyung Kim struct callchain_print_arg *arg) 73218bb8381SNamhyung Kim { 73318bb8381SNamhyung Kim char bf[1024], *alloc_str; 73418bb8381SNamhyung Kim const char *str; 73518bb8381SNamhyung Kim 73618bb8381SNamhyung Kim if (arg->row_offset != 0) { 73718bb8381SNamhyung Kim arg->row_offset--; 73818bb8381SNamhyung Kim return 0; 73918bb8381SNamhyung Kim } 74018bb8381SNamhyung Kim 74118bb8381SNamhyung Kim alloc_str = NULL; 74218bb8381SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 74318bb8381SNamhyung Kim browser->show_dso); 74418bb8381SNamhyung Kim 74518bb8381SNamhyung Kim if (need_percent) { 74618bb8381SNamhyung Kim char buf[64]; 74718bb8381SNamhyung Kim 74818bb8381SNamhyung Kim callchain_node__scnprintf_value(node, buf, sizeof(buf), 74918bb8381SNamhyung Kim total); 75018bb8381SNamhyung Kim 75118bb8381SNamhyung Kim if (asprintf(&alloc_str, "%s %s", buf, str) < 0) 75218bb8381SNamhyung Kim str = "Not enough memory!"; 75318bb8381SNamhyung Kim else 75418bb8381SNamhyung Kim str = alloc_str; 75518bb8381SNamhyung Kim } 75618bb8381SNamhyung Kim 75718bb8381SNamhyung Kim print(browser, chain, str, offset, row, arg); 75818bb8381SNamhyung Kim 75918bb8381SNamhyung Kim free(alloc_str); 76018bb8381SNamhyung Kim return 1; 76118bb8381SNamhyung Kim } 76218bb8381SNamhyung Kim 76359c624e2SNamhyung Kim static bool check_percent_display(struct rb_node *node, u64 parent_total) 76459c624e2SNamhyung Kim { 76559c624e2SNamhyung Kim struct callchain_node *child; 76659c624e2SNamhyung Kim 76759c624e2SNamhyung Kim if (node == NULL) 76859c624e2SNamhyung Kim return false; 76959c624e2SNamhyung Kim 77059c624e2SNamhyung Kim if (rb_next(node)) 77159c624e2SNamhyung Kim return true; 77259c624e2SNamhyung Kim 77359c624e2SNamhyung Kim child = rb_entry(node, struct callchain_node, rb_node); 77459c624e2SNamhyung Kim return callchain_cumul_hits(child) != parent_total; 77559c624e2SNamhyung Kim } 77659c624e2SNamhyung Kim 7774b3a3212SNamhyung Kim static int hist_browser__show_callchain_flat(struct hist_browser *browser, 7784b3a3212SNamhyung Kim struct rb_root *root, 7794b3a3212SNamhyung Kim unsigned short row, u64 total, 78059c624e2SNamhyung Kim u64 parent_total, 7814b3a3212SNamhyung Kim print_callchain_entry_fn print, 7824b3a3212SNamhyung Kim struct callchain_print_arg *arg, 7834b3a3212SNamhyung Kim check_output_full_fn is_output_full) 7844b3a3212SNamhyung Kim { 7854b3a3212SNamhyung Kim struct rb_node *node; 7864b3a3212SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 7874b3a3212SNamhyung Kim bool need_percent; 7884b3a3212SNamhyung Kim 7894b3a3212SNamhyung Kim node = rb_first(root); 79059c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 7914b3a3212SNamhyung Kim 7924b3a3212SNamhyung Kim while (node) { 7934b3a3212SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 7944b3a3212SNamhyung Kim struct rb_node *next = rb_next(node); 7954b3a3212SNamhyung Kim struct callchain_list *chain; 7964b3a3212SNamhyung Kim char folded_sign = ' '; 7974b3a3212SNamhyung Kim int first = true; 7984b3a3212SNamhyung Kim int extra_offset = 0; 7994b3a3212SNamhyung Kim 8004b3a3212SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 8014b3a3212SNamhyung Kim bool was_first = first; 8024b3a3212SNamhyung Kim 8034b3a3212SNamhyung Kim if (first) 8044b3a3212SNamhyung Kim first = false; 8054b3a3212SNamhyung Kim else if (need_percent) 8064b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 8074b3a3212SNamhyung Kim 8084b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 8094b3a3212SNamhyung Kim 8104b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 8114b3a3212SNamhyung Kim chain, row, total, 8124b3a3212SNamhyung Kim was_first && need_percent, 8134b3a3212SNamhyung Kim offset + extra_offset, 8144b3a3212SNamhyung Kim print, arg); 8154b3a3212SNamhyung Kim 8164b3a3212SNamhyung Kim if (is_output_full(browser, row)) 8174b3a3212SNamhyung Kim goto out; 8184b3a3212SNamhyung Kim 8194b3a3212SNamhyung Kim if (folded_sign == '+') 8204b3a3212SNamhyung Kim goto next; 8214b3a3212SNamhyung Kim } 8224b3a3212SNamhyung Kim 8234b3a3212SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 8244b3a3212SNamhyung Kim bool was_first = first; 8254b3a3212SNamhyung Kim 8264b3a3212SNamhyung Kim if (first) 8274b3a3212SNamhyung Kim first = false; 8284b3a3212SNamhyung Kim else if (need_percent) 8294b3a3212SNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 8304b3a3212SNamhyung Kim 8314b3a3212SNamhyung Kim folded_sign = callchain_list__folded(chain); 8324b3a3212SNamhyung Kim 8334b3a3212SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 8344b3a3212SNamhyung Kim chain, row, total, 8354b3a3212SNamhyung Kim was_first && need_percent, 8364b3a3212SNamhyung Kim offset + extra_offset, 8374b3a3212SNamhyung Kim print, arg); 8384b3a3212SNamhyung Kim 8394b3a3212SNamhyung Kim if (is_output_full(browser, row)) 8404b3a3212SNamhyung Kim goto out; 8414b3a3212SNamhyung Kim 8424b3a3212SNamhyung Kim if (folded_sign == '+') 8434b3a3212SNamhyung Kim break; 8444b3a3212SNamhyung Kim } 8454b3a3212SNamhyung Kim 8464b3a3212SNamhyung Kim next: 8474b3a3212SNamhyung Kim if (is_output_full(browser, row)) 8484b3a3212SNamhyung Kim break; 8494b3a3212SNamhyung Kim node = next; 8504b3a3212SNamhyung Kim } 8514b3a3212SNamhyung Kim out: 8524b3a3212SNamhyung Kim return row - first_row; 8534b3a3212SNamhyung Kim } 8544b3a3212SNamhyung Kim 8558c430a34SNamhyung Kim static char *hist_browser__folded_callchain_str(struct hist_browser *browser, 8568c430a34SNamhyung Kim struct callchain_list *chain, 8578c430a34SNamhyung Kim char *value_str, char *old_str) 8588c430a34SNamhyung Kim { 8598c430a34SNamhyung Kim char bf[1024]; 8608c430a34SNamhyung Kim const char *str; 8618c430a34SNamhyung Kim char *new; 8628c430a34SNamhyung Kim 8638c430a34SNamhyung Kim str = callchain_list__sym_name(chain, bf, sizeof(bf), 8648c430a34SNamhyung Kim browser->show_dso); 8658c430a34SNamhyung Kim if (old_str) { 8668c430a34SNamhyung Kim if (asprintf(&new, "%s%s%s", old_str, 8678c430a34SNamhyung Kim symbol_conf.field_sep ?: ";", str) < 0) 8688c430a34SNamhyung Kim new = NULL; 8698c430a34SNamhyung Kim } else { 8708c430a34SNamhyung Kim if (value_str) { 8718c430a34SNamhyung Kim if (asprintf(&new, "%s %s", value_str, str) < 0) 8728c430a34SNamhyung Kim new = NULL; 8738c430a34SNamhyung Kim } else { 8748c430a34SNamhyung Kim if (asprintf(&new, "%s", str) < 0) 8758c430a34SNamhyung Kim new = NULL; 8768c430a34SNamhyung Kim } 8778c430a34SNamhyung Kim } 8788c430a34SNamhyung Kim return new; 8798c430a34SNamhyung Kim } 8808c430a34SNamhyung Kim 8818c430a34SNamhyung Kim static int hist_browser__show_callchain_folded(struct hist_browser *browser, 8828c430a34SNamhyung Kim struct rb_root *root, 8838c430a34SNamhyung Kim unsigned short row, u64 total, 88459c624e2SNamhyung Kim u64 parent_total, 8858c430a34SNamhyung Kim print_callchain_entry_fn print, 8868c430a34SNamhyung Kim struct callchain_print_arg *arg, 8878c430a34SNamhyung Kim check_output_full_fn is_output_full) 8888c430a34SNamhyung Kim { 8898c430a34SNamhyung Kim struct rb_node *node; 8908c430a34SNamhyung Kim int first_row = row, offset = LEVEL_OFFSET_STEP; 8918c430a34SNamhyung Kim bool need_percent; 8928c430a34SNamhyung Kim 8938c430a34SNamhyung Kim node = rb_first(root); 89459c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 8958c430a34SNamhyung Kim 8968c430a34SNamhyung Kim while (node) { 8978c430a34SNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 8988c430a34SNamhyung Kim struct rb_node *next = rb_next(node); 8998c430a34SNamhyung Kim struct callchain_list *chain, *first_chain = NULL; 9008c430a34SNamhyung Kim int first = true; 9018c430a34SNamhyung Kim char *value_str = NULL, *value_str_alloc = NULL; 9028c430a34SNamhyung Kim char *chain_str = NULL, *chain_str_alloc = NULL; 9038c430a34SNamhyung Kim 9048c430a34SNamhyung Kim if (arg->row_offset != 0) { 9058c430a34SNamhyung Kim arg->row_offset--; 9068c430a34SNamhyung Kim goto next; 9078c430a34SNamhyung Kim } 9088c430a34SNamhyung Kim 9098c430a34SNamhyung Kim if (need_percent) { 9108c430a34SNamhyung Kim char buf[64]; 9118c430a34SNamhyung Kim 9128c430a34SNamhyung Kim callchain_node__scnprintf_value(child, buf, sizeof(buf), total); 9138c430a34SNamhyung Kim if (asprintf(&value_str, "%s", buf) < 0) { 9148c430a34SNamhyung Kim value_str = (char *)"<...>"; 9158c430a34SNamhyung Kim goto do_print; 9168c430a34SNamhyung Kim } 9178c430a34SNamhyung Kim value_str_alloc = value_str; 9188c430a34SNamhyung Kim } 9198c430a34SNamhyung Kim 9208c430a34SNamhyung Kim list_for_each_entry(chain, &child->parent_val, list) { 9218c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 9228c430a34SNamhyung Kim chain, value_str, chain_str); 9238c430a34SNamhyung Kim if (first) { 9248c430a34SNamhyung Kim first = false; 9258c430a34SNamhyung Kim first_chain = chain; 9268c430a34SNamhyung Kim } 9278c430a34SNamhyung Kim 9288c430a34SNamhyung Kim if (chain_str == NULL) { 9298c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 9308c430a34SNamhyung Kim goto do_print; 9318c430a34SNamhyung Kim } 9328c430a34SNamhyung Kim 9338c430a34SNamhyung Kim chain_str_alloc = chain_str; 9348c430a34SNamhyung Kim } 9358c430a34SNamhyung Kim 9368c430a34SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 9378c430a34SNamhyung Kim chain_str = hist_browser__folded_callchain_str(browser, 9388c430a34SNamhyung Kim chain, value_str, chain_str); 9398c430a34SNamhyung Kim if (first) { 9408c430a34SNamhyung Kim first = false; 9418c430a34SNamhyung Kim first_chain = chain; 9428c430a34SNamhyung Kim } 9438c430a34SNamhyung Kim 9448c430a34SNamhyung Kim if (chain_str == NULL) { 9458c430a34SNamhyung Kim chain_str = (char *)"Not enough memory!"; 9468c430a34SNamhyung Kim goto do_print; 9478c430a34SNamhyung Kim } 9488c430a34SNamhyung Kim 9498c430a34SNamhyung Kim chain_str_alloc = chain_str; 9508c430a34SNamhyung Kim } 9518c430a34SNamhyung Kim 9528c430a34SNamhyung Kim do_print: 9538c430a34SNamhyung Kim print(browser, first_chain, chain_str, offset, row++, arg); 9548c430a34SNamhyung Kim free(value_str_alloc); 9558c430a34SNamhyung Kim free(chain_str_alloc); 9568c430a34SNamhyung Kim 9578c430a34SNamhyung Kim next: 9588c430a34SNamhyung Kim if (is_output_full(browser, row)) 9598c430a34SNamhyung Kim break; 9608c430a34SNamhyung Kim node = next; 9618c430a34SNamhyung Kim } 9628c430a34SNamhyung Kim 9638c430a34SNamhyung Kim return row - first_row; 9648c430a34SNamhyung Kim } 9658c430a34SNamhyung Kim 9660c841c6cSNamhyung Kim static int hist_browser__show_callchain_graph(struct hist_browser *browser, 967c09a7e75SNamhyung Kim struct rb_root *root, int level, 96839ee533fSNamhyung Kim unsigned short row, u64 total, 9695eca104eSNamhyung Kim u64 parent_total, 97039ee533fSNamhyung Kim print_callchain_entry_fn print, 97139ee533fSNamhyung Kim struct callchain_print_arg *arg, 97239ee533fSNamhyung Kim check_output_full_fn is_output_full) 973aca7a94dSNamhyung Kim { 974aca7a94dSNamhyung Kim struct rb_node *node; 975f4536dddSNamhyung Kim int first_row = row, offset = level * LEVEL_OFFSET_STEP; 9764087d11cSNamhyung Kim bool need_percent; 9775eca104eSNamhyung Kim u64 percent_total = total; 9785eca104eSNamhyung Kim 9795eca104eSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 9805eca104eSNamhyung Kim percent_total = parent_total; 981aca7a94dSNamhyung Kim 982c09a7e75SNamhyung Kim node = rb_first(root); 98359c624e2SNamhyung Kim need_percent = check_percent_display(node, parent_total); 9844087d11cSNamhyung Kim 985aca7a94dSNamhyung Kim while (node) { 986aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 987aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 988aca7a94dSNamhyung Kim struct callchain_list *chain; 989aca7a94dSNamhyung Kim char folded_sign = ' '; 990aca7a94dSNamhyung Kim int first = true; 991aca7a94dSNamhyung Kim int extra_offset = 0; 992aca7a94dSNamhyung Kim 993aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 994aca7a94dSNamhyung Kim bool was_first = first; 995aca7a94dSNamhyung Kim 996aca7a94dSNamhyung Kim if (first) 997aca7a94dSNamhyung Kim first = false; 9984087d11cSNamhyung Kim else if (need_percent) 999aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 1000aca7a94dSNamhyung Kim 1001aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 1002aca7a94dSNamhyung Kim 100318bb8381SNamhyung Kim row += hist_browser__show_callchain_list(browser, child, 10045eca104eSNamhyung Kim chain, row, percent_total, 100518bb8381SNamhyung Kim was_first && need_percent, 100618bb8381SNamhyung Kim offset + extra_offset, 100718bb8381SNamhyung Kim print, arg); 1008c09a7e75SNamhyung Kim 100918bb8381SNamhyung Kim if (is_output_full(browser, row)) 1010aca7a94dSNamhyung Kim goto out; 101118bb8381SNamhyung Kim 1012aca7a94dSNamhyung Kim if (folded_sign == '+') 1013aca7a94dSNamhyung Kim break; 1014aca7a94dSNamhyung Kim } 1015aca7a94dSNamhyung Kim 1016aca7a94dSNamhyung Kim if (folded_sign == '-') { 1017aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 1018c09a7e75SNamhyung Kim 10190c841c6cSNamhyung Kim row += hist_browser__show_callchain_graph(browser, &child->rb_root, 10205eca104eSNamhyung Kim new_level, row, total, 10215eca104eSNamhyung Kim child->children_hit, 102239ee533fSNamhyung Kim print, arg, is_output_full); 1023aca7a94dSNamhyung Kim } 102439ee533fSNamhyung Kim if (is_output_full(browser, row)) 1025c09a7e75SNamhyung Kim break; 1026aca7a94dSNamhyung Kim node = next; 1027aca7a94dSNamhyung Kim } 1028aca7a94dSNamhyung Kim out: 1029aca7a94dSNamhyung Kim return row - first_row; 1030aca7a94dSNamhyung Kim } 1031aca7a94dSNamhyung Kim 10320c841c6cSNamhyung Kim static int hist_browser__show_callchain(struct hist_browser *browser, 10330c841c6cSNamhyung Kim struct hist_entry *entry, int level, 10340c841c6cSNamhyung Kim unsigned short row, 10350c841c6cSNamhyung Kim print_callchain_entry_fn print, 10360c841c6cSNamhyung Kim struct callchain_print_arg *arg, 10370c841c6cSNamhyung Kim check_output_full_fn is_output_full) 10380c841c6cSNamhyung Kim { 10390c841c6cSNamhyung Kim u64 total = hists__total_period(entry->hists); 10405eca104eSNamhyung Kim u64 parent_total; 10410c841c6cSNamhyung Kim int printed; 10420c841c6cSNamhyung Kim 10430c841c6cSNamhyung Kim if (symbol_conf.cumulate_callchain) 10445eca104eSNamhyung Kim parent_total = entry->stat_acc->period; 10450c841c6cSNamhyung Kim else 10465eca104eSNamhyung Kim parent_total = entry->stat.period; 10470c841c6cSNamhyung Kim 10480c841c6cSNamhyung Kim if (callchain_param.mode == CHAIN_FLAT) { 10490c841c6cSNamhyung Kim printed = hist_browser__show_callchain_flat(browser, 10505eca104eSNamhyung Kim &entry->sorted_chain, row, 10515eca104eSNamhyung Kim total, parent_total, print, arg, 10525eca104eSNamhyung Kim is_output_full); 10530c841c6cSNamhyung Kim } else if (callchain_param.mode == CHAIN_FOLDED) { 10540c841c6cSNamhyung Kim printed = hist_browser__show_callchain_folded(browser, 10555eca104eSNamhyung Kim &entry->sorted_chain, row, 10565eca104eSNamhyung Kim total, parent_total, print, arg, 10575eca104eSNamhyung Kim is_output_full); 10580c841c6cSNamhyung Kim } else { 10590c841c6cSNamhyung Kim printed = hist_browser__show_callchain_graph(browser, 10605eca104eSNamhyung Kim &entry->sorted_chain, level, row, 10615eca104eSNamhyung Kim total, parent_total, print, arg, 10625eca104eSNamhyung Kim is_output_full); 10630c841c6cSNamhyung Kim } 10640c841c6cSNamhyung Kim 10650c841c6cSNamhyung Kim if (arg->is_current_entry) 10660c841c6cSNamhyung Kim browser->he_selection = entry; 10670c841c6cSNamhyung Kim 10680c841c6cSNamhyung Kim return printed; 10690c841c6cSNamhyung Kim } 10700c841c6cSNamhyung Kim 107189701460SNamhyung Kim struct hpp_arg { 107289701460SNamhyung Kim struct ui_browser *b; 107389701460SNamhyung Kim char folded_sign; 107489701460SNamhyung Kim bool current_entry; 107589701460SNamhyung Kim }; 107689701460SNamhyung Kim 10772f6d9009SNamhyung Kim static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 10782f6d9009SNamhyung Kim { 10792f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 1080d675107cSNamhyung Kim int ret, len; 10812f6d9009SNamhyung Kim va_list args; 10822f6d9009SNamhyung Kim double percent; 10832f6d9009SNamhyung Kim 10842f6d9009SNamhyung Kim va_start(args, fmt); 1085d675107cSNamhyung Kim len = va_arg(args, int); 10862f6d9009SNamhyung Kim percent = va_arg(args, double); 10872f6d9009SNamhyung Kim va_end(args); 10885aed9d24SNamhyung Kim 108989701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 10905aed9d24SNamhyung Kim 1091d675107cSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); 1092517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); 109389701460SNamhyung Kim 10942f6d9009SNamhyung Kim advance_hpp(hpp, ret); 10955aed9d24SNamhyung Kim return ret; 1096f5951d56SNamhyung Kim } 1097f5951d56SNamhyung Kim 1098fb821c9eSNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field) \ 10995aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 11005aed9d24SNamhyung Kim { \ 11015aed9d24SNamhyung Kim return he->stat._field; \ 11025aed9d24SNamhyung Kim } \ 11035aed9d24SNamhyung Kim \ 11042c5d4b4aSJiri Olsa static int \ 11055b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 11062c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 11075aed9d24SNamhyung Kim struct hist_entry *he) \ 11085aed9d24SNamhyung Kim { \ 11095b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \ 11102f6d9009SNamhyung Kim __hpp__slsmg_color_printf, true); \ 11115aed9d24SNamhyung Kim } 1112f5951d56SNamhyung Kim 11130434ddd2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 11140434ddd2SNamhyung Kim static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ 11150434ddd2SNamhyung Kim { \ 11160434ddd2SNamhyung Kim return he->stat_acc->_field; \ 11170434ddd2SNamhyung Kim } \ 11180434ddd2SNamhyung Kim \ 11190434ddd2SNamhyung Kim static int \ 11205b591669SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ 11210434ddd2SNamhyung Kim struct perf_hpp *hpp, \ 11220434ddd2SNamhyung Kim struct hist_entry *he) \ 11230434ddd2SNamhyung Kim { \ 11240434ddd2SNamhyung Kim if (!symbol_conf.cumulate_callchain) { \ 1125517dfdb3SArnaldo Carvalho de Melo struct hpp_arg *arg = hpp->ptr; \ 11265b591669SNamhyung Kim int len = fmt->user_len ?: fmt->len; \ 1127d675107cSNamhyung Kim int ret = scnprintf(hpp->buf, hpp->size, \ 11285b591669SNamhyung Kim "%*s", len, "N/A"); \ 1129517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(arg->b, "%s", hpp->buf); \ 11300434ddd2SNamhyung Kim \ 11310434ddd2SNamhyung Kim return ret; \ 11320434ddd2SNamhyung Kim } \ 11335b591669SNamhyung Kim return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \ 11345b591669SNamhyung Kim " %*.2f%%", __hpp__slsmg_color_printf, true); \ 11350434ddd2SNamhyung Kim } 11360434ddd2SNamhyung Kim 1137fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period) 1138fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 1139fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us) 1140fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 1141fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 11420434ddd2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period) 11435aed9d24SNamhyung Kim 11445aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 11450434ddd2SNamhyung Kim #undef __HPP_COLOR_ACC_PERCENT_FN 1146f5951d56SNamhyung Kim 1147f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 1148f5951d56SNamhyung Kim { 1149f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 1150f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 1151f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 1152f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 1153f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 1154f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 1155f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 1156f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 1157f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 1158f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 11590434ddd2SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = 11600434ddd2SNamhyung Kim hist_browser__hpp_color_overhead_acc; 1161f5951d56SNamhyung Kim } 1162f5951d56SNamhyung Kim 116305e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 1164aca7a94dSNamhyung Kim struct hist_entry *entry, 1165aca7a94dSNamhyung Kim unsigned short row) 1166aca7a94dSNamhyung Kim { 11671240005eSJiri Olsa int printed = 0; 116867d25916SNamhyung Kim int width = browser->b.width; 1169aca7a94dSNamhyung Kim char folded_sign = ' '; 117005e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1171aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 117263a1a3d8SNamhyung Kim bool first = true; 11731240005eSJiri Olsa struct perf_hpp_fmt *fmt; 1174aca7a94dSNamhyung Kim 1175aca7a94dSNamhyung Kim if (current_entry) { 117605e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 117705e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 1178aca7a94dSNamhyung Kim } 1179aca7a94dSNamhyung Kim 1180aca7a94dSNamhyung Kim if (symbol_conf.use_callchain) { 1181aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 1182aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 1183aca7a94dSNamhyung Kim } 1184aca7a94dSNamhyung Kim 1185aca7a94dSNamhyung Kim if (row_offset == 0) { 118689701460SNamhyung Kim struct hpp_arg arg = { 118789701460SNamhyung Kim .b = &browser->b, 118889701460SNamhyung Kim .folded_sign = folded_sign, 118989701460SNamhyung Kim .current_entry = current_entry, 119089701460SNamhyung Kim }; 1191c6c3c02dSArnaldo Carvalho de Melo int column = 0; 1192f5951d56SNamhyung Kim 1193ca3ff33bSArnaldo Carvalho de Melo hist_browser__gotorc(browser, row, 0); 1194f5951d56SNamhyung Kim 1195f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 119689fee709SArnaldo Carvalho de Melo char s[2048]; 119789fee709SArnaldo Carvalho de Melo struct perf_hpp hpp = { 119889fee709SArnaldo Carvalho de Melo .buf = s, 119989fee709SArnaldo Carvalho de Melo .size = sizeof(s), 120089fee709SArnaldo Carvalho de Melo .ptr = &arg, 120189fee709SArnaldo Carvalho de Melo }; 120289fee709SArnaldo Carvalho de Melo 1203361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1204361459f1SNamhyung Kim column++ < browser->b.horiz_scroll) 1205e67d49a7SNamhyung Kim continue; 1206e67d49a7SNamhyung Kim 1207fb821c9eSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1208fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1209fb821c9eSNamhyung Kim HE_COLORSET_SELECTED); 1210fb821c9eSNamhyung Kim } else { 1211fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 1212fb821c9eSNamhyung Kim HE_COLORSET_NORMAL); 1213fb821c9eSNamhyung Kim } 1214fb821c9eSNamhyung Kim 1215fb821c9eSNamhyung Kim if (first) { 1216fb821c9eSNamhyung Kim if (symbol_conf.use_callchain) { 1217517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%c ", folded_sign); 1218f5951d56SNamhyung Kim width -= 2; 1219f5951d56SNamhyung Kim } 122063a1a3d8SNamhyung Kim first = false; 1221fb821c9eSNamhyung Kim } else { 1222517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, " "); 1223fb821c9eSNamhyung Kim width -= 2; 1224fb821c9eSNamhyung Kim } 1225f5951d56SNamhyung Kim 12261240005eSJiri Olsa if (fmt->color) { 122789fee709SArnaldo Carvalho de Melo int ret = fmt->color(fmt, &hpp, entry); 122889fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 122989fee709SArnaldo Carvalho de Melo /* 123089fee709SArnaldo Carvalho de Melo * fmt->color() already used ui_browser to 123189fee709SArnaldo Carvalho de Melo * print the non alignment bits, skip it (+ret): 123289fee709SArnaldo Carvalho de Melo */ 123389fee709SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s + ret); 1234f5951d56SNamhyung Kim } else { 123589fee709SArnaldo Carvalho de Melo hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry)); 1236517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(&browser->b, "%s", s); 1237f5951d56SNamhyung Kim } 123889fee709SArnaldo Carvalho de Melo width -= hpp.buf - s; 1239f5951d56SNamhyung Kim } 1240aca7a94dSNamhyung Kim 1241aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 124205e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 1243aca7a94dSNamhyung Kim width += 1; 1244aca7a94dSNamhyung Kim 124526270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, "", width); 124626d8b338SNamhyung Kim 1247aca7a94dSNamhyung Kim ++row; 1248aca7a94dSNamhyung Kim ++printed; 1249aca7a94dSNamhyung Kim } else 1250aca7a94dSNamhyung Kim --row_offset; 1251aca7a94dSNamhyung Kim 125262c95ae3SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.rows) { 125339ee533fSNamhyung Kim struct callchain_print_arg arg = { 125439ee533fSNamhyung Kim .row_offset = row_offset, 125539ee533fSNamhyung Kim .is_current_entry = current_entry, 125639ee533fSNamhyung Kim }; 1257c09a7e75SNamhyung Kim 12580c841c6cSNamhyung Kim printed += hist_browser__show_callchain(browser, entry, 1, row, 12594b3a3212SNamhyung Kim hist_browser__show_callchain_entry, &arg, 12604b3a3212SNamhyung Kim hist_browser__check_output_full); 1261aca7a94dSNamhyung Kim } 1262aca7a94dSNamhyung Kim 1263aca7a94dSNamhyung Kim return printed; 1264aca7a94dSNamhyung Kim } 1265aca7a94dSNamhyung Kim 1266d0506edbSNamhyung Kim static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, 1267d0506edbSNamhyung Kim struct hist_entry *entry, 1268d0506edbSNamhyung Kim unsigned short row, 12692dbbe9f2SNamhyung Kim int level) 1270d0506edbSNamhyung Kim { 1271d0506edbSNamhyung Kim int printed = 0; 1272d0506edbSNamhyung Kim int width = browser->b.width; 1273d0506edbSNamhyung Kim char folded_sign = ' '; 1274d0506edbSNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 1275d0506edbSNamhyung Kim off_t row_offset = entry->row_offset; 1276d0506edbSNamhyung Kim bool first = true; 1277d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 1278a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1279d0506edbSNamhyung Kim struct hpp_arg arg = { 1280d0506edbSNamhyung Kim .b = &browser->b, 1281d0506edbSNamhyung Kim .current_entry = current_entry, 1282d0506edbSNamhyung Kim }; 1283d0506edbSNamhyung Kim int column = 0; 12842dbbe9f2SNamhyung Kim int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 1285d0506edbSNamhyung Kim 1286d0506edbSNamhyung Kim if (current_entry) { 1287d0506edbSNamhyung Kim browser->he_selection = entry; 1288d0506edbSNamhyung Kim browser->selection = &entry->ms; 1289d0506edbSNamhyung Kim } 1290d0506edbSNamhyung Kim 1291d0506edbSNamhyung Kim hist_entry__init_have_children(entry); 1292d0506edbSNamhyung Kim folded_sign = hist_entry__folded(entry); 1293d0506edbSNamhyung Kim arg.folded_sign = folded_sign; 1294d0506edbSNamhyung Kim 1295d0506edbSNamhyung Kim if (entry->leaf && row_offset) { 1296d0506edbSNamhyung Kim row_offset--; 1297d0506edbSNamhyung Kim goto show_callchain; 1298d0506edbSNamhyung Kim } 1299d0506edbSNamhyung Kim 1300d0506edbSNamhyung Kim hist_browser__gotorc(browser, row, 0); 1301d0506edbSNamhyung Kim 1302d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) 1303d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 1304d0506edbSNamhyung Kim else 1305d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 1306d0506edbSNamhyung Kim 1307d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 1308d0506edbSNamhyung Kim width -= level * HIERARCHY_INDENT; 1309d0506edbSNamhyung Kim 1310a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1311a61a22f6SNamhyung Kim fmt_node = list_first_entry(&entry->hists->hpp_formats, 1312a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1313a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1314d0506edbSNamhyung Kim char s[2048]; 1315d0506edbSNamhyung Kim struct perf_hpp hpp = { 1316d0506edbSNamhyung Kim .buf = s, 1317d0506edbSNamhyung Kim .size = sizeof(s), 1318d0506edbSNamhyung Kim .ptr = &arg, 1319d0506edbSNamhyung Kim }; 1320d0506edbSNamhyung Kim 1321d0506edbSNamhyung Kim if (perf_hpp__should_skip(fmt, entry->hists) || 1322d0506edbSNamhyung Kim column++ < browser->b.horiz_scroll) 1323d0506edbSNamhyung Kim continue; 1324d0506edbSNamhyung Kim 1325d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1326d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1327d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1328d0506edbSNamhyung Kim } else { 1329d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1330d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1331d0506edbSNamhyung Kim } 1332d0506edbSNamhyung Kim 1333d0506edbSNamhyung Kim if (first) { 1334d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%c", folded_sign); 1335d0506edbSNamhyung Kim width--; 1336d0506edbSNamhyung Kim first = false; 1337d0506edbSNamhyung Kim } else { 1338d0506edbSNamhyung Kim ui_browser__printf(&browser->b, " "); 1339d0506edbSNamhyung Kim width -= 2; 1340d0506edbSNamhyung Kim } 1341d0506edbSNamhyung Kim 1342d0506edbSNamhyung Kim if (fmt->color) { 1343d0506edbSNamhyung Kim int ret = fmt->color(fmt, &hpp, entry); 1344d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1345d0506edbSNamhyung Kim /* 1346d0506edbSNamhyung Kim * fmt->color() already used ui_browser to 1347d0506edbSNamhyung Kim * print the non alignment bits, skip it (+ret): 1348d0506edbSNamhyung Kim */ 1349d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s + ret); 1350d0506edbSNamhyung Kim } else { 1351d0506edbSNamhyung Kim int ret = fmt->entry(fmt, &hpp, entry); 1352d0506edbSNamhyung Kim hist_entry__snprintf_alignment(entry, &hpp, fmt, ret); 1353d0506edbSNamhyung Kim ui_browser__printf(&browser->b, "%s", s); 1354d0506edbSNamhyung Kim } 1355d0506edbSNamhyung Kim width -= hpp.buf - s; 1356d0506edbSNamhyung Kim } 1357d0506edbSNamhyung Kim 1358d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", hierarchy_indent); 1359d0506edbSNamhyung Kim width -= hierarchy_indent; 1360d0506edbSNamhyung Kim 1361d0506edbSNamhyung Kim if (column >= browser->b.horiz_scroll) { 1362d0506edbSNamhyung Kim char s[2048]; 1363d0506edbSNamhyung Kim struct perf_hpp hpp = { 1364d0506edbSNamhyung Kim .buf = s, 1365d0506edbSNamhyung Kim .size = sizeof(s), 1366d0506edbSNamhyung Kim .ptr = &arg, 1367d0506edbSNamhyung Kim }; 1368d0506edbSNamhyung Kim 1369d0506edbSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 1370d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1371d0506edbSNamhyung Kim HE_COLORSET_SELECTED); 1372d0506edbSNamhyung Kim } else { 1373d0506edbSNamhyung Kim ui_browser__set_color(&browser->b, 1374d0506edbSNamhyung Kim HE_COLORSET_NORMAL); 1375d0506edbSNamhyung Kim } 1376d0506edbSNamhyung Kim 13771b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(entry->hpp_list, fmt) { 1378d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", 2); 1379d0506edbSNamhyung Kim width -= 2; 1380d0506edbSNamhyung Kim 1381d0506edbSNamhyung Kim /* 1382d0506edbSNamhyung Kim * No need to call hist_entry__snprintf_alignment() 1383d0506edbSNamhyung Kim * since this fmt is always the last column in the 1384d0506edbSNamhyung Kim * hierarchy mode. 1385d0506edbSNamhyung Kim */ 1386d0506edbSNamhyung Kim if (fmt->color) { 1387d0506edbSNamhyung Kim width -= fmt->color(fmt, &hpp, entry); 1388d0506edbSNamhyung Kim } else { 1389cb1fab91SNamhyung Kim int i = 0; 1390cb1fab91SNamhyung Kim 1391d0506edbSNamhyung Kim width -= fmt->entry(fmt, &hpp, entry); 1392cb1fab91SNamhyung Kim ui_browser__printf(&browser->b, "%s", ltrim(s)); 1393cb1fab91SNamhyung Kim 1394cb1fab91SNamhyung Kim while (isspace(s[i++])) 1395cb1fab91SNamhyung Kim width++; 1396d0506edbSNamhyung Kim } 1397d0506edbSNamhyung Kim } 13981b2dbbf4SNamhyung Kim } 1399d0506edbSNamhyung Kim 1400d0506edbSNamhyung Kim /* The scroll bar isn't being used */ 1401d0506edbSNamhyung Kim if (!browser->b.navkeypressed) 1402d0506edbSNamhyung Kim width += 1; 1403d0506edbSNamhyung Kim 1404d0506edbSNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 1405d0506edbSNamhyung Kim 1406d0506edbSNamhyung Kim ++row; 1407d0506edbSNamhyung Kim ++printed; 1408d0506edbSNamhyung Kim 1409d0506edbSNamhyung Kim show_callchain: 1410d0506edbSNamhyung Kim if (entry->leaf && folded_sign == '-' && row != browser->b.rows) { 1411d0506edbSNamhyung Kim struct callchain_print_arg carg = { 1412d0506edbSNamhyung Kim .row_offset = row_offset, 1413d0506edbSNamhyung Kim }; 1414d0506edbSNamhyung Kim 1415d0506edbSNamhyung Kim printed += hist_browser__show_callchain(browser, entry, 1416d0506edbSNamhyung Kim level + 1, row, 1417d0506edbSNamhyung Kim hist_browser__show_callchain_entry, &carg, 1418d0506edbSNamhyung Kim hist_browser__check_output_full); 1419d0506edbSNamhyung Kim } 1420d0506edbSNamhyung Kim 1421d0506edbSNamhyung Kim return printed; 1422d0506edbSNamhyung Kim } 1423d0506edbSNamhyung Kim 142479dded87SNamhyung Kim static int hist_browser__show_no_entry(struct hist_browser *browser, 14252dbbe9f2SNamhyung Kim unsigned short row, int level) 142679dded87SNamhyung Kim { 142779dded87SNamhyung Kim int width = browser->b.width; 142879dded87SNamhyung Kim bool current_entry = ui_browser__is_current_entry(&browser->b, row); 142979dded87SNamhyung Kim bool first = true; 143079dded87SNamhyung Kim int column = 0; 143179dded87SNamhyung Kim int ret; 143279dded87SNamhyung Kim struct perf_hpp_fmt *fmt; 1433a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 14342dbbe9f2SNamhyung Kim int indent = browser->hists->nr_hpp_node - 2; 143579dded87SNamhyung Kim 143679dded87SNamhyung Kim if (current_entry) { 143779dded87SNamhyung Kim browser->he_selection = NULL; 143879dded87SNamhyung Kim browser->selection = NULL; 143979dded87SNamhyung Kim } 144079dded87SNamhyung Kim 144179dded87SNamhyung Kim hist_browser__gotorc(browser, row, 0); 144279dded87SNamhyung Kim 144379dded87SNamhyung Kim if (current_entry && browser->b.navkeypressed) 144479dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); 144579dded87SNamhyung Kim else 144679dded87SNamhyung Kim ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); 144779dded87SNamhyung Kim 144879dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT); 144979dded87SNamhyung Kim width -= level * HIERARCHY_INDENT; 145079dded87SNamhyung Kim 1451a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1452a61a22f6SNamhyung Kim fmt_node = list_first_entry(&browser->hists->hpp_formats, 1453a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1454a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 145579dded87SNamhyung Kim if (perf_hpp__should_skip(fmt, browser->hists) || 145679dded87SNamhyung Kim column++ < browser->b.horiz_scroll) 145779dded87SNamhyung Kim continue; 145879dded87SNamhyung Kim 1459da1b0407SJiri Olsa ret = fmt->width(fmt, NULL, browser->hists); 146079dded87SNamhyung Kim 146179dded87SNamhyung Kim if (first) { 146279dded87SNamhyung Kim /* for folded sign */ 146379dded87SNamhyung Kim first = false; 146479dded87SNamhyung Kim ret++; 146579dded87SNamhyung Kim } else { 146679dded87SNamhyung Kim /* space between columns */ 146779dded87SNamhyung Kim ret += 2; 146879dded87SNamhyung Kim } 146979dded87SNamhyung Kim 147079dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", ret); 147179dded87SNamhyung Kim width -= ret; 147279dded87SNamhyung Kim } 147379dded87SNamhyung Kim 14742dbbe9f2SNamhyung Kim ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT); 14752dbbe9f2SNamhyung Kim width -= indent * HIERARCHY_INDENT; 147679dded87SNamhyung Kim 147779dded87SNamhyung Kim if (column >= browser->b.horiz_scroll) { 147879dded87SNamhyung Kim char buf[32]; 147979dded87SNamhyung Kim 148079dded87SNamhyung Kim ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt); 148179dded87SNamhyung Kim ui_browser__printf(&browser->b, " %s", buf); 148279dded87SNamhyung Kim width -= ret + 2; 148379dded87SNamhyung Kim } 148479dded87SNamhyung Kim 148579dded87SNamhyung Kim /* The scroll bar isn't being used */ 148679dded87SNamhyung Kim if (!browser->b.navkeypressed) 148779dded87SNamhyung Kim width += 1; 148879dded87SNamhyung Kim 148979dded87SNamhyung Kim ui_browser__write_nstring(&browser->b, "", width); 149079dded87SNamhyung Kim return 1; 149179dded87SNamhyung Kim } 149279dded87SNamhyung Kim 149381a888feSJiri Olsa static int advance_hpp_check(struct perf_hpp *hpp, int inc) 149481a888feSJiri Olsa { 149581a888feSJiri Olsa advance_hpp(hpp, inc); 149681a888feSJiri Olsa return hpp->size <= 0; 149781a888feSJiri Olsa } 149881a888feSJiri Olsa 1499c6c3c02dSArnaldo Carvalho de Melo static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size) 150081a888feSJiri Olsa { 1501c6c3c02dSArnaldo Carvalho de Melo struct hists *hists = browser->hists; 150281a888feSJiri Olsa struct perf_hpp dummy_hpp = { 150381a888feSJiri Olsa .buf = buf, 150481a888feSJiri Olsa .size = size, 150581a888feSJiri Olsa }; 150681a888feSJiri Olsa struct perf_hpp_fmt *fmt; 150781a888feSJiri Olsa size_t ret = 0; 1508c6c3c02dSArnaldo Carvalho de Melo int column = 0; 150981a888feSJiri Olsa 151081a888feSJiri Olsa if (symbol_conf.use_callchain) { 151181a888feSJiri Olsa ret = scnprintf(buf, size, " "); 151281a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 151381a888feSJiri Olsa return ret; 151481a888feSJiri Olsa } 151581a888feSJiri Olsa 1516f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 1517361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) 151881a888feSJiri Olsa continue; 151981a888feSJiri Olsa 152005372173SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists); 152181a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 152281a888feSJiri Olsa break; 152381a888feSJiri Olsa 152481a888feSJiri Olsa ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 152581a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 152681a888feSJiri Olsa break; 152781a888feSJiri Olsa } 152881a888feSJiri Olsa 152981a888feSJiri Olsa return ret; 153081a888feSJiri Olsa } 153181a888feSJiri Olsa 1532d8b92400SNamhyung Kim static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size) 1533d8b92400SNamhyung Kim { 1534d8b92400SNamhyung Kim struct hists *hists = browser->hists; 1535d8b92400SNamhyung Kim struct perf_hpp dummy_hpp = { 1536d8b92400SNamhyung Kim .buf = buf, 1537d8b92400SNamhyung Kim .size = size, 1538d8b92400SNamhyung Kim }; 1539d8b92400SNamhyung Kim struct perf_hpp_fmt *fmt; 1540a61a22f6SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1541d8b92400SNamhyung Kim size_t ret = 0; 1542d8b92400SNamhyung Kim int column = 0; 15432dbbe9f2SNamhyung Kim int indent = hists->nr_hpp_node - 2; 1544a61a22f6SNamhyung Kim bool first_node, first_col; 1545d8b92400SNamhyung Kim 1546d8b92400SNamhyung Kim ret = scnprintf(buf, size, " "); 1547d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1548d8b92400SNamhyung Kim return ret; 1549d8b92400SNamhyung Kim 1550a61a22f6SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1551a61a22f6SNamhyung Kim fmt_node = list_first_entry(&hists->hpp_formats, 1552a61a22f6SNamhyung Kim struct perf_hpp_list_node, list); 1553a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1554d8b92400SNamhyung Kim if (column++ < browser->b.horiz_scroll) 1555d8b92400SNamhyung Kim continue; 1556d8b92400SNamhyung Kim 155705372173SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists); 1558d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1559d8b92400SNamhyung Kim break; 1560d8b92400SNamhyung Kim 1561d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 1562d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1563d8b92400SNamhyung Kim break; 1564d8b92400SNamhyung Kim } 1565d8b92400SNamhyung Kim 1566d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s", 15672dbbe9f2SNamhyung Kim indent * HIERARCHY_INDENT, ""); 1568d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1569d8b92400SNamhyung Kim return ret; 1570d8b92400SNamhyung Kim 1571a61a22f6SNamhyung Kim first_node = true; 1572a61a22f6SNamhyung Kim list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) { 1573a61a22f6SNamhyung Kim if (!first_node) { 1574d8b92400SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / "); 1575d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1576d8b92400SNamhyung Kim break; 1577d8b92400SNamhyung Kim } 1578a61a22f6SNamhyung Kim first_node = false; 1579a61a22f6SNamhyung Kim 1580a61a22f6SNamhyung Kim first_col = true; 1581a61a22f6SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1582a61a22f6SNamhyung Kim char *start; 1583a61a22f6SNamhyung Kim 1584a61a22f6SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 1585a61a22f6SNamhyung Kim continue; 1586a61a22f6SNamhyung Kim 1587a61a22f6SNamhyung Kim if (!first_col) { 1588a61a22f6SNamhyung Kim ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+"); 1589a61a22f6SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1590a61a22f6SNamhyung Kim break; 1591a61a22f6SNamhyung Kim } 1592a61a22f6SNamhyung Kim first_col = false; 1593d8b92400SNamhyung Kim 159405372173SJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists); 1595d8b92400SNamhyung Kim dummy_hpp.buf[ret] = '\0'; 1596d8b92400SNamhyung Kim 15977d6a7e78SJiri Olsa start = trim(dummy_hpp.buf); 1598cb1fab91SNamhyung Kim ret = strlen(start); 1599cb1fab91SNamhyung Kim 1600cb1fab91SNamhyung Kim if (start != dummy_hpp.buf) 1601cb1fab91SNamhyung Kim memmove(dummy_hpp.buf, start, ret + 1); 1602cb1fab91SNamhyung Kim 1603d8b92400SNamhyung Kim if (advance_hpp_check(&dummy_hpp, ret)) 1604d8b92400SNamhyung Kim break; 1605d8b92400SNamhyung Kim } 1606a61a22f6SNamhyung Kim } 1607d8b92400SNamhyung Kim 1608d8b92400SNamhyung Kim return ret; 1609d8b92400SNamhyung Kim } 1610d8b92400SNamhyung Kim 161101b4770dSJiri Olsa static void hists_browser__hierarchy_headers(struct hist_browser *browser) 1612025bf7eaSArnaldo Carvalho de Melo { 161381a888feSJiri Olsa char headers[1024]; 161481a888feSJiri Olsa 1615d8b92400SNamhyung Kim hists_browser__scnprintf_hierarchy_headers(browser, headers, 1616d8b92400SNamhyung Kim sizeof(headers)); 161701b4770dSJiri Olsa 1618025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, 0, 0); 1619025bf7eaSArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 162026270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 1621025bf7eaSArnaldo Carvalho de Melo } 1622025bf7eaSArnaldo Carvalho de Melo 162301b4770dSJiri Olsa static void hists_browser__headers(struct hist_browser *browser) 162401b4770dSJiri Olsa { 162501b4770dSJiri Olsa char headers[1024]; 162601b4770dSJiri Olsa 162701b4770dSJiri Olsa hists_browser__scnprintf_headers(browser, headers, 162801b4770dSJiri Olsa sizeof(headers)); 162901b4770dSJiri Olsa 163001b4770dSJiri Olsa ui_browser__gotorc(&browser->b, 0, 0); 163101b4770dSJiri Olsa ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 163201b4770dSJiri Olsa ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 163301b4770dSJiri Olsa } 163401b4770dSJiri Olsa 163501b4770dSJiri Olsa static void hist_browser__show_headers(struct hist_browser *browser) 163601b4770dSJiri Olsa { 163701b4770dSJiri Olsa if (symbol_conf.report_hierarchy) 163801b4770dSJiri Olsa hists_browser__hierarchy_headers(browser); 163901b4770dSJiri Olsa else 164001b4770dSJiri Olsa hists_browser__headers(browser); 164101b4770dSJiri Olsa } 164201b4770dSJiri Olsa 1643aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 1644aca7a94dSNamhyung Kim { 1645aca7a94dSNamhyung Kim if (browser->top == NULL) { 1646aca7a94dSNamhyung Kim struct hist_browser *hb; 1647aca7a94dSNamhyung Kim 1648aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1649aca7a94dSNamhyung Kim browser->top = rb_first(&hb->hists->entries); 1650aca7a94dSNamhyung Kim } 1651aca7a94dSNamhyung Kim } 1652aca7a94dSNamhyung Kim 165305e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 1654aca7a94dSNamhyung Kim { 1655aca7a94dSNamhyung Kim unsigned row = 0; 1656025bf7eaSArnaldo Carvalho de Melo u16 header_offset = 0; 1657aca7a94dSNamhyung Kim struct rb_node *nd; 165805e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 1659aca7a94dSNamhyung Kim 1660025bf7eaSArnaldo Carvalho de Melo if (hb->show_headers) { 1661025bf7eaSArnaldo Carvalho de Melo hist_browser__show_headers(hb); 1662025bf7eaSArnaldo Carvalho de Melo header_offset = 1; 1663025bf7eaSArnaldo Carvalho de Melo } 1664025bf7eaSArnaldo Carvalho de Melo 166505e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1666979d2cacSWang Nan hb->he_selection = NULL; 1667979d2cacSWang Nan hb->selection = NULL; 1668aca7a94dSNamhyung Kim 1669d0506edbSNamhyung Kim for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) { 1670aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 167114135663SNamhyung Kim float percent; 1672aca7a94dSNamhyung Kim 1673d0506edbSNamhyung Kim if (h->filtered) { 1674d0506edbSNamhyung Kim /* let it move to sibling */ 1675d0506edbSNamhyung Kim h->unfolded = false; 1676aca7a94dSNamhyung Kim continue; 1677d0506edbSNamhyung Kim } 1678aca7a94dSNamhyung Kim 167914135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 1680064f1981SNamhyung Kim if (percent < hb->min_pcnt) 1681064f1981SNamhyung Kim continue; 1682064f1981SNamhyung Kim 1683d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 1684d0506edbSNamhyung Kim row += hist_browser__show_hierarchy_entry(hb, h, row, 16852dbbe9f2SNamhyung Kim h->depth); 168679dded87SNamhyung Kim if (row == browser->rows) 168779dded87SNamhyung Kim break; 168879dded87SNamhyung Kim 168979dded87SNamhyung Kim if (h->has_no_entry) { 1690a61a22f6SNamhyung Kim hist_browser__show_no_entry(hb, row, h->depth + 1); 169179dded87SNamhyung Kim row++; 169279dded87SNamhyung Kim } 1693d0506edbSNamhyung Kim } else { 1694aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 1695d0506edbSNamhyung Kim } 1696d0506edbSNamhyung Kim 169762c95ae3SArnaldo Carvalho de Melo if (row == browser->rows) 1698aca7a94dSNamhyung Kim break; 1699aca7a94dSNamhyung Kim } 1700aca7a94dSNamhyung Kim 1701025bf7eaSArnaldo Carvalho de Melo return row + header_offset; 1702aca7a94dSNamhyung Kim } 1703aca7a94dSNamhyung Kim 1704064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 1705064f1981SNamhyung Kim float min_pcnt) 1706aca7a94dSNamhyung Kim { 1707aca7a94dSNamhyung Kim while (nd != NULL) { 1708aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 170914135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1710064f1981SNamhyung Kim 1711c0f1527bSNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1712aca7a94dSNamhyung Kim return nd; 1713aca7a94dSNamhyung Kim 1714d0506edbSNamhyung Kim /* 1715d0506edbSNamhyung Kim * If it's filtered, its all children also were filtered. 1716d0506edbSNamhyung Kim * So move to sibling node. 1717d0506edbSNamhyung Kim */ 1718d0506edbSNamhyung Kim if (rb_next(nd)) 1719aca7a94dSNamhyung Kim nd = rb_next(nd); 1720d0506edbSNamhyung Kim else 1721d0506edbSNamhyung Kim nd = rb_hierarchy_next(nd); 1722aca7a94dSNamhyung Kim } 1723aca7a94dSNamhyung Kim 1724aca7a94dSNamhyung Kim return NULL; 1725aca7a94dSNamhyung Kim } 1726aca7a94dSNamhyung Kim 1727064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 1728064f1981SNamhyung Kim float min_pcnt) 1729aca7a94dSNamhyung Kim { 1730aca7a94dSNamhyung Kim while (nd != NULL) { 1731aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 173214135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 1733064f1981SNamhyung Kim 1734064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 1735aca7a94dSNamhyung Kim return nd; 1736aca7a94dSNamhyung Kim 1737d0506edbSNamhyung Kim nd = rb_hierarchy_prev(nd); 1738aca7a94dSNamhyung Kim } 1739aca7a94dSNamhyung Kim 1740aca7a94dSNamhyung Kim return NULL; 1741aca7a94dSNamhyung Kim } 1742aca7a94dSNamhyung Kim 174305e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 1744aca7a94dSNamhyung Kim off_t offset, int whence) 1745aca7a94dSNamhyung Kim { 1746aca7a94dSNamhyung Kim struct hist_entry *h; 1747aca7a94dSNamhyung Kim struct rb_node *nd; 1748aca7a94dSNamhyung Kim bool first = true; 1749064f1981SNamhyung Kim struct hist_browser *hb; 1750064f1981SNamhyung Kim 1751064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 1752aca7a94dSNamhyung Kim 175305e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 1754aca7a94dSNamhyung Kim return; 1755aca7a94dSNamhyung Kim 175605e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 1757aca7a94dSNamhyung Kim 1758aca7a94dSNamhyung Kim switch (whence) { 1759aca7a94dSNamhyung Kim case SEEK_SET: 1760064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 176114135663SNamhyung Kim hb->min_pcnt); 1762aca7a94dSNamhyung Kim break; 1763aca7a94dSNamhyung Kim case SEEK_CUR: 176405e8b080SArnaldo Carvalho de Melo nd = browser->top; 1765aca7a94dSNamhyung Kim goto do_offset; 1766aca7a94dSNamhyung Kim case SEEK_END: 1767d0506edbSNamhyung Kim nd = rb_hierarchy_last(rb_last(browser->entries)); 1768d0506edbSNamhyung Kim nd = hists__filter_prev_entries(nd, hb->min_pcnt); 1769aca7a94dSNamhyung Kim first = false; 1770aca7a94dSNamhyung Kim break; 1771aca7a94dSNamhyung Kim default: 1772aca7a94dSNamhyung Kim return; 1773aca7a94dSNamhyung Kim } 1774aca7a94dSNamhyung Kim 1775aca7a94dSNamhyung Kim /* 1776aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 1777aca7a94dSNamhyung Kim * row_offset: 1778aca7a94dSNamhyung Kim */ 177905e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 1780aca7a94dSNamhyung Kim h->row_offset = 0; 1781aca7a94dSNamhyung Kim 1782aca7a94dSNamhyung Kim /* 1783aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 1784aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 1785aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 1786aca7a94dSNamhyung Kim * 1787aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 1788aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 1789aca7a94dSNamhyung Kim * 1790aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 1791aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 1792aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 1793aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 1794aca7a94dSNamhyung Kim */ 1795aca7a94dSNamhyung Kim do_offset: 1796837eeb75SWang Nan if (!nd) 1797837eeb75SWang Nan return; 1798837eeb75SWang Nan 1799aca7a94dSNamhyung Kim if (offset > 0) { 1800aca7a94dSNamhyung Kim do { 1801aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1802d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1803aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 1804aca7a94dSNamhyung Kim if (offset > remaining) { 1805aca7a94dSNamhyung Kim offset -= remaining; 1806aca7a94dSNamhyung Kim h->row_offset = 0; 1807aca7a94dSNamhyung Kim } else { 1808aca7a94dSNamhyung Kim h->row_offset += offset; 1809aca7a94dSNamhyung Kim offset = 0; 181005e8b080SArnaldo Carvalho de Melo browser->top = nd; 1811aca7a94dSNamhyung Kim break; 1812aca7a94dSNamhyung Kim } 1813aca7a94dSNamhyung Kim } 1814d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 1815d0506edbSNamhyung Kim hb->min_pcnt); 1816aca7a94dSNamhyung Kim if (nd == NULL) 1817aca7a94dSNamhyung Kim break; 1818aca7a94dSNamhyung Kim --offset; 181905e8b080SArnaldo Carvalho de Melo browser->top = nd; 1820aca7a94dSNamhyung Kim } while (offset != 0); 1821aca7a94dSNamhyung Kim } else if (offset < 0) { 1822aca7a94dSNamhyung Kim while (1) { 1823aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1824d0506edbSNamhyung Kim if (h->unfolded && h->leaf) { 1825aca7a94dSNamhyung Kim if (first) { 1826aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 1827aca7a94dSNamhyung Kim offset += h->row_offset; 1828aca7a94dSNamhyung Kim h->row_offset = 0; 1829aca7a94dSNamhyung Kim } else { 1830aca7a94dSNamhyung Kim h->row_offset += offset; 1831aca7a94dSNamhyung Kim offset = 0; 183205e8b080SArnaldo Carvalho de Melo browser->top = nd; 1833aca7a94dSNamhyung Kim break; 1834aca7a94dSNamhyung Kim } 1835aca7a94dSNamhyung Kim } else { 1836aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 1837aca7a94dSNamhyung Kim offset += h->nr_rows; 1838aca7a94dSNamhyung Kim h->row_offset = 0; 1839aca7a94dSNamhyung Kim } else { 1840aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 1841aca7a94dSNamhyung Kim offset = 0; 184205e8b080SArnaldo Carvalho de Melo browser->top = nd; 1843aca7a94dSNamhyung Kim break; 1844aca7a94dSNamhyung Kim } 1845aca7a94dSNamhyung Kim } 1846aca7a94dSNamhyung Kim } 1847aca7a94dSNamhyung Kim 1848d0506edbSNamhyung Kim nd = hists__filter_prev_entries(rb_hierarchy_prev(nd), 1849064f1981SNamhyung Kim hb->min_pcnt); 1850aca7a94dSNamhyung Kim if (nd == NULL) 1851aca7a94dSNamhyung Kim break; 1852aca7a94dSNamhyung Kim ++offset; 185305e8b080SArnaldo Carvalho de Melo browser->top = nd; 1854aca7a94dSNamhyung Kim if (offset == 0) { 1855aca7a94dSNamhyung Kim /* 1856aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 1857aca7a94dSNamhyung Kim * unfolded, if it is then we should have 1858aca7a94dSNamhyung Kim * row_offset at its last entry. 1859aca7a94dSNamhyung Kim */ 1860aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1861d0506edbSNamhyung Kim if (h->unfolded && h->leaf) 1862aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 1863aca7a94dSNamhyung Kim break; 1864aca7a94dSNamhyung Kim } 1865aca7a94dSNamhyung Kim first = false; 1866aca7a94dSNamhyung Kim } 1867aca7a94dSNamhyung Kim } else { 186805e8b080SArnaldo Carvalho de Melo browser->top = nd; 1869aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1870aca7a94dSNamhyung Kim h->row_offset = 0; 1871aca7a94dSNamhyung Kim } 1872aca7a94dSNamhyung Kim } 1873aca7a94dSNamhyung Kim 1874aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1875d0506edbSNamhyung Kim struct hist_entry *he, FILE *fp, 1876d0506edbSNamhyung Kim int level) 1877aff3f3f6SArnaldo Carvalho de Melo { 187839ee533fSNamhyung Kim struct callchain_print_arg arg = { 187939ee533fSNamhyung Kim .fp = fp, 188039ee533fSNamhyung Kim }; 1881aff3f3f6SArnaldo Carvalho de Melo 1882d0506edbSNamhyung Kim hist_browser__show_callchain(browser, he, level, 0, 188339ee533fSNamhyung Kim hist_browser__fprintf_callchain_entry, &arg, 188439ee533fSNamhyung Kim hist_browser__check_dump_full); 188539ee533fSNamhyung Kim return arg.printed; 1886aff3f3f6SArnaldo Carvalho de Melo } 1887aff3f3f6SArnaldo Carvalho de Melo 1888aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 1889aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 1890aff3f3f6SArnaldo Carvalho de Melo { 1891aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 1892aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1893aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 189426d8b338SNamhyung Kim struct perf_hpp hpp = { 189526d8b338SNamhyung Kim .buf = s, 189626d8b338SNamhyung Kim .size = sizeof(s), 189726d8b338SNamhyung Kim }; 189826d8b338SNamhyung Kim struct perf_hpp_fmt *fmt; 189926d8b338SNamhyung Kim bool first = true; 190026d8b338SNamhyung Kim int ret; 1901aff3f3f6SArnaldo Carvalho de Melo 19021b6b678eSArnaldo Carvalho de Melo if (symbol_conf.use_callchain) { 1903aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 1904aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 19051b6b678eSArnaldo Carvalho de Melo } 1906aff3f3f6SArnaldo Carvalho de Melo 1907f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 1908361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, he->hists)) 1909e67d49a7SNamhyung Kim continue; 1910e67d49a7SNamhyung Kim 191126d8b338SNamhyung Kim if (!first) { 191226d8b338SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 191326d8b338SNamhyung Kim advance_hpp(&hpp, ret); 191426d8b338SNamhyung Kim } else 191526d8b338SNamhyung Kim first = false; 1916aff3f3f6SArnaldo Carvalho de Melo 191726d8b338SNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 191889fee709SArnaldo Carvalho de Melo ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret); 191926d8b338SNamhyung Kim advance_hpp(&hpp, ret); 192026d8b338SNamhyung Kim } 192189fee709SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", s); 1922aff3f3f6SArnaldo Carvalho de Melo 1923aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 1924d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 1); 1925d0506edbSNamhyung Kim 1926d0506edbSNamhyung Kim return printed; 1927d0506edbSNamhyung Kim } 1928d0506edbSNamhyung Kim 1929d0506edbSNamhyung Kim 1930d0506edbSNamhyung Kim static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser, 1931d0506edbSNamhyung Kim struct hist_entry *he, 1932325a6283SNamhyung Kim FILE *fp, int level) 1933d0506edbSNamhyung Kim { 1934d0506edbSNamhyung Kim char s[8192]; 1935d0506edbSNamhyung Kim int printed = 0; 1936d0506edbSNamhyung Kim char folded_sign = ' '; 1937d0506edbSNamhyung Kim struct perf_hpp hpp = { 1938d0506edbSNamhyung Kim .buf = s, 1939d0506edbSNamhyung Kim .size = sizeof(s), 1940d0506edbSNamhyung Kim }; 1941d0506edbSNamhyung Kim struct perf_hpp_fmt *fmt; 1942325a6283SNamhyung Kim struct perf_hpp_list_node *fmt_node; 1943d0506edbSNamhyung Kim bool first = true; 1944d0506edbSNamhyung Kim int ret; 1945325a6283SNamhyung Kim int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT; 1946d0506edbSNamhyung Kim 1947d0506edbSNamhyung Kim printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, ""); 1948d0506edbSNamhyung Kim 1949d0506edbSNamhyung Kim folded_sign = hist_entry__folded(he); 1950d0506edbSNamhyung Kim printed += fprintf(fp, "%c", folded_sign); 1951d0506edbSNamhyung Kim 1952325a6283SNamhyung Kim /* the first hpp_list_node is for overhead columns */ 1953325a6283SNamhyung Kim fmt_node = list_first_entry(&he->hists->hpp_formats, 1954325a6283SNamhyung Kim struct perf_hpp_list_node, list); 1955325a6283SNamhyung Kim perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { 1956d0506edbSNamhyung Kim if (!first) { 1957d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 1958d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 1959d0506edbSNamhyung Kim } else 1960d0506edbSNamhyung Kim first = false; 1961d0506edbSNamhyung Kim 1962d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 1963d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 1964d0506edbSNamhyung Kim } 1965d0506edbSNamhyung Kim 1966d0506edbSNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, ""); 1967d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 1968d0506edbSNamhyung Kim 19691b2dbbf4SNamhyung Kim perf_hpp_list__for_each_format(he->hpp_list, fmt) { 19701b2dbbf4SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 19711b2dbbf4SNamhyung Kim advance_hpp(&hpp, ret); 19721b2dbbf4SNamhyung Kim 1973d0506edbSNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 1974d0506edbSNamhyung Kim advance_hpp(&hpp, ret); 19751b2dbbf4SNamhyung Kim } 1976d0506edbSNamhyung Kim 1977d0506edbSNamhyung Kim printed += fprintf(fp, "%s\n", rtrim(s)); 1978d0506edbSNamhyung Kim 1979d0506edbSNamhyung Kim if (he->leaf && folded_sign == '-') { 1980d0506edbSNamhyung Kim printed += hist_browser__fprintf_callchain(browser, he, fp, 1981d0506edbSNamhyung Kim he->depth + 1); 1982d0506edbSNamhyung Kim } 1983aff3f3f6SArnaldo Carvalho de Melo 1984aff3f3f6SArnaldo Carvalho de Melo return printed; 1985aff3f3f6SArnaldo Carvalho de Melo } 1986aff3f3f6SArnaldo Carvalho de Melo 1987aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1988aff3f3f6SArnaldo Carvalho de Melo { 1989064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1990064f1981SNamhyung Kim browser->min_pcnt); 1991aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1992aff3f3f6SArnaldo Carvalho de Melo 1993aff3f3f6SArnaldo Carvalho de Melo while (nd) { 1994aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1995aff3f3f6SArnaldo Carvalho de Melo 1996d0506edbSNamhyung Kim if (symbol_conf.report_hierarchy) { 1997d0506edbSNamhyung Kim printed += hist_browser__fprintf_hierarchy_entry(browser, 1998d0506edbSNamhyung Kim h, fp, 1999325a6283SNamhyung Kim h->depth); 2000d0506edbSNamhyung Kim } else { 2001aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 2002d0506edbSNamhyung Kim } 2003d0506edbSNamhyung Kim 2004d0506edbSNamhyung Kim nd = hists__filter_entries(rb_hierarchy_next(nd), 2005d0506edbSNamhyung Kim browser->min_pcnt); 2006aff3f3f6SArnaldo Carvalho de Melo } 2007aff3f3f6SArnaldo Carvalho de Melo 2008aff3f3f6SArnaldo Carvalho de Melo return printed; 2009aff3f3f6SArnaldo Carvalho de Melo } 2010aff3f3f6SArnaldo Carvalho de Melo 2011aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 2012aff3f3f6SArnaldo Carvalho de Melo { 2013aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 2014aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 2015aff3f3f6SArnaldo Carvalho de Melo 2016aff3f3f6SArnaldo Carvalho de Melo while (1) { 2017aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 2018aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 2019aff3f3f6SArnaldo Carvalho de Melo break; 2020aff3f3f6SArnaldo Carvalho de Melo /* 2021aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 2022aff3f3f6SArnaldo Carvalho de Melo */ 2023aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 2024aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 2025aff3f3f6SArnaldo Carvalho de Melo return -1; 2026aff3f3f6SArnaldo Carvalho de Melo } 2027aff3f3f6SArnaldo Carvalho de Melo } 2028aff3f3f6SArnaldo Carvalho de Melo 2029aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 2030aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 2031aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 20324cc49d4dSKirill A. Shutemov const char *err = strerror_r(errno, bf, sizeof(bf)); 20334cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 2034aff3f3f6SArnaldo Carvalho de Melo return -1; 2035aff3f3f6SArnaldo Carvalho de Melo } 2036aff3f3f6SArnaldo Carvalho de Melo 2037aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 2038aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 2039aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 2040aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 2041aff3f3f6SArnaldo Carvalho de Melo 2042aff3f3f6SArnaldo Carvalho de Melo return 0; 2043aff3f3f6SArnaldo Carvalho de Melo } 2044aff3f3f6SArnaldo Carvalho de Melo 2045dabd2012SJiri Olsa struct hist_browser *hist_browser__new(struct hists *hists, 2046b1a9ceefSNamhyung Kim struct hist_browser_timer *hbt, 2047ce80d3beSKan Liang struct perf_env *env) 2048aca7a94dSNamhyung Kim { 204905e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = zalloc(sizeof(*browser)); 2050aca7a94dSNamhyung Kim 205105e8b080SArnaldo Carvalho de Melo if (browser) { 205205e8b080SArnaldo Carvalho de Melo browser->hists = hists; 205305e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 2054357cfff1SArnaldo Carvalho de Melo browser->b.refresh_dimensions = hist_browser__refresh_dimensions; 205505e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 205605e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 2057c8302367SJiri Olsa browser->show_headers = symbol_conf.show_hist_headers; 2058c2a51ab8SNamhyung Kim browser->hbt = hbt; 2059b1a9ceefSNamhyung Kim browser->env = env; 2060*5b91a86fSJiri Olsa browser->title = perf_evsel_browser_title; 2061aca7a94dSNamhyung Kim } 2062aca7a94dSNamhyung Kim 206305e8b080SArnaldo Carvalho de Melo return browser; 2064aca7a94dSNamhyung Kim } 2065aca7a94dSNamhyung Kim 2066dabd2012SJiri Olsa void hist_browser__delete(struct hist_browser *browser) 2067aca7a94dSNamhyung Kim { 206805e8b080SArnaldo Carvalho de Melo free(browser); 2069aca7a94dSNamhyung Kim } 2070aca7a94dSNamhyung Kim 207105e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 2072aca7a94dSNamhyung Kim { 207305e8b080SArnaldo Carvalho de Melo return browser->he_selection; 2074aca7a94dSNamhyung Kim } 2075aca7a94dSNamhyung Kim 207605e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 2077aca7a94dSNamhyung Kim { 207805e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 2079aca7a94dSNamhyung Kim } 2080aca7a94dSNamhyung Kim 20811e378ebdSTaeung Song /* Check whether the browser is for 'top' or 'report' */ 20821e378ebdSTaeung Song static inline bool is_report_browser(void *timer) 20831e378ebdSTaeung Song { 20841e378ebdSTaeung Song return timer == NULL; 20851e378ebdSTaeung Song } 20861e378ebdSTaeung Song 2087*5b91a86fSJiri Olsa static int perf_evsel_browser_title(struct hist_browser *browser, 20881e378ebdSTaeung Song char *bf, size_t size) 2089aca7a94dSNamhyung Kim { 2090*5b91a86fSJiri Olsa struct hist_browser_timer *hbt = browser->hbt; 2091*5b91a86fSJiri Olsa struct hists *hists = browser->hists; 2092aca7a94dSNamhyung Kim char unit; 2093aca7a94dSNamhyung Kim int printed; 209405e8b080SArnaldo Carvalho de Melo const struct dso *dso = hists->dso_filter; 209505e8b080SArnaldo Carvalho de Melo const struct thread *thread = hists->thread_filter; 209684734b06SKan Liang int socket_id = hists->socket_filter; 209705e8b080SArnaldo Carvalho de Melo unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 209805e8b080SArnaldo Carvalho de Melo u64 nr_events = hists->stats.total_period; 2099717e263fSNamhyung Kim struct perf_evsel *evsel = hists_to_evsel(hists); 2100dd00d486SJiri Olsa const char *ev_name = perf_evsel__name(evsel); 2101717e263fSNamhyung Kim char buf[512]; 2102717e263fSNamhyung Kim size_t buflen = sizeof(buf); 21039e207ddfSKan Liang char ref[30] = " show reference callgraph, "; 21049e207ddfSKan Liang bool enable_ref = false; 2105717e263fSNamhyung Kim 2106f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 2107f2148330SNamhyung Kim nr_samples = hists->stats.nr_non_filtered_samples; 2108f2148330SNamhyung Kim nr_events = hists->stats.total_non_filtered_period; 2109f2148330SNamhyung Kim } 2110f2148330SNamhyung Kim 2111759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 2112717e263fSNamhyung Kim struct perf_evsel *pos; 2113717e263fSNamhyung Kim 2114717e263fSNamhyung Kim perf_evsel__group_desc(evsel, buf, buflen); 2115717e263fSNamhyung Kim ev_name = buf; 2116717e263fSNamhyung Kim 2117717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 21184ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 21194ea062edSArnaldo Carvalho de Melo 2120f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 21214ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_non_filtered_samples; 21224ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_non_filtered_period; 2123f2148330SNamhyung Kim } else { 21244ea062edSArnaldo Carvalho de Melo nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 21254ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.total_period; 2126717e263fSNamhyung Kim } 2127717e263fSNamhyung Kim } 2128f2148330SNamhyung Kim } 2129aca7a94dSNamhyung Kim 21309e207ddfSKan Liang if (symbol_conf.show_ref_callgraph && 21319e207ddfSKan Liang strstr(ev_name, "call-graph=no")) 21329e207ddfSKan Liang enable_ref = true; 2133aca7a94dSNamhyung Kim nr_samples = convert_unit(nr_samples, &unit); 2134aca7a94dSNamhyung Kim printed = scnprintf(bf, size, 21359e207ddfSKan Liang "Samples: %lu%c of event '%s',%sEvent count (approx.): %" PRIu64, 21369e207ddfSKan Liang nr_samples, unit, ev_name, enable_ref ? ref : " ", nr_events); 2137aca7a94dSNamhyung Kim 2138aca7a94dSNamhyung Kim 213905e8b080SArnaldo Carvalho de Melo if (hists->uid_filter_str) 2140aca7a94dSNamhyung Kim printed += snprintf(bf + printed, size - printed, 214105e8b080SArnaldo Carvalho de Melo ", UID: %s", hists->uid_filter_str); 21426962ccb3SNamhyung Kim if (thread) { 2143fa82911aSJiri Olsa if (hists__has(hists, thread)) { 2144aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 2145aca7a94dSNamhyung Kim ", Thread: %s(%d)", 2146b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 214738051234SAdrian Hunter thread->tid); 21486962ccb3SNamhyung Kim } else { 21496962ccb3SNamhyung Kim printed += scnprintf(bf + printed, size - printed, 21506962ccb3SNamhyung Kim ", Thread: %s", 21516962ccb3SNamhyung Kim (thread->comm_set ? thread__comm_str(thread) : "")); 21526962ccb3SNamhyung Kim } 21536962ccb3SNamhyung Kim } 2154aca7a94dSNamhyung Kim if (dso) 2155aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 2156aca7a94dSNamhyung Kim ", DSO: %s", dso->short_name); 215784734b06SKan Liang if (socket_id > -1) 215821394d94SKan Liang printed += scnprintf(bf + printed, size - printed, 215984734b06SKan Liang ", Processor Socket: %d", socket_id); 21601e378ebdSTaeung Song if (!is_report_browser(hbt)) { 21611e378ebdSTaeung Song struct perf_top *top = hbt->arg; 21621e378ebdSTaeung Song 21631e378ebdSTaeung Song if (top->zero) 21641e378ebdSTaeung Song printed += scnprintf(bf + printed, size - printed, " [z]"); 21651e378ebdSTaeung Song } 21661e378ebdSTaeung Song 2167aca7a94dSNamhyung Kim return printed; 2168aca7a94dSNamhyung Kim } 2169aca7a94dSNamhyung Kim 2170aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 2171aca7a94dSNamhyung Kim { 2172aca7a94dSNamhyung Kim int i; 2173aca7a94dSNamhyung Kim 217404662523SArnaldo Carvalho de Melo for (i = 0; i < n; ++i) 217504662523SArnaldo Carvalho de Melo zfree(&options[i]); 2176aca7a94dSNamhyung Kim } 2177aca7a94dSNamhyung Kim 2178341487abSFeng Tang /* 2179341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 2180341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 2181341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 2182341487abSFeng Tang */ 2183341487abSFeng Tang static bool is_input_name_malloced = false; 2184341487abSFeng Tang 2185341487abSFeng Tang static int switch_data_file(void) 2186341487abSFeng Tang { 2187341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 2188341487abSFeng Tang DIR *pwd_dir; 2189341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 2190341487abSFeng Tang struct dirent *dent; 2191341487abSFeng Tang 2192341487abSFeng Tang pwd = getenv("PWD"); 2193341487abSFeng Tang if (!pwd) 2194341487abSFeng Tang return ret; 2195341487abSFeng Tang 2196341487abSFeng Tang pwd_dir = opendir(pwd); 2197341487abSFeng Tang if (!pwd_dir) 2198341487abSFeng Tang return ret; 2199341487abSFeng Tang 2200341487abSFeng Tang memset(options, 0, sizeof(options)); 2201341487abSFeng Tang memset(options, 0, sizeof(abs_path)); 2202341487abSFeng Tang 2203341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 2204341487abSFeng Tang char path[PATH_MAX]; 2205341487abSFeng Tang u64 magic; 2206341487abSFeng Tang char *name = dent->d_name; 2207341487abSFeng Tang FILE *file; 2208341487abSFeng Tang 2209341487abSFeng Tang if (!(dent->d_type == DT_REG)) 2210341487abSFeng Tang continue; 2211341487abSFeng Tang 2212341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 2213341487abSFeng Tang 2214341487abSFeng Tang file = fopen(path, "r"); 2215341487abSFeng Tang if (!file) 2216341487abSFeng Tang continue; 2217341487abSFeng Tang 2218341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 2219341487abSFeng Tang goto close_file_and_continue; 2220341487abSFeng Tang 2221341487abSFeng Tang if (is_perf_magic(magic)) { 2222341487abSFeng Tang options[nr_options] = strdup(name); 2223341487abSFeng Tang if (!options[nr_options]) 2224341487abSFeng Tang goto close_file_and_continue; 2225341487abSFeng Tang 2226341487abSFeng Tang abs_path[nr_options] = strdup(path); 2227341487abSFeng Tang if (!abs_path[nr_options]) { 222874cf249dSArnaldo Carvalho de Melo zfree(&options[nr_options]); 2229341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 2230341487abSFeng Tang fclose(file); 2231341487abSFeng Tang break; 2232341487abSFeng Tang } 2233341487abSFeng Tang 2234341487abSFeng Tang nr_options++; 2235341487abSFeng Tang } 2236341487abSFeng Tang 2237341487abSFeng Tang close_file_and_continue: 2238341487abSFeng Tang fclose(file); 2239341487abSFeng Tang if (nr_options >= 32) { 2240341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 2241341487abSFeng Tang "Only the first 32 files will be listed.\n"); 2242341487abSFeng Tang break; 2243341487abSFeng Tang } 2244341487abSFeng Tang } 2245341487abSFeng Tang closedir(pwd_dir); 2246341487abSFeng Tang 2247341487abSFeng Tang if (nr_options) { 2248341487abSFeng Tang choice = ui__popup_menu(nr_options, options); 2249341487abSFeng Tang if (choice < nr_options && choice >= 0) { 2250341487abSFeng Tang tmp = strdup(abs_path[choice]); 2251341487abSFeng Tang if (tmp) { 2252341487abSFeng Tang if (is_input_name_malloced) 2253341487abSFeng Tang free((void *)input_name); 2254341487abSFeng Tang input_name = tmp; 2255341487abSFeng Tang is_input_name_malloced = true; 2256341487abSFeng Tang ret = 0; 2257341487abSFeng Tang } else 2258341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 2259341487abSFeng Tang } 2260341487abSFeng Tang } 2261341487abSFeng Tang 2262341487abSFeng Tang free_popup_options(options, nr_options); 2263341487abSFeng Tang free_popup_options(abs_path, nr_options); 2264341487abSFeng Tang return ret; 2265341487abSFeng Tang } 2266341487abSFeng Tang 2267ea7cd592SNamhyung Kim struct popup_action { 2268ea7cd592SNamhyung Kim struct thread *thread; 2269ea7cd592SNamhyung Kim struct map_symbol ms; 227084734b06SKan Liang int socket; 2271ea7cd592SNamhyung Kim 2272ea7cd592SNamhyung Kim int (*fn)(struct hist_browser *browser, struct popup_action *act); 2273ea7cd592SNamhyung Kim }; 2274ea7cd592SNamhyung Kim 2275bc7cad42SNamhyung Kim static int 2276ea7cd592SNamhyung Kim do_annotate(struct hist_browser *browser, struct popup_action *act) 2277bc7cad42SNamhyung Kim { 2278bc7cad42SNamhyung Kim struct perf_evsel *evsel; 2279bc7cad42SNamhyung Kim struct annotation *notes; 2280bc7cad42SNamhyung Kim struct hist_entry *he; 2281bc7cad42SNamhyung Kim int err; 2282bc7cad42SNamhyung Kim 2283eebd0bfcSArnaldo Carvalho de Melo if (!objdump_path && perf_env__lookup_objdump(browser->env)) 2284bc7cad42SNamhyung Kim return 0; 2285bc7cad42SNamhyung Kim 2286ea7cd592SNamhyung Kim notes = symbol__annotation(act->ms.sym); 2287bc7cad42SNamhyung Kim if (!notes->src) 2288bc7cad42SNamhyung Kim return 0; 2289bc7cad42SNamhyung Kim 2290bc7cad42SNamhyung Kim evsel = hists_to_evsel(browser->hists); 2291ea7cd592SNamhyung Kim err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); 2292bc7cad42SNamhyung Kim he = hist_browser__selected_entry(browser); 2293bc7cad42SNamhyung Kim /* 2294bc7cad42SNamhyung Kim * offer option to annotate the other branch source or target 2295bc7cad42SNamhyung Kim * (if they exists) when returning from annotate 2296bc7cad42SNamhyung Kim */ 2297bc7cad42SNamhyung Kim if ((err == 'q' || err == CTRL('c')) && he->branch_info) 2298bc7cad42SNamhyung Kim return 1; 2299bc7cad42SNamhyung Kim 2300bc7cad42SNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 2301bc7cad42SNamhyung Kim if (err) 2302bc7cad42SNamhyung Kim ui_browser__handle_resize(&browser->b); 2303bc7cad42SNamhyung Kim return 0; 2304bc7cad42SNamhyung Kim } 2305bc7cad42SNamhyung Kim 2306bc7cad42SNamhyung Kim static int 2307ea7cd592SNamhyung Kim add_annotate_opt(struct hist_browser *browser __maybe_unused, 2308ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 2309ea7cd592SNamhyung Kim struct map *map, struct symbol *sym) 2310bc7cad42SNamhyung Kim { 2311ea7cd592SNamhyung Kim if (sym == NULL || map->dso->annotate_warned) 2312ea7cd592SNamhyung Kim return 0; 2313ea7cd592SNamhyung Kim 2314ea7cd592SNamhyung Kim if (asprintf(optstr, "Annotate %s", sym->name) < 0) 2315ea7cd592SNamhyung Kim return 0; 2316ea7cd592SNamhyung Kim 2317ea7cd592SNamhyung Kim act->ms.map = map; 2318ea7cd592SNamhyung Kim act->ms.sym = sym; 2319ea7cd592SNamhyung Kim act->fn = do_annotate; 2320ea7cd592SNamhyung Kim return 1; 2321ea7cd592SNamhyung Kim } 2322ea7cd592SNamhyung Kim 2323ea7cd592SNamhyung Kim static int 2324ea7cd592SNamhyung Kim do_zoom_thread(struct hist_browser *browser, struct popup_action *act) 2325ea7cd592SNamhyung Kim { 2326ea7cd592SNamhyung Kim struct thread *thread = act->thread; 2327ea7cd592SNamhyung Kim 23287cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 23297cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2330599a2f38SNamhyung Kim return 0; 2331599a2f38SNamhyung Kim 2332bc7cad42SNamhyung Kim if (browser->hists->thread_filter) { 2333bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->thread_filter); 2334bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2335bc7cad42SNamhyung Kim thread__zput(browser->hists->thread_filter); 2336bc7cad42SNamhyung Kim ui_helpline__pop(); 2337bc7cad42SNamhyung Kim } else { 2338fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 23397727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 2340bc7cad42SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 2341bc7cad42SNamhyung Kim thread->tid); 23426962ccb3SNamhyung Kim } else { 23436962ccb3SNamhyung Kim ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"", 23446962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 23456962ccb3SNamhyung Kim } 23466962ccb3SNamhyung Kim 2347bc7cad42SNamhyung Kim browser->hists->thread_filter = thread__get(thread); 2348bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_THREAD, false); 2349bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->thread_filter); 2350bc7cad42SNamhyung Kim } 2351bc7cad42SNamhyung Kim 2352bc7cad42SNamhyung Kim hists__filter_by_thread(browser->hists); 2353bc7cad42SNamhyung Kim hist_browser__reset(browser); 2354bc7cad42SNamhyung Kim return 0; 2355bc7cad42SNamhyung Kim } 2356bc7cad42SNamhyung Kim 2357bc7cad42SNamhyung Kim static int 2358ea7cd592SNamhyung Kim add_thread_opt(struct hist_browser *browser, struct popup_action *act, 2359ea7cd592SNamhyung Kim char **optstr, struct thread *thread) 2360bc7cad42SNamhyung Kim { 23616962ccb3SNamhyung Kim int ret; 23626962ccb3SNamhyung Kim 23637cecb7feSJiri Olsa if ((!hists__has(browser->hists, thread) && 23647cecb7feSJiri Olsa !hists__has(browser->hists, comm)) || thread == NULL) 2365ea7cd592SNamhyung Kim return 0; 2366ea7cd592SNamhyung Kim 2367fa82911aSJiri Olsa if (hists__has(browser->hists, thread)) { 23686962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s(%d) thread", 2369ea7cd592SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 2370ea7cd592SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : "", 23716962ccb3SNamhyung Kim thread->tid); 23726962ccb3SNamhyung Kim } else { 23736962ccb3SNamhyung Kim ret = asprintf(optstr, "Zoom %s %s thread", 23746962ccb3SNamhyung Kim browser->hists->thread_filter ? "out of" : "into", 23756962ccb3SNamhyung Kim thread->comm_set ? thread__comm_str(thread) : ""); 23766962ccb3SNamhyung Kim } 23776962ccb3SNamhyung Kim if (ret < 0) 2378ea7cd592SNamhyung Kim return 0; 2379ea7cd592SNamhyung Kim 2380ea7cd592SNamhyung Kim act->thread = thread; 2381ea7cd592SNamhyung Kim act->fn = do_zoom_thread; 2382ea7cd592SNamhyung Kim return 1; 2383ea7cd592SNamhyung Kim } 2384ea7cd592SNamhyung Kim 2385ea7cd592SNamhyung Kim static int 2386ea7cd592SNamhyung Kim do_zoom_dso(struct hist_browser *browser, struct popup_action *act) 2387ea7cd592SNamhyung Kim { 2388045b80ddSArnaldo Carvalho de Melo struct map *map = act->ms.map; 2389ea7cd592SNamhyung Kim 239069849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2391599a2f38SNamhyung Kim return 0; 2392599a2f38SNamhyung Kim 2393bc7cad42SNamhyung Kim if (browser->hists->dso_filter) { 2394bc7cad42SNamhyung Kim pstack__remove(browser->pstack, &browser->hists->dso_filter); 2395bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, false); 2396bc7cad42SNamhyung Kim browser->hists->dso_filter = NULL; 2397bc7cad42SNamhyung Kim ui_helpline__pop(); 2398bc7cad42SNamhyung Kim } else { 2399045b80ddSArnaldo Carvalho de Melo if (map == NULL) 2400bc7cad42SNamhyung Kim return 0; 24017727a925SArnaldo Carvalho de Melo ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", 2402045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); 2403045b80ddSArnaldo Carvalho de Melo browser->hists->dso_filter = map->dso; 2404bc7cad42SNamhyung Kim perf_hpp__set_elide(HISTC_DSO, true); 2405bc7cad42SNamhyung Kim pstack__push(browser->pstack, &browser->hists->dso_filter); 2406bc7cad42SNamhyung Kim } 2407bc7cad42SNamhyung Kim 2408bc7cad42SNamhyung Kim hists__filter_by_dso(browser->hists); 2409bc7cad42SNamhyung Kim hist_browser__reset(browser); 2410bc7cad42SNamhyung Kim return 0; 2411bc7cad42SNamhyung Kim } 2412bc7cad42SNamhyung Kim 2413bc7cad42SNamhyung Kim static int 2414ea7cd592SNamhyung Kim add_dso_opt(struct hist_browser *browser, struct popup_action *act, 2415045b80ddSArnaldo Carvalho de Melo char **optstr, struct map *map) 2416bc7cad42SNamhyung Kim { 241769849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2418ea7cd592SNamhyung Kim return 0; 2419ea7cd592SNamhyung Kim 2420ea7cd592SNamhyung Kim if (asprintf(optstr, "Zoom %s %s DSO", 2421ea7cd592SNamhyung Kim browser->hists->dso_filter ? "out of" : "into", 2422045b80ddSArnaldo Carvalho de Melo __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) 2423ea7cd592SNamhyung Kim return 0; 2424ea7cd592SNamhyung Kim 2425045b80ddSArnaldo Carvalho de Melo act->ms.map = map; 2426ea7cd592SNamhyung Kim act->fn = do_zoom_dso; 2427ea7cd592SNamhyung Kim return 1; 2428ea7cd592SNamhyung Kim } 2429ea7cd592SNamhyung Kim 2430ea7cd592SNamhyung Kim static int 2431ea7cd592SNamhyung Kim do_browse_map(struct hist_browser *browser __maybe_unused, 2432ea7cd592SNamhyung Kim struct popup_action *act) 2433ea7cd592SNamhyung Kim { 2434ea7cd592SNamhyung Kim map__browse(act->ms.map); 2435bc7cad42SNamhyung Kim return 0; 2436bc7cad42SNamhyung Kim } 2437bc7cad42SNamhyung Kim 2438bc7cad42SNamhyung Kim static int 243969849fc5SJiri Olsa add_map_opt(struct hist_browser *browser, 2440ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, struct map *map) 2441ea7cd592SNamhyung Kim { 244269849fc5SJiri Olsa if (!hists__has(browser->hists, dso) || map == NULL) 2443ea7cd592SNamhyung Kim return 0; 2444ea7cd592SNamhyung Kim 2445ea7cd592SNamhyung Kim if (asprintf(optstr, "Browse map details") < 0) 2446ea7cd592SNamhyung Kim return 0; 2447ea7cd592SNamhyung Kim 2448ea7cd592SNamhyung Kim act->ms.map = map; 2449ea7cd592SNamhyung Kim act->fn = do_browse_map; 2450ea7cd592SNamhyung Kim return 1; 2451ea7cd592SNamhyung Kim } 2452ea7cd592SNamhyung Kim 2453ea7cd592SNamhyung Kim static int 2454bc7cad42SNamhyung Kim do_run_script(struct hist_browser *browser __maybe_unused, 2455ea7cd592SNamhyung Kim struct popup_action *act) 2456bc7cad42SNamhyung Kim { 2457bc7cad42SNamhyung Kim char script_opt[64]; 2458bc7cad42SNamhyung Kim memset(script_opt, 0, sizeof(script_opt)); 2459bc7cad42SNamhyung Kim 2460ea7cd592SNamhyung Kim if (act->thread) { 2461bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -c %s ", 2462ea7cd592SNamhyung Kim thread__comm_str(act->thread)); 2463ea7cd592SNamhyung Kim } else if (act->ms.sym) { 2464bc7cad42SNamhyung Kim scnprintf(script_opt, sizeof(script_opt), " -S %s ", 2465ea7cd592SNamhyung Kim act->ms.sym->name); 2466bc7cad42SNamhyung Kim } 2467bc7cad42SNamhyung Kim 2468bc7cad42SNamhyung Kim script_browse(script_opt); 2469bc7cad42SNamhyung Kim return 0; 2470bc7cad42SNamhyung Kim } 2471bc7cad42SNamhyung Kim 2472bc7cad42SNamhyung Kim static int 2473ea7cd592SNamhyung Kim add_script_opt(struct hist_browser *browser __maybe_unused, 2474ea7cd592SNamhyung Kim struct popup_action *act, char **optstr, 2475ea7cd592SNamhyung Kim struct thread *thread, struct symbol *sym) 2476ea7cd592SNamhyung Kim { 2477ea7cd592SNamhyung Kim if (thread) { 2478ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of thread [%s]", 2479ea7cd592SNamhyung Kim thread__comm_str(thread)) < 0) 2480ea7cd592SNamhyung Kim return 0; 2481ea7cd592SNamhyung Kim } else if (sym) { 2482ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for samples of symbol [%s]", 2483ea7cd592SNamhyung Kim sym->name) < 0) 2484ea7cd592SNamhyung Kim return 0; 2485ea7cd592SNamhyung Kim } else { 2486ea7cd592SNamhyung Kim if (asprintf(optstr, "Run scripts for all samples") < 0) 2487ea7cd592SNamhyung Kim return 0; 2488ea7cd592SNamhyung Kim } 2489ea7cd592SNamhyung Kim 2490ea7cd592SNamhyung Kim act->thread = thread; 2491ea7cd592SNamhyung Kim act->ms.sym = sym; 2492ea7cd592SNamhyung Kim act->fn = do_run_script; 2493ea7cd592SNamhyung Kim return 1; 2494ea7cd592SNamhyung Kim } 2495ea7cd592SNamhyung Kim 2496ea7cd592SNamhyung Kim static int 2497ea7cd592SNamhyung Kim do_switch_data(struct hist_browser *browser __maybe_unused, 2498ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2499bc7cad42SNamhyung Kim { 2500bc7cad42SNamhyung Kim if (switch_data_file()) { 2501bc7cad42SNamhyung Kim ui__warning("Won't switch the data files due to\n" 2502bc7cad42SNamhyung Kim "no valid data file get selected!\n"); 2503ea7cd592SNamhyung Kim return 0; 2504bc7cad42SNamhyung Kim } 2505bc7cad42SNamhyung Kim 2506bc7cad42SNamhyung Kim return K_SWITCH_INPUT_DATA; 2507bc7cad42SNamhyung Kim } 2508bc7cad42SNamhyung Kim 2509ea7cd592SNamhyung Kim static int 2510ea7cd592SNamhyung Kim add_switch_opt(struct hist_browser *browser, 2511ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2512ea7cd592SNamhyung Kim { 2513ea7cd592SNamhyung Kim if (!is_report_browser(browser->hbt)) 2514ea7cd592SNamhyung Kim return 0; 2515ea7cd592SNamhyung Kim 2516ea7cd592SNamhyung Kim if (asprintf(optstr, "Switch to another data file in PWD") < 0) 2517ea7cd592SNamhyung Kim return 0; 2518ea7cd592SNamhyung Kim 2519ea7cd592SNamhyung Kim act->fn = do_switch_data; 2520ea7cd592SNamhyung Kim return 1; 2521ea7cd592SNamhyung Kim } 2522ea7cd592SNamhyung Kim 2523ea7cd592SNamhyung Kim static int 2524ea7cd592SNamhyung Kim do_exit_browser(struct hist_browser *browser __maybe_unused, 2525ea7cd592SNamhyung Kim struct popup_action *act __maybe_unused) 2526ea7cd592SNamhyung Kim { 2527ea7cd592SNamhyung Kim return 0; 2528ea7cd592SNamhyung Kim } 2529ea7cd592SNamhyung Kim 2530ea7cd592SNamhyung Kim static int 2531ea7cd592SNamhyung Kim add_exit_opt(struct hist_browser *browser __maybe_unused, 2532ea7cd592SNamhyung Kim struct popup_action *act, char **optstr) 2533ea7cd592SNamhyung Kim { 2534ea7cd592SNamhyung Kim if (asprintf(optstr, "Exit") < 0) 2535ea7cd592SNamhyung Kim return 0; 2536ea7cd592SNamhyung Kim 2537ea7cd592SNamhyung Kim act->fn = do_exit_browser; 2538ea7cd592SNamhyung Kim return 1; 2539ea7cd592SNamhyung Kim } 2540ea7cd592SNamhyung Kim 254184734b06SKan Liang static int 254284734b06SKan Liang do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 254384734b06SKan Liang { 254435a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || act->socket < 0) 2545599a2f38SNamhyung Kim return 0; 2546599a2f38SNamhyung Kim 254784734b06SKan Liang if (browser->hists->socket_filter > -1) { 254884734b06SKan Liang pstack__remove(browser->pstack, &browser->hists->socket_filter); 254984734b06SKan Liang browser->hists->socket_filter = -1; 255084734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, false); 255184734b06SKan Liang } else { 255284734b06SKan Liang browser->hists->socket_filter = act->socket; 255384734b06SKan Liang perf_hpp__set_elide(HISTC_SOCKET, true); 255484734b06SKan Liang pstack__push(browser->pstack, &browser->hists->socket_filter); 255584734b06SKan Liang } 255684734b06SKan Liang 255784734b06SKan Liang hists__filter_by_socket(browser->hists); 255884734b06SKan Liang hist_browser__reset(browser); 255984734b06SKan Liang return 0; 256084734b06SKan Liang } 256184734b06SKan Liang 256284734b06SKan Liang static int 256384734b06SKan Liang add_socket_opt(struct hist_browser *browser, struct popup_action *act, 256484734b06SKan Liang char **optstr, int socket_id) 256584734b06SKan Liang { 256635a634f7SJiri Olsa if (!hists__has(browser->hists, socket) || socket_id < 0) 256784734b06SKan Liang return 0; 256884734b06SKan Liang 256984734b06SKan Liang if (asprintf(optstr, "Zoom %s Processor Socket %d", 257084734b06SKan Liang (browser->hists->socket_filter > -1) ? "out of" : "into", 257184734b06SKan Liang socket_id) < 0) 257284734b06SKan Liang return 0; 257384734b06SKan Liang 257484734b06SKan Liang act->socket = socket_id; 257584734b06SKan Liang act->fn = do_zoom_socket; 257684734b06SKan Liang return 1; 257784734b06SKan Liang } 257884734b06SKan Liang 2579112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb) 2580064f1981SNamhyung Kim { 2581064f1981SNamhyung Kim u64 nr_entries = 0; 2582064f1981SNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 2583064f1981SNamhyung Kim 2584f5b763feSNamhyung Kim if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) { 2585268397cbSNamhyung Kim hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 2586268397cbSNamhyung Kim return; 2587268397cbSNamhyung Kim } 2588268397cbSNamhyung Kim 258914135663SNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2590064f1981SNamhyung Kim nr_entries++; 2591f5b763feSNamhyung Kim nd = rb_hierarchy_next(nd); 2592064f1981SNamhyung Kim } 2593064f1981SNamhyung Kim 2594112f761fSNamhyung Kim hb->nr_non_filtered_entries = nr_entries; 2595f5b763feSNamhyung Kim hb->nr_hierarchy_entries = nr_entries; 2596064f1981SNamhyung Kim } 2597341487abSFeng Tang 2598b62e8dfcSNamhyung Kim static void hist_browser__update_percent_limit(struct hist_browser *hb, 2599b62e8dfcSNamhyung Kim double percent) 2600b62e8dfcSNamhyung Kim { 2601b62e8dfcSNamhyung Kim struct hist_entry *he; 2602b62e8dfcSNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 2603b62e8dfcSNamhyung Kim u64 total = hists__total_period(hb->hists); 2604b62e8dfcSNamhyung Kim u64 min_callchain_hits = total * (percent / 100); 2605b62e8dfcSNamhyung Kim 2606b62e8dfcSNamhyung Kim hb->min_pcnt = callchain_param.min_percent = percent; 2607b62e8dfcSNamhyung Kim 2608b62e8dfcSNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2609b62e8dfcSNamhyung Kim he = rb_entry(nd, struct hist_entry, rb_node); 2610b62e8dfcSNamhyung Kim 261179dded87SNamhyung Kim if (he->has_no_entry) { 261279dded87SNamhyung Kim he->has_no_entry = false; 261379dded87SNamhyung Kim he->nr_rows = 0; 261479dded87SNamhyung Kim } 261579dded87SNamhyung Kim 2616d0506edbSNamhyung Kim if (!he->leaf || !symbol_conf.use_callchain) 2617d0506edbSNamhyung Kim goto next; 2618d0506edbSNamhyung Kim 2619b62e8dfcSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) { 2620b62e8dfcSNamhyung Kim total = he->stat.period; 2621b62e8dfcSNamhyung Kim 2622b62e8dfcSNamhyung Kim if (symbol_conf.cumulate_callchain) 2623b62e8dfcSNamhyung Kim total = he->stat_acc->period; 2624b62e8dfcSNamhyung Kim 2625b62e8dfcSNamhyung Kim min_callchain_hits = total * (percent / 100); 2626b62e8dfcSNamhyung Kim } 2627b62e8dfcSNamhyung Kim 2628b62e8dfcSNamhyung Kim callchain_param.sort(&he->sorted_chain, he->callchain, 2629b62e8dfcSNamhyung Kim min_callchain_hits, &callchain_param); 2630b62e8dfcSNamhyung Kim 2631d0506edbSNamhyung Kim next: 2632201fde73SNamhyung Kim nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); 2633d0506edbSNamhyung Kim 2634b62e8dfcSNamhyung Kim /* force to re-evaluate folding state of callchains */ 2635b62e8dfcSNamhyung Kim he->init_have_children = false; 2636492b1010SNamhyung Kim hist_entry__set_folding(he, hb, false); 2637b62e8dfcSNamhyung Kim } 2638b62e8dfcSNamhyung Kim } 2639b62e8dfcSNamhyung Kim 2640aca7a94dSNamhyung Kim static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 2641dd00d486SJiri Olsa const char *helpline, 2642aca7a94dSNamhyung Kim bool left_exits, 264368d80758SNamhyung Kim struct hist_browser_timer *hbt, 2644064f1981SNamhyung Kim float min_pcnt, 2645ce80d3beSKan Liang struct perf_env *env) 2646aca7a94dSNamhyung Kim { 26474ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 2648b1a9ceefSNamhyung Kim struct hist_browser *browser = hist_browser__new(hists, hbt, env); 2649aca7a94dSNamhyung Kim struct branch_info *bi; 2650f2b487dbSNamhyung Kim #define MAX_OPTIONS 16 2651f2b487dbSNamhyung Kim char *options[MAX_OPTIONS]; 2652ea7cd592SNamhyung Kim struct popup_action actions[MAX_OPTIONS]; 2653aca7a94dSNamhyung Kim int nr_options = 0; 2654aca7a94dSNamhyung Kim int key = -1; 2655aca7a94dSNamhyung Kim char buf[64]; 26569783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 265759dc9f25SNamhyung Kim struct perf_hpp_fmt *fmt; 2658aca7a94dSNamhyung Kim 2659e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 2660e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 2661e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 2662e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 2663e8e684a5SNamhyung Kim "q/ESC/CTRL+C Exit browser\n\n" \ 2664e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 2665e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 2666e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 26677727a925SArnaldo Carvalho de Melo "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \ 26687727a925SArnaldo Carvalho de Melo "ESC Zoom out\n" \ 2669e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 2670e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 2671e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 2672e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 2673105eb30fSNamhyung Kim "F Toggle percentage of filtered entries\n" \ 2674025bf7eaSArnaldo Carvalho de Melo "H Display column headers\n" \ 2675b62e8dfcSNamhyung Kim "L Change percent limit\n" \ 267631eb4360SNamhyung Kim "m Display context menu\n" \ 267784734b06SKan Liang "S Zoom into current Processor Socket\n" \ 2678e8e684a5SNamhyung Kim 2679e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 2680e8e684a5SNamhyung Kim const char report_help[] = HIST_BROWSER_HELP_COMMON 26816dd60135SNamhyung Kim "i Show header information\n" 2682e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2683e8e684a5SNamhyung Kim "r Run available scripts\n" 2684e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 2685e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2686e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 2687e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2688e8e684a5SNamhyung Kim const char top_help[] = HIST_BROWSER_HELP_COMMON 2689e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 2690e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 2691e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 269242337a22SNamhyung Kim "z Toggle zeroing of samples\n" 2693fbb7997eSArnaldo Carvalho de Melo "f Enable/Disable events\n" 2694e8e684a5SNamhyung Kim "/ Filter symbol by name"; 2695e8e684a5SNamhyung Kim 2696aca7a94dSNamhyung Kim if (browser == NULL) 2697aca7a94dSNamhyung Kim return -1; 2698aca7a94dSNamhyung Kim 2699ed426915SNamhyung Kim /* reset abort key so that it can get Ctrl-C as a key */ 2700ed426915SNamhyung Kim SLang_reset_tty(); 2701ed426915SNamhyung Kim SLang_init_tty(0, 0, 0); 2702ed426915SNamhyung Kim 270303905048SNamhyung Kim if (min_pcnt) 2704064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 2705112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 2706064f1981SNamhyung Kim 270784734b06SKan Liang browser->pstack = pstack__new(3); 270801f00a1cSNamhyung Kim if (browser->pstack == NULL) 2709aca7a94dSNamhyung Kim goto out; 2710aca7a94dSNamhyung Kim 2711aca7a94dSNamhyung Kim ui_helpline__push(helpline); 2712aca7a94dSNamhyung Kim 2713aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 2714ea7cd592SNamhyung Kim memset(actions, 0, sizeof(actions)); 2715aca7a94dSNamhyung Kim 2716f0786af5SJiri Olsa hists__for_each_format(browser->hists, fmt) { 271759dc9f25SNamhyung Kim perf_hpp__reset_width(fmt, hists); 2718c6c3c02dSArnaldo Carvalho de Melo /* 2719c6c3c02dSArnaldo Carvalho de Melo * This is done just once, and activates the horizontal scrolling 2720c6c3c02dSArnaldo Carvalho de Melo * code in the ui_browser code, it would be better to have a the 2721c6c3c02dSArnaldo Carvalho de Melo * counter in the perf_hpp code, but I couldn't find doing it here 2722c6c3c02dSArnaldo Carvalho de Melo * works, FIXME by setting this in hist_browser__new, for now, be 2723c6c3c02dSArnaldo Carvalho de Melo * clever 8-) 2724c6c3c02dSArnaldo Carvalho de Melo */ 2725c6c3c02dSArnaldo Carvalho de Melo ++browser->b.columns; 2726c6c3c02dSArnaldo Carvalho de Melo } 272759dc9f25SNamhyung Kim 27285b591669SNamhyung Kim if (symbol_conf.col_width_list_str) 27295b591669SNamhyung Kim perf_hpp__set_user_width(symbol_conf.col_width_list_str); 27305b591669SNamhyung Kim 2731aca7a94dSNamhyung Kim while (1) { 2732f3b623b8SArnaldo Carvalho de Melo struct thread *thread = NULL; 2733045b80ddSArnaldo Carvalho de Melo struct map *map = NULL; 2734ea7cd592SNamhyung Kim int choice = 0; 273584734b06SKan Liang int socked_id = -1; 2736aca7a94dSNamhyung Kim 2737aca7a94dSNamhyung Kim nr_options = 0; 2738aca7a94dSNamhyung Kim 27395f00b0f4SArnaldo Carvalho de Melo key = hist_browser__run(browser, helpline); 2740aca7a94dSNamhyung Kim 2741aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 2742aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 2743045b80ddSArnaldo Carvalho de Melo map = browser->selection->map; 274484734b06SKan Liang socked_id = browser->he_selection->socket; 2745aca7a94dSNamhyung Kim } 2746aca7a94dSNamhyung Kim switch (key) { 2747aca7a94dSNamhyung Kim case K_TAB: 2748aca7a94dSNamhyung Kim case K_UNTAB: 2749aca7a94dSNamhyung Kim if (nr_events == 1) 2750aca7a94dSNamhyung Kim continue; 2751aca7a94dSNamhyung Kim /* 2752aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 2753aca7a94dSNamhyung Kim * go to the next or previous 2754aca7a94dSNamhyung Kim */ 2755aca7a94dSNamhyung Kim goto out_free_stack; 2756aca7a94dSNamhyung Kim case 'a': 27572e0453afSJiri Olsa if (!hists__has(hists, sym)) { 2758aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 2759aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 2760aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 2761aca7a94dSNamhyung Kim continue; 2762aca7a94dSNamhyung Kim } 2763aca7a94dSNamhyung Kim 2764aca7a94dSNamhyung Kim if (browser->selection == NULL || 2765aca7a94dSNamhyung Kim browser->selection->sym == NULL || 2766aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 2767aca7a94dSNamhyung Kim continue; 2768bc7cad42SNamhyung Kim 2769ea7cd592SNamhyung Kim actions->ms.map = browser->selection->map; 2770ea7cd592SNamhyung Kim actions->ms.sym = browser->selection->sym; 2771ea7cd592SNamhyung Kim do_annotate(browser, actions); 2772bc7cad42SNamhyung Kim continue; 2773aff3f3f6SArnaldo Carvalho de Melo case 'P': 2774aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 2775aff3f3f6SArnaldo Carvalho de Melo continue; 2776aca7a94dSNamhyung Kim case 'd': 2777fae00650SArnaldo Carvalho de Melo actions->ms.map = map; 2778ea7cd592SNamhyung Kim do_zoom_dso(browser, actions); 2779bc7cad42SNamhyung Kim continue; 2780a7cb8863SArnaldo Carvalho de Melo case 'V': 2781a7cb8863SArnaldo Carvalho de Melo browser->show_dso = !browser->show_dso; 2782a7cb8863SArnaldo Carvalho de Melo continue; 2783aca7a94dSNamhyung Kim case 't': 2784ea7cd592SNamhyung Kim actions->thread = thread; 2785ea7cd592SNamhyung Kim do_zoom_thread(browser, actions); 2786bc7cad42SNamhyung Kim continue; 278784734b06SKan Liang case 'S': 278884734b06SKan Liang actions->socket = socked_id; 278984734b06SKan Liang do_zoom_socket(browser, actions); 279084734b06SKan Liang continue; 27915a5626b1SArnaldo Carvalho de Melo case '/': 2792aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 27934aa8e454SArnaldo Carvalho de Melo "Please enter the name of symbol you want to see.\n" 27944aa8e454SArnaldo Carvalho de Melo "To remove the filter later, press / + ENTER.", 2795aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 2796aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 279705e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 279805e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 2799aca7a94dSNamhyung Kim hist_browser__reset(browser); 2800aca7a94dSNamhyung Kim } 2801aca7a94dSNamhyung Kim continue; 2802cdbab7c2SFeng Tang case 'r': 2803ea7cd592SNamhyung Kim if (is_report_browser(hbt)) { 2804ea7cd592SNamhyung Kim actions->thread = NULL; 2805ea7cd592SNamhyung Kim actions->ms.sym = NULL; 2806ea7cd592SNamhyung Kim do_run_script(browser, actions); 2807ea7cd592SNamhyung Kim } 2808c77d8d70SFeng Tang continue; 2809341487abSFeng Tang case 's': 2810bc7cad42SNamhyung Kim if (is_report_browser(hbt)) { 2811ea7cd592SNamhyung Kim key = do_switch_data(browser, actions); 2812bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 2813bc7cad42SNamhyung Kim goto out_free_stack; 2814bc7cad42SNamhyung Kim } 2815341487abSFeng Tang continue; 28166dd60135SNamhyung Kim case 'i': 28176dd60135SNamhyung Kim /* env->arch is NULL for live-mode (i.e. perf top) */ 28186dd60135SNamhyung Kim if (env->arch) 28196dd60135SNamhyung Kim tui__header_window(env); 28206dd60135SNamhyung Kim continue; 2821105eb30fSNamhyung Kim case 'F': 2822105eb30fSNamhyung Kim symbol_conf.filter_relative ^= 1; 2823105eb30fSNamhyung Kim continue; 282442337a22SNamhyung Kim case 'z': 282542337a22SNamhyung Kim if (!is_report_browser(hbt)) { 282642337a22SNamhyung Kim struct perf_top *top = hbt->arg; 282742337a22SNamhyung Kim 282842337a22SNamhyung Kim top->zero = !top->zero; 282942337a22SNamhyung Kim } 283042337a22SNamhyung Kim continue; 2831b62e8dfcSNamhyung Kim case 'L': 2832b62e8dfcSNamhyung Kim if (ui_browser__input_window("Percent Limit", 2833b62e8dfcSNamhyung Kim "Please enter the value you want to hide entries under that percent.", 2834b62e8dfcSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 2835b62e8dfcSNamhyung Kim delay_secs * 2) == K_ENTER) { 2836b62e8dfcSNamhyung Kim char *end; 2837b62e8dfcSNamhyung Kim double new_percent = strtod(buf, &end); 2838b62e8dfcSNamhyung Kim 2839b62e8dfcSNamhyung Kim if (new_percent < 0 || new_percent > 100) { 2840b62e8dfcSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 2841b62e8dfcSNamhyung Kim "Invalid percent: %.2f", new_percent); 2842b62e8dfcSNamhyung Kim continue; 2843b62e8dfcSNamhyung Kim } 2844b62e8dfcSNamhyung Kim 2845b62e8dfcSNamhyung Kim hist_browser__update_percent_limit(browser, new_percent); 2846b62e8dfcSNamhyung Kim hist_browser__reset(browser); 2847b62e8dfcSNamhyung Kim } 2848b62e8dfcSNamhyung Kim continue; 2849aca7a94dSNamhyung Kim case K_F1: 2850aca7a94dSNamhyung Kim case 'h': 2851aca7a94dSNamhyung Kim case '?': 2852aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 2853e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 2854aca7a94dSNamhyung Kim continue; 2855aca7a94dSNamhyung Kim case K_ENTER: 2856aca7a94dSNamhyung Kim case K_RIGHT: 285731eb4360SNamhyung Kim case 'm': 2858aca7a94dSNamhyung Kim /* menu */ 2859aca7a94dSNamhyung Kim break; 286063ab1749SArnaldo Carvalho de Melo case K_ESC: 2861aca7a94dSNamhyung Kim case K_LEFT: { 2862aca7a94dSNamhyung Kim const void *top; 2863aca7a94dSNamhyung Kim 286401f00a1cSNamhyung Kim if (pstack__empty(browser->pstack)) { 2865aca7a94dSNamhyung Kim /* 2866aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 2867aca7a94dSNamhyung Kim */ 2868aca7a94dSNamhyung Kim if (left_exits) 2869aca7a94dSNamhyung Kim goto out_free_stack; 287063ab1749SArnaldo Carvalho de Melo 287163ab1749SArnaldo Carvalho de Melo if (key == K_ESC && 287263ab1749SArnaldo Carvalho de Melo ui_browser__dialog_yesno(&browser->b, 287363ab1749SArnaldo Carvalho de Melo "Do you really want to exit?")) 287463ab1749SArnaldo Carvalho de Melo goto out_free_stack; 287563ab1749SArnaldo Carvalho de Melo 2876aca7a94dSNamhyung Kim continue; 2877aca7a94dSNamhyung Kim } 28786422184bSNamhyung Kim top = pstack__peek(browser->pstack); 2879bc7cad42SNamhyung Kim if (top == &browser->hists->dso_filter) { 28806422184bSNamhyung Kim /* 28816422184bSNamhyung Kim * No need to set actions->dso here since 28826422184bSNamhyung Kim * it's just to remove the current filter. 28836422184bSNamhyung Kim * Ditto for thread below. 28846422184bSNamhyung Kim */ 28856422184bSNamhyung Kim do_zoom_dso(browser, actions); 288684734b06SKan Liang } else if (top == &browser->hists->thread_filter) { 28876422184bSNamhyung Kim do_zoom_thread(browser, actions); 288884734b06SKan Liang } else if (top == &browser->hists->socket_filter) { 288984734b06SKan Liang do_zoom_socket(browser, actions); 289084734b06SKan Liang } 2891aca7a94dSNamhyung Kim continue; 2892aca7a94dSNamhyung Kim } 2893aca7a94dSNamhyung Kim case 'q': 2894aca7a94dSNamhyung Kim case CTRL('c'): 2895516e5368SArnaldo Carvalho de Melo goto out_free_stack; 2896fbb7997eSArnaldo Carvalho de Melo case 'f': 289713d1e536SNamhyung Kim if (!is_report_browser(hbt)) { 289813d1e536SNamhyung Kim struct perf_top *top = hbt->arg; 289913d1e536SNamhyung Kim 290013d1e536SNamhyung Kim perf_evlist__toggle_enable(top->evlist); 290113d1e536SNamhyung Kim /* 290213d1e536SNamhyung Kim * No need to refresh, resort/decay histogram 290313d1e536SNamhyung Kim * entries if we are not collecting samples: 290413d1e536SNamhyung Kim */ 290513d1e536SNamhyung Kim if (top->evlist->enabled) { 290613d1e536SNamhyung Kim helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; 290713d1e536SNamhyung Kim hbt->refresh = delay_secs; 290813d1e536SNamhyung Kim } else { 290913d1e536SNamhyung Kim helpline = "Press 'f' again to re-enable the events"; 291013d1e536SNamhyung Kim hbt->refresh = 0; 291113d1e536SNamhyung Kim } 291213d1e536SNamhyung Kim continue; 291313d1e536SNamhyung Kim } 29143e323dc0SArnaldo Carvalho de Melo /* Fall thru */ 2915aca7a94dSNamhyung Kim default: 29163e323dc0SArnaldo Carvalho de Melo helpline = "Press '?' for help on key bindings"; 2917aca7a94dSNamhyung Kim continue; 2918aca7a94dSNamhyung Kim } 2919aca7a94dSNamhyung Kim 29202e0453afSJiri Olsa if (!hists__has(hists, sym) || browser->selection == NULL) 29210ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 29220ba332f7SArnaldo Carvalho de Melo 292355369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 2924aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 29250ba332f7SArnaldo Carvalho de Melo 29260ba332f7SArnaldo Carvalho de Melo if (bi == NULL) 29270ba332f7SArnaldo Carvalho de Melo goto skip_annotation; 29280ba332f7SArnaldo Carvalho de Melo 2929ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2930ea7cd592SNamhyung Kim &actions[nr_options], 2931ea7cd592SNamhyung Kim &options[nr_options], 2932ea7cd592SNamhyung Kim bi->from.map, 2933ea7cd592SNamhyung Kim bi->from.sym); 2934ea7cd592SNamhyung Kim if (bi->to.sym != bi->from.sym) 2935ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2936ea7cd592SNamhyung Kim &actions[nr_options], 2937ea7cd592SNamhyung Kim &options[nr_options], 2938ea7cd592SNamhyung Kim bi->to.map, 2939ea7cd592SNamhyung Kim bi->to.sym); 2940aca7a94dSNamhyung Kim } else { 2941ea7cd592SNamhyung Kim nr_options += add_annotate_opt(browser, 2942ea7cd592SNamhyung Kim &actions[nr_options], 2943ea7cd592SNamhyung Kim &options[nr_options], 2944ea7cd592SNamhyung Kim browser->selection->map, 2945ea7cd592SNamhyung Kim browser->selection->sym); 2946446fb96cSArnaldo Carvalho de Melo } 29470ba332f7SArnaldo Carvalho de Melo skip_annotation: 2948ea7cd592SNamhyung Kim nr_options += add_thread_opt(browser, &actions[nr_options], 2949ea7cd592SNamhyung Kim &options[nr_options], thread); 2950ea7cd592SNamhyung Kim nr_options += add_dso_opt(browser, &actions[nr_options], 2951045b80ddSArnaldo Carvalho de Melo &options[nr_options], map); 2952ea7cd592SNamhyung Kim nr_options += add_map_opt(browser, &actions[nr_options], 2953ea7cd592SNamhyung Kim &options[nr_options], 2954bd315aabSWang Nan browser->selection ? 2955bd315aabSWang Nan browser->selection->map : NULL); 295684734b06SKan Liang nr_options += add_socket_opt(browser, &actions[nr_options], 295784734b06SKan Liang &options[nr_options], 295884734b06SKan Liang socked_id); 2959cdbab7c2SFeng Tang /* perf script support */ 2960b1baae89SNamhyung Kim if (!is_report_browser(hbt)) 2961b1baae89SNamhyung Kim goto skip_scripting; 2962b1baae89SNamhyung Kim 2963cdbab7c2SFeng Tang if (browser->he_selection) { 2964fa82911aSJiri Olsa if (hists__has(hists, thread) && thread) { 2965ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 2966ea7cd592SNamhyung Kim &actions[nr_options], 2967ea7cd592SNamhyung Kim &options[nr_options], 2968ea7cd592SNamhyung Kim thread, NULL); 29692eafd410SNamhyung Kim } 2970bd315aabSWang Nan /* 2971bd315aabSWang Nan * Note that browser->selection != NULL 2972bd315aabSWang Nan * when browser->he_selection is not NULL, 2973bd315aabSWang Nan * so we don't need to check browser->selection 2974bd315aabSWang Nan * before fetching browser->selection->sym like what 2975bd315aabSWang Nan * we do before fetching browser->selection->map. 2976bd315aabSWang Nan * 2977bd315aabSWang Nan * See hist_browser__show_entry. 2978bd315aabSWang Nan */ 29792e0453afSJiri Olsa if (hists__has(hists, sym) && browser->selection->sym) { 2980ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, 2981ea7cd592SNamhyung Kim &actions[nr_options], 2982ea7cd592SNamhyung Kim &options[nr_options], 2983ea7cd592SNamhyung Kim NULL, browser->selection->sym); 2984cdbab7c2SFeng Tang } 2985c221acb0SNamhyung Kim } 2986ea7cd592SNamhyung Kim nr_options += add_script_opt(browser, &actions[nr_options], 2987ea7cd592SNamhyung Kim &options[nr_options], NULL, NULL); 2988ea7cd592SNamhyung Kim nr_options += add_switch_opt(browser, &actions[nr_options], 2989ea7cd592SNamhyung Kim &options[nr_options]); 2990b1baae89SNamhyung Kim skip_scripting: 2991ea7cd592SNamhyung Kim nr_options += add_exit_opt(browser, &actions[nr_options], 2992ea7cd592SNamhyung Kim &options[nr_options]); 2993aca7a94dSNamhyung Kim 2994ea7cd592SNamhyung Kim do { 2995ea7cd592SNamhyung Kim struct popup_action *act; 2996ea7cd592SNamhyung Kim 2997ea7cd592SNamhyung Kim choice = ui__popup_menu(nr_options, options); 2998ea7cd592SNamhyung Kim if (choice == -1 || choice >= nr_options) 2999aca7a94dSNamhyung Kim break; 3000aca7a94dSNamhyung Kim 3001ea7cd592SNamhyung Kim act = &actions[choice]; 3002ea7cd592SNamhyung Kim key = act->fn(browser, act); 3003ea7cd592SNamhyung Kim } while (key == 1); 3004aca7a94dSNamhyung Kim 3005bc7cad42SNamhyung Kim if (key == K_SWITCH_INPUT_DATA) 3006341487abSFeng Tang break; 3007341487abSFeng Tang } 3008aca7a94dSNamhyung Kim out_free_stack: 300901f00a1cSNamhyung Kim pstack__delete(browser->pstack); 3010aca7a94dSNamhyung Kim out: 3011aca7a94dSNamhyung Kim hist_browser__delete(browser); 3012f2b487dbSNamhyung Kim free_popup_options(options, MAX_OPTIONS); 3013aca7a94dSNamhyung Kim return key; 3014aca7a94dSNamhyung Kim } 3015aca7a94dSNamhyung Kim 3016aca7a94dSNamhyung Kim struct perf_evsel_menu { 3017aca7a94dSNamhyung Kim struct ui_browser b; 3018aca7a94dSNamhyung Kim struct perf_evsel *selection; 3019aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 3020064f1981SNamhyung Kim float min_pcnt; 3021ce80d3beSKan Liang struct perf_env *env; 3022aca7a94dSNamhyung Kim }; 3023aca7a94dSNamhyung Kim 3024aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 3025aca7a94dSNamhyung Kim void *entry, int row) 3026aca7a94dSNamhyung Kim { 3027aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 3028aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 3029aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 30304ea062edSArnaldo Carvalho de Melo struct hists *hists = evsel__hists(evsel); 3031aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 30324ea062edSArnaldo Carvalho de Melo unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 30337289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 3034aca7a94dSNamhyung Kim char bf[256], unit; 3035aca7a94dSNamhyung Kim const char *warn = " "; 3036aca7a94dSNamhyung Kim size_t printed; 3037aca7a94dSNamhyung Kim 3038aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 3039aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 3040aca7a94dSNamhyung Kim 3041759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 3042717e263fSNamhyung Kim struct perf_evsel *pos; 3043717e263fSNamhyung Kim 3044717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 3045717e263fSNamhyung Kim 3046717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 30474ea062edSArnaldo Carvalho de Melo struct hists *pos_hists = evsel__hists(pos); 30484ea062edSArnaldo Carvalho de Melo nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; 3049717e263fSNamhyung Kim } 3050717e263fSNamhyung Kim } 3051717e263fSNamhyung Kim 3052aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3053aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 3054aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 3055517dfdb3SArnaldo Carvalho de Melo ui_browser__printf(browser, "%s", bf); 3056aca7a94dSNamhyung Kim 30574ea062edSArnaldo Carvalho de Melo nr_events = hists->stats.nr_events[PERF_RECORD_LOST]; 3058aca7a94dSNamhyung Kim if (nr_events != 0) { 3059aca7a94dSNamhyung Kim menu->lost_events = true; 3060aca7a94dSNamhyung Kim if (!current_entry) 3061aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 3062aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 3063aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 3064aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 3065aca7a94dSNamhyung Kim warn = bf; 3066aca7a94dSNamhyung Kim } 3067aca7a94dSNamhyung Kim 306826270a00SArnaldo Carvalho de Melo ui_browser__write_nstring(browser, warn, browser->width - printed); 3069aca7a94dSNamhyung Kim 3070aca7a94dSNamhyung Kim if (current_entry) 3071aca7a94dSNamhyung Kim menu->selection = evsel; 3072aca7a94dSNamhyung Kim } 3073aca7a94dSNamhyung Kim 3074aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 3075aca7a94dSNamhyung Kim int nr_events, const char *help, 30769783adf7SNamhyung Kim struct hist_browser_timer *hbt) 3077aca7a94dSNamhyung Kim { 3078aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 3079aca7a94dSNamhyung Kim struct perf_evsel *pos; 3080dd00d486SJiri Olsa const char *title = "Available samples"; 30819783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 3082aca7a94dSNamhyung Kim int key; 3083aca7a94dSNamhyung Kim 3084aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 3085aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 3086aca7a94dSNamhyung Kim return -1; 3087aca7a94dSNamhyung Kim 3088aca7a94dSNamhyung Kim while (1) { 3089aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 3090aca7a94dSNamhyung Kim 3091aca7a94dSNamhyung Kim switch (key) { 3092aca7a94dSNamhyung Kim case K_TIMER: 30939783adf7SNamhyung Kim hbt->timer(hbt->arg); 3094aca7a94dSNamhyung Kim 3095aca7a94dSNamhyung Kim if (!menu->lost_events_warned && menu->lost_events) { 3096aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 3097aca7a94dSNamhyung Kim menu->lost_events_warned = true; 3098aca7a94dSNamhyung Kim } 3099aca7a94dSNamhyung Kim continue; 3100aca7a94dSNamhyung Kim case K_RIGHT: 3101aca7a94dSNamhyung Kim case K_ENTER: 3102aca7a94dSNamhyung Kim if (!menu->selection) 3103aca7a94dSNamhyung Kim continue; 3104aca7a94dSNamhyung Kim pos = menu->selection; 3105aca7a94dSNamhyung Kim browse_hists: 3106aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 3107aca7a94dSNamhyung Kim /* 3108aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 3109aca7a94dSNamhyung Kim * default evsel resorted hists tree. 3110aca7a94dSNamhyung Kim */ 31119783adf7SNamhyung Kim if (hbt) 31129783adf7SNamhyung Kim hbt->timer(hbt->arg); 3113aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 3114dd00d486SJiri Olsa true, hbt, 3115064f1981SNamhyung Kim menu->min_pcnt, 311668d80758SNamhyung Kim menu->env); 3117aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 3118aca7a94dSNamhyung Kim switch (key) { 3119aca7a94dSNamhyung Kim case K_TAB: 3120aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 31219a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__first(evlist); 3122aca7a94dSNamhyung Kim else 31239a354cdcSArnaldo Carvalho de Melo pos = perf_evsel__next(pos); 3124aca7a94dSNamhyung Kim goto browse_hists; 3125aca7a94dSNamhyung Kim case K_UNTAB: 3126aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 31279a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__last(evlist); 3128aca7a94dSNamhyung Kim else 3129d87fcb4aSArnaldo Carvalho de Melo pos = perf_evsel__prev(pos); 3130aca7a94dSNamhyung Kim goto browse_hists; 3131341487abSFeng Tang case K_SWITCH_INPUT_DATA: 3132aca7a94dSNamhyung Kim case 'q': 3133aca7a94dSNamhyung Kim case CTRL('c'): 3134aca7a94dSNamhyung Kim goto out; 313563ab1749SArnaldo Carvalho de Melo case K_ESC: 3136aca7a94dSNamhyung Kim default: 3137aca7a94dSNamhyung Kim continue; 3138aca7a94dSNamhyung Kim } 3139aca7a94dSNamhyung Kim case K_LEFT: 3140aca7a94dSNamhyung Kim continue; 3141aca7a94dSNamhyung Kim case K_ESC: 3142aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 3143aca7a94dSNamhyung Kim "Do you really want to exit?")) 3144aca7a94dSNamhyung Kim continue; 3145aca7a94dSNamhyung Kim /* Fall thru */ 3146aca7a94dSNamhyung Kim case 'q': 3147aca7a94dSNamhyung Kim case CTRL('c'): 3148aca7a94dSNamhyung Kim goto out; 3149aca7a94dSNamhyung Kim default: 3150aca7a94dSNamhyung Kim continue; 3151aca7a94dSNamhyung Kim } 3152aca7a94dSNamhyung Kim } 3153aca7a94dSNamhyung Kim 3154aca7a94dSNamhyung Kim out: 3155aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 3156aca7a94dSNamhyung Kim return key; 3157aca7a94dSNamhyung Kim } 3158aca7a94dSNamhyung Kim 3159316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 3160fc24d7c2SNamhyung Kim void *entry) 3161fc24d7c2SNamhyung Kim { 3162fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 3163fc24d7c2SNamhyung Kim 3164fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 3165fc24d7c2SNamhyung Kim return true; 3166fc24d7c2SNamhyung Kim 3167fc24d7c2SNamhyung Kim return false; 3168fc24d7c2SNamhyung Kim } 3169fc24d7c2SNamhyung Kim 3170aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 3171fc24d7c2SNamhyung Kim int nr_entries, const char *help, 317268d80758SNamhyung Kim struct hist_browser_timer *hbt, 3173064f1981SNamhyung Kim float min_pcnt, 3174ce80d3beSKan Liang struct perf_env *env) 3175aca7a94dSNamhyung Kim { 3176aca7a94dSNamhyung Kim struct perf_evsel *pos; 3177aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 3178aca7a94dSNamhyung Kim .b = { 3179aca7a94dSNamhyung Kim .entries = &evlist->entries, 3180aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 3181aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 3182aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 3183fc24d7c2SNamhyung Kim .filter = filter_group_entries, 3184fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 3185aca7a94dSNamhyung Kim .priv = evlist, 3186aca7a94dSNamhyung Kim }, 3187064f1981SNamhyung Kim .min_pcnt = min_pcnt, 318868d80758SNamhyung Kim .env = env, 3189aca7a94dSNamhyung Kim }; 3190aca7a94dSNamhyung Kim 3191aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 3192aca7a94dSNamhyung Kim 31930050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 31947289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 3195aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 3196aca7a94dSNamhyung Kim 3197aca7a94dSNamhyung Kim if (menu.b.width < line_len) 3198aca7a94dSNamhyung Kim menu.b.width = line_len; 3199aca7a94dSNamhyung Kim } 3200aca7a94dSNamhyung Kim 3201fc24d7c2SNamhyung Kim return perf_evsel_menu__run(&menu, nr_entries, help, hbt); 3202aca7a94dSNamhyung Kim } 3203aca7a94dSNamhyung Kim 3204aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 320568d80758SNamhyung Kim struct hist_browser_timer *hbt, 3206064f1981SNamhyung Kim float min_pcnt, 3207ce80d3beSKan Liang struct perf_env *env) 3208aca7a94dSNamhyung Kim { 3209fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 3210fc24d7c2SNamhyung Kim 3211fc24d7c2SNamhyung Kim single_entry: 3212fc24d7c2SNamhyung Kim if (nr_entries == 1) { 32139a354cdcSArnaldo Carvalho de Melo struct perf_evsel *first = perf_evlist__first(evlist); 3214fc24d7c2SNamhyung Kim 3215fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 3216dd00d486SJiri Olsa false, hbt, min_pcnt, 3217064f1981SNamhyung Kim env); 3218aca7a94dSNamhyung Kim } 3219aca7a94dSNamhyung Kim 3220fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 3221fc24d7c2SNamhyung Kim struct perf_evsel *pos; 3222fc24d7c2SNamhyung Kim 3223fc24d7c2SNamhyung Kim nr_entries = 0; 32240050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 3225fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 3226fc24d7c2SNamhyung Kim nr_entries++; 32270050f7aaSArnaldo Carvalho de Melo } 3228fc24d7c2SNamhyung Kim 3229fc24d7c2SNamhyung Kim if (nr_entries == 1) 3230fc24d7c2SNamhyung Kim goto single_entry; 3231fc24d7c2SNamhyung Kim } 3232fc24d7c2SNamhyung Kim 3233fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 3234064f1981SNamhyung Kim hbt, min_pcnt, env); 3235aca7a94dSNamhyung Kim } 3236