1aca7a94dSNamhyung Kim #include <stdio.h> 2aca7a94dSNamhyung Kim #include "../libslang.h" 3aca7a94dSNamhyung Kim #include <stdlib.h> 4aca7a94dSNamhyung Kim #include <string.h> 5aca7a94dSNamhyung Kim #include <linux/rbtree.h> 6aca7a94dSNamhyung Kim 7aca7a94dSNamhyung Kim #include "../../util/evsel.h" 8aca7a94dSNamhyung Kim #include "../../util/evlist.h" 9aca7a94dSNamhyung Kim #include "../../util/hist.h" 10aca7a94dSNamhyung Kim #include "../../util/pstack.h" 11aca7a94dSNamhyung Kim #include "../../util/sort.h" 12aca7a94dSNamhyung Kim #include "../../util/util.h" 1368d80758SNamhyung Kim #include "../../arch/common.h" 14aca7a94dSNamhyung Kim 15aca7a94dSNamhyung Kim #include "../browser.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 22aca7a94dSNamhyung Kim struct hist_browser { 23aca7a94dSNamhyung Kim struct ui_browser b; 24aca7a94dSNamhyung Kim struct hists *hists; 25aca7a94dSNamhyung Kim struct hist_entry *he_selection; 26aca7a94dSNamhyung Kim struct map_symbol *selection; 27aff3f3f6SArnaldo Carvalho de Melo int print_seq; 28a7cb8863SArnaldo Carvalho de Melo bool show_dso; 29025bf7eaSArnaldo Carvalho de Melo bool show_headers; 30064f1981SNamhyung Kim float min_pcnt; 31112f761fSNamhyung Kim u64 nr_non_filtered_entries; 32c3b78952SNamhyung Kim u64 nr_callchain_rows; 33aca7a94dSNamhyung Kim }; 34aca7a94dSNamhyung Kim 35f5951d56SNamhyung Kim extern void hist_browser__init_hpp(void); 36f5951d56SNamhyung Kim 37dd00d486SJiri Olsa static int hists__browser_title(struct hists *hists, char *bf, size_t size); 38112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb); 39aca7a94dSNamhyung Kim 40c3b78952SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 41c3b78952SNamhyung Kim float min_pcnt); 42c3b78952SNamhyung Kim 43268397cbSNamhyung Kim static bool hist_browser__has_filter(struct hist_browser *hb) 44268397cbSNamhyung Kim { 45268397cbSNamhyung Kim return hists__has_filter(hb->hists) || hb->min_pcnt; 46268397cbSNamhyung Kim } 47268397cbSNamhyung Kim 48c3b78952SNamhyung Kim static u32 hist_browser__nr_entries(struct hist_browser *hb) 49c3b78952SNamhyung Kim { 50c3b78952SNamhyung Kim u32 nr_entries; 51c3b78952SNamhyung Kim 52c3b78952SNamhyung Kim if (hist_browser__has_filter(hb)) 53c3b78952SNamhyung Kim nr_entries = hb->nr_non_filtered_entries; 54c3b78952SNamhyung Kim else 55c3b78952SNamhyung Kim nr_entries = hb->hists->nr_entries; 56c3b78952SNamhyung Kim 57c3b78952SNamhyung Kim return nr_entries + hb->nr_callchain_rows; 58c3b78952SNamhyung Kim } 59c3b78952SNamhyung Kim 60025bf7eaSArnaldo Carvalho de Melo static void hist_browser__update_rows(struct hist_browser *hb) 61025bf7eaSArnaldo Carvalho de Melo { 62025bf7eaSArnaldo Carvalho de Melo struct ui_browser *browser = &hb->b; 63025bf7eaSArnaldo Carvalho de Melo u16 header_offset = hb->show_headers ? 1 : 0, index_row; 64025bf7eaSArnaldo Carvalho de Melo 65025bf7eaSArnaldo Carvalho de Melo browser->rows = browser->height - header_offset; 66025bf7eaSArnaldo Carvalho de Melo /* 67025bf7eaSArnaldo Carvalho de Melo * Verify if we were at the last line and that line isn't 68025bf7eaSArnaldo Carvalho de Melo * visibe because we now show the header line(s). 69025bf7eaSArnaldo Carvalho de Melo */ 70025bf7eaSArnaldo Carvalho de Melo index_row = browser->index - browser->top_idx; 71025bf7eaSArnaldo Carvalho de Melo if (index_row >= browser->rows) 72025bf7eaSArnaldo Carvalho de Melo browser->index -= index_row - browser->rows + 1; 73025bf7eaSArnaldo Carvalho de Melo } 74025bf7eaSArnaldo Carvalho de Melo 75357cfff1SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct ui_browser *browser) 76aca7a94dSNamhyung Kim { 77357cfff1SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 78357cfff1SArnaldo Carvalho de Melo 79aca7a94dSNamhyung Kim /* 3 == +/- toggle symbol before actual hist_entry rendering */ 80357cfff1SArnaldo Carvalho de Melo browser->width = 3 + (hists__sort_list_width(hb->hists) + sizeof("[k]")); 81357cfff1SArnaldo Carvalho de Melo /* 82357cfff1SArnaldo Carvalho de Melo * FIXME: Just keeping existing behaviour, but this really should be 83357cfff1SArnaldo Carvalho de Melo * before updating browser->width, as it will invalidate the 84357cfff1SArnaldo Carvalho de Melo * calculation above. Fix this and the fallout in another 85357cfff1SArnaldo Carvalho de Melo * changeset. 86357cfff1SArnaldo Carvalho de Melo */ 87357cfff1SArnaldo Carvalho de Melo ui_browser__refresh_dimensions(browser); 88025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(hb); 89aca7a94dSNamhyung Kim } 90aca7a94dSNamhyung Kim 91ca3ff33bSArnaldo Carvalho de Melo static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) 92ca3ff33bSArnaldo Carvalho de Melo { 93025bf7eaSArnaldo Carvalho de Melo u16 header_offset = browser->show_headers ? 1 : 0; 94025bf7eaSArnaldo Carvalho de Melo 95025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row + header_offset, column); 96ca3ff33bSArnaldo Carvalho de Melo } 97ca3ff33bSArnaldo Carvalho de Melo 9805e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser) 99aca7a94dSNamhyung Kim { 100c3b78952SNamhyung Kim /* 101c3b78952SNamhyung Kim * The hists__remove_entry_filter() already folds non-filtered 102c3b78952SNamhyung Kim * entries so we can assume it has 0 callchain rows. 103c3b78952SNamhyung Kim */ 104c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 105c3b78952SNamhyung Kim 106268397cbSNamhyung Kim hist_browser__update_nr_entries(browser); 107c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 108357cfff1SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(&browser->b); 10905e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 110aca7a94dSNamhyung Kim } 111aca7a94dSNamhyung Kim 112aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded) 113aca7a94dSNamhyung Kim { 114aca7a94dSNamhyung Kim return unfolded ? '-' : '+'; 115aca7a94dSNamhyung Kim } 116aca7a94dSNamhyung Kim 11705e8b080SArnaldo Carvalho de Melo static char map_symbol__folded(const struct map_symbol *ms) 118aca7a94dSNamhyung Kim { 11905e8b080SArnaldo Carvalho de Melo return ms->has_children ? tree__folded_sign(ms->unfolded) : ' '; 120aca7a94dSNamhyung Kim } 121aca7a94dSNamhyung Kim 12205e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he) 123aca7a94dSNamhyung Kim { 12405e8b080SArnaldo Carvalho de Melo return map_symbol__folded(&he->ms); 125aca7a94dSNamhyung Kim } 126aca7a94dSNamhyung Kim 12705e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl) 128aca7a94dSNamhyung Kim { 12905e8b080SArnaldo Carvalho de Melo return map_symbol__folded(&cl->ms); 130aca7a94dSNamhyung Kim } 131aca7a94dSNamhyung Kim 13205e8b080SArnaldo Carvalho de Melo static void map_symbol__set_folding(struct map_symbol *ms, bool unfold) 133aca7a94dSNamhyung Kim { 13405e8b080SArnaldo Carvalho de Melo ms->unfolded = unfold ? ms->has_children : false; 135aca7a94dSNamhyung Kim } 136aca7a94dSNamhyung Kim 13705e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 138aca7a94dSNamhyung Kim { 139aca7a94dSNamhyung Kim int n = 0; 140aca7a94dSNamhyung Kim struct rb_node *nd; 141aca7a94dSNamhyung Kim 14205e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 143aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 144aca7a94dSNamhyung Kim struct callchain_list *chain; 145aca7a94dSNamhyung Kim char folded_sign = ' '; /* No children */ 146aca7a94dSNamhyung Kim 147aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 148aca7a94dSNamhyung Kim ++n; 149aca7a94dSNamhyung Kim /* We need this because we may not have children */ 150aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 151aca7a94dSNamhyung Kim if (folded_sign == '+') 152aca7a94dSNamhyung Kim break; 153aca7a94dSNamhyung Kim } 154aca7a94dSNamhyung Kim 155aca7a94dSNamhyung Kim if (folded_sign == '-') /* Have children and they're unfolded */ 156aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(child); 157aca7a94dSNamhyung Kim } 158aca7a94dSNamhyung Kim 159aca7a94dSNamhyung Kim return n; 160aca7a94dSNamhyung Kim } 161aca7a94dSNamhyung Kim 162aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 163aca7a94dSNamhyung Kim { 164aca7a94dSNamhyung Kim struct callchain_list *chain; 165aca7a94dSNamhyung Kim bool unfolded = false; 166aca7a94dSNamhyung Kim int n = 0; 167aca7a94dSNamhyung Kim 168aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 169aca7a94dSNamhyung Kim ++n; 170aca7a94dSNamhyung Kim unfolded = chain->ms.unfolded; 171aca7a94dSNamhyung Kim } 172aca7a94dSNamhyung Kim 173aca7a94dSNamhyung Kim if (unfolded) 174aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 175aca7a94dSNamhyung Kim 176aca7a94dSNamhyung Kim return n; 177aca7a94dSNamhyung Kim } 178aca7a94dSNamhyung Kim 179aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 180aca7a94dSNamhyung Kim { 181aca7a94dSNamhyung Kim struct rb_node *nd; 182aca7a94dSNamhyung Kim int n = 0; 183aca7a94dSNamhyung Kim 184aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 185aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 186aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 187aca7a94dSNamhyung Kim } 188aca7a94dSNamhyung Kim 189aca7a94dSNamhyung Kim return n; 190aca7a94dSNamhyung Kim } 191aca7a94dSNamhyung Kim 19205e8b080SArnaldo Carvalho de Melo static bool map_symbol__toggle_fold(struct map_symbol *ms) 193aca7a94dSNamhyung Kim { 19405e8b080SArnaldo Carvalho de Melo if (!ms) 195aca7a94dSNamhyung Kim return false; 196aca7a94dSNamhyung Kim 19705e8b080SArnaldo Carvalho de Melo if (!ms->has_children) 198aca7a94dSNamhyung Kim return false; 199aca7a94dSNamhyung Kim 20005e8b080SArnaldo Carvalho de Melo ms->unfolded = !ms->unfolded; 201aca7a94dSNamhyung Kim return true; 202aca7a94dSNamhyung Kim } 203aca7a94dSNamhyung Kim 20405e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 205aca7a94dSNamhyung Kim { 20605e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 207aca7a94dSNamhyung Kim 20805e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 209aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 210aca7a94dSNamhyung Kim struct callchain_list *chain; 211aca7a94dSNamhyung Kim bool first = true; 212aca7a94dSNamhyung Kim 213aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 214aca7a94dSNamhyung Kim if (first) { 215aca7a94dSNamhyung Kim first = false; 216aca7a94dSNamhyung Kim chain->ms.has_children = chain->list.next != &child->val || 217aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 218aca7a94dSNamhyung Kim } else 219aca7a94dSNamhyung Kim chain->ms.has_children = chain->list.next == &child->val && 220aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 221aca7a94dSNamhyung Kim } 222aca7a94dSNamhyung Kim 223aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 224aca7a94dSNamhyung Kim } 225aca7a94dSNamhyung Kim } 226aca7a94dSNamhyung Kim 22705e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children(struct callchain_node *node) 228aca7a94dSNamhyung Kim { 229aca7a94dSNamhyung Kim struct callchain_list *chain; 230aca7a94dSNamhyung Kim 23105e8b080SArnaldo Carvalho de Melo list_for_each_entry(chain, &node->val, list) 23205e8b080SArnaldo Carvalho de Melo chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); 233aca7a94dSNamhyung Kim 23405e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 235aca7a94dSNamhyung Kim } 236aca7a94dSNamhyung Kim 23705e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 238aca7a94dSNamhyung Kim { 239aca7a94dSNamhyung Kim struct rb_node *nd; 240aca7a94dSNamhyung Kim 24105e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 242aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 243aca7a94dSNamhyung Kim callchain_node__init_have_children(node); 244aca7a94dSNamhyung Kim } 245aca7a94dSNamhyung Kim } 246aca7a94dSNamhyung Kim 24705e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 248aca7a94dSNamhyung Kim { 24905e8b080SArnaldo Carvalho de Melo if (!he->init_have_children) { 25005e8b080SArnaldo Carvalho de Melo he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 25105e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 25205e8b080SArnaldo Carvalho de Melo he->init_have_children = true; 253aca7a94dSNamhyung Kim } 254aca7a94dSNamhyung Kim } 255aca7a94dSNamhyung Kim 25605e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 257aca7a94dSNamhyung Kim { 25805e8b080SArnaldo Carvalho de Melo if (map_symbol__toggle_fold(browser->selection)) { 25905e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 260aca7a94dSNamhyung Kim 261aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 262c3b78952SNamhyung Kim browser->b.nr_entries -= he->nr_rows; 263c3b78952SNamhyung Kim browser->nr_callchain_rows -= he->nr_rows; 264aca7a94dSNamhyung Kim 265aca7a94dSNamhyung Kim if (he->ms.unfolded) 266aca7a94dSNamhyung Kim he->nr_rows = callchain__count_rows(&he->sorted_chain); 267aca7a94dSNamhyung Kim else 268aca7a94dSNamhyung Kim he->nr_rows = 0; 269c3b78952SNamhyung Kim 270c3b78952SNamhyung Kim browser->b.nr_entries += he->nr_rows; 271c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 272aca7a94dSNamhyung Kim 273aca7a94dSNamhyung Kim return true; 274aca7a94dSNamhyung Kim } 275aca7a94dSNamhyung Kim 276aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 277aca7a94dSNamhyung Kim return false; 278aca7a94dSNamhyung Kim } 279aca7a94dSNamhyung Kim 28005e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 281aca7a94dSNamhyung Kim { 282aca7a94dSNamhyung Kim int n = 0; 283aca7a94dSNamhyung Kim struct rb_node *nd; 284aca7a94dSNamhyung Kim 28505e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 286aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 287aca7a94dSNamhyung Kim struct callchain_list *chain; 288aca7a94dSNamhyung Kim bool has_children = false; 289aca7a94dSNamhyung Kim 290aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 291aca7a94dSNamhyung Kim ++n; 292aca7a94dSNamhyung Kim map_symbol__set_folding(&chain->ms, unfold); 293aca7a94dSNamhyung Kim has_children = chain->ms.has_children; 294aca7a94dSNamhyung Kim } 295aca7a94dSNamhyung Kim 296aca7a94dSNamhyung Kim if (has_children) 297aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 298aca7a94dSNamhyung Kim } 299aca7a94dSNamhyung Kim 300aca7a94dSNamhyung Kim return n; 301aca7a94dSNamhyung Kim } 302aca7a94dSNamhyung Kim 303aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 304aca7a94dSNamhyung Kim { 305aca7a94dSNamhyung Kim struct callchain_list *chain; 306aca7a94dSNamhyung Kim bool has_children = false; 307aca7a94dSNamhyung Kim int n = 0; 308aca7a94dSNamhyung Kim 309aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 310aca7a94dSNamhyung Kim ++n; 311aca7a94dSNamhyung Kim map_symbol__set_folding(&chain->ms, unfold); 312aca7a94dSNamhyung Kim has_children = chain->ms.has_children; 313aca7a94dSNamhyung Kim } 314aca7a94dSNamhyung Kim 315aca7a94dSNamhyung Kim if (has_children) 316aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 317aca7a94dSNamhyung Kim 318aca7a94dSNamhyung Kim return n; 319aca7a94dSNamhyung Kim } 320aca7a94dSNamhyung Kim 321aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 322aca7a94dSNamhyung Kim { 323aca7a94dSNamhyung Kim struct rb_node *nd; 324aca7a94dSNamhyung Kim int n = 0; 325aca7a94dSNamhyung Kim 326aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 327aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 328aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 329aca7a94dSNamhyung Kim } 330aca7a94dSNamhyung Kim 331aca7a94dSNamhyung Kim return n; 332aca7a94dSNamhyung Kim } 333aca7a94dSNamhyung Kim 33405e8b080SArnaldo Carvalho de Melo static void hist_entry__set_folding(struct hist_entry *he, bool unfold) 335aca7a94dSNamhyung Kim { 33605e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 33705e8b080SArnaldo Carvalho de Melo map_symbol__set_folding(&he->ms, unfold); 338aca7a94dSNamhyung Kim 33905e8b080SArnaldo Carvalho de Melo if (he->ms.has_children) { 34005e8b080SArnaldo Carvalho de Melo int n = callchain__set_folding(&he->sorted_chain, unfold); 34105e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 342aca7a94dSNamhyung Kim } else 34305e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 344aca7a94dSNamhyung Kim } 345aca7a94dSNamhyung Kim 346c3b78952SNamhyung Kim static void 347c3b78952SNamhyung Kim __hist_browser__set_folding(struct hist_browser *browser, bool unfold) 348aca7a94dSNamhyung Kim { 349aca7a94dSNamhyung Kim struct rb_node *nd; 350c3b78952SNamhyung Kim struct hists *hists = browser->hists; 351aca7a94dSNamhyung Kim 352c3b78952SNamhyung Kim for (nd = rb_first(&hists->entries); 35314135663SNamhyung Kim (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 354c3b78952SNamhyung Kim nd = rb_next(nd)) { 355aca7a94dSNamhyung Kim struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 356aca7a94dSNamhyung Kim hist_entry__set_folding(he, unfold); 357c3b78952SNamhyung Kim browser->nr_callchain_rows += he->nr_rows; 358aca7a94dSNamhyung Kim } 359aca7a94dSNamhyung Kim } 360aca7a94dSNamhyung Kim 36105e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 362aca7a94dSNamhyung Kim { 363c3b78952SNamhyung Kim browser->nr_callchain_rows = 0; 364c3b78952SNamhyung Kim __hist_browser__set_folding(browser, unfold); 365c3b78952SNamhyung Kim 366c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 367aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 36805e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 369aca7a94dSNamhyung Kim } 370aca7a94dSNamhyung Kim 371aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 372aca7a94dSNamhyung Kim { 373aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 374aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 375aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 376aca7a94dSNamhyung Kim " perf top -r 80\n\n" 377aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 378aca7a94dSNamhyung Kim } 379aca7a94dSNamhyung Kim 380dd00d486SJiri Olsa static int hist_browser__run(struct hist_browser *browser, 3819783adf7SNamhyung Kim struct hist_browser_timer *hbt) 382aca7a94dSNamhyung Kim { 383aca7a94dSNamhyung Kim int key; 384aca7a94dSNamhyung Kim char title[160]; 3859783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 386aca7a94dSNamhyung Kim 38705e8b080SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 388c3b78952SNamhyung Kim browser->b.nr_entries = hist_browser__nr_entries(browser); 389aca7a94dSNamhyung Kim 390dd00d486SJiri Olsa hists__browser_title(browser->hists, title, sizeof(title)); 391aca7a94dSNamhyung Kim 39205e8b080SArnaldo Carvalho de Melo if (ui_browser__show(&browser->b, title, 393aca7a94dSNamhyung Kim "Press '?' for help on key bindings") < 0) 394aca7a94dSNamhyung Kim return -1; 395aca7a94dSNamhyung Kim 396aca7a94dSNamhyung Kim while (1) { 39705e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 398aca7a94dSNamhyung Kim 399aca7a94dSNamhyung Kim switch (key) { 400fa5df943SNamhyung Kim case K_TIMER: { 401fa5df943SNamhyung Kim u64 nr_entries; 4029783adf7SNamhyung Kim hbt->timer(hbt->arg); 403fa5df943SNamhyung Kim 404c3b78952SNamhyung Kim if (hist_browser__has_filter(browser)) 405112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 406fa5df943SNamhyung Kim 407c3b78952SNamhyung Kim nr_entries = hist_browser__nr_entries(browser); 408fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 409aca7a94dSNamhyung Kim 41005e8b080SArnaldo Carvalho de Melo if (browser->hists->stats.nr_lost_warned != 41105e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]) { 41205e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 41305e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 41405e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 415aca7a94dSNamhyung Kim } 416aca7a94dSNamhyung Kim 417dd00d486SJiri Olsa hists__browser_title(browser->hists, title, sizeof(title)); 41805e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 419aca7a94dSNamhyung Kim continue; 420fa5df943SNamhyung Kim } 421aca7a94dSNamhyung Kim case 'D': { /* Debug */ 422aca7a94dSNamhyung Kim static int seq; 42305e8b080SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, 424aca7a94dSNamhyung Kim struct hist_entry, rb_node); 425aca7a94dSNamhyung Kim ui_helpline__pop(); 42662c95ae3SArnaldo Carvalho de Melo ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 42705e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 42805e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries, 42962c95ae3SArnaldo Carvalho de Melo browser->b.rows, 43005e8b080SArnaldo Carvalho de Melo browser->b.index, 43105e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 432aca7a94dSNamhyung Kim h->row_offset, h->nr_rows); 433aca7a94dSNamhyung Kim } 434aca7a94dSNamhyung Kim break; 435aca7a94dSNamhyung Kim case 'C': 436aca7a94dSNamhyung Kim /* Collapse the whole world. */ 43705e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 438aca7a94dSNamhyung Kim break; 439aca7a94dSNamhyung Kim case 'E': 440aca7a94dSNamhyung Kim /* Expand the whole world. */ 44105e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 442aca7a94dSNamhyung Kim break; 443025bf7eaSArnaldo Carvalho de Melo case 'H': 444025bf7eaSArnaldo Carvalho de Melo browser->show_headers = !browser->show_headers; 445025bf7eaSArnaldo Carvalho de Melo hist_browser__update_rows(browser); 446025bf7eaSArnaldo Carvalho de Melo break; 447aca7a94dSNamhyung Kim case K_ENTER: 44805e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 449aca7a94dSNamhyung Kim break; 450aca7a94dSNamhyung Kim /* fall thru */ 451aca7a94dSNamhyung Kim default: 452aca7a94dSNamhyung Kim goto out; 453aca7a94dSNamhyung Kim } 454aca7a94dSNamhyung Kim } 455aca7a94dSNamhyung Kim out: 45605e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 457aca7a94dSNamhyung Kim return key; 458aca7a94dSNamhyung Kim } 459aca7a94dSNamhyung Kim 46005e8b080SArnaldo Carvalho de Melo static char *callchain_list__sym_name(struct callchain_list *cl, 461a7cb8863SArnaldo Carvalho de Melo char *bf, size_t bfsize, bool show_dso) 462aca7a94dSNamhyung Kim { 463a7cb8863SArnaldo Carvalho de Melo int printed; 464aca7a94dSNamhyung Kim 465a7cb8863SArnaldo Carvalho de Melo if (cl->ms.sym) 466a7cb8863SArnaldo Carvalho de Melo printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name); 467a7cb8863SArnaldo Carvalho de Melo else 468a7cb8863SArnaldo Carvalho de Melo printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip); 469a7cb8863SArnaldo Carvalho de Melo 470a7cb8863SArnaldo Carvalho de Melo if (show_dso) 471a7cb8863SArnaldo Carvalho de Melo scnprintf(bf + printed, bfsize - printed, " %s", 472a7cb8863SArnaldo Carvalho de Melo cl->ms.map ? cl->ms.map->dso->short_name : "unknown"); 473a7cb8863SArnaldo Carvalho de Melo 474aca7a94dSNamhyung Kim return bf; 475aca7a94dSNamhyung Kim } 476aca7a94dSNamhyung Kim 477aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 478aca7a94dSNamhyung Kim 47905e8b080SArnaldo Carvalho de Melo static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser, 480aca7a94dSNamhyung Kim struct callchain_node *chain_node, 481aca7a94dSNamhyung Kim u64 total, int level, 482aca7a94dSNamhyung Kim unsigned short row, 483aca7a94dSNamhyung Kim off_t *row_offset, 484aca7a94dSNamhyung Kim bool *is_current_entry) 485aca7a94dSNamhyung Kim { 486aca7a94dSNamhyung Kim struct rb_node *node; 487aca7a94dSNamhyung Kim int first_row = row, width, offset = level * LEVEL_OFFSET_STEP; 488aca7a94dSNamhyung Kim u64 new_total, remaining; 489aca7a94dSNamhyung Kim 490aca7a94dSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 491aca7a94dSNamhyung Kim new_total = chain_node->children_hit; 492aca7a94dSNamhyung Kim else 493aca7a94dSNamhyung Kim new_total = total; 494aca7a94dSNamhyung Kim 495aca7a94dSNamhyung Kim remaining = new_total; 496aca7a94dSNamhyung Kim node = rb_first(&chain_node->rb_root); 497aca7a94dSNamhyung Kim while (node) { 498aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 499aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 500aca7a94dSNamhyung Kim u64 cumul = callchain_cumul_hits(child); 501aca7a94dSNamhyung Kim struct callchain_list *chain; 502aca7a94dSNamhyung Kim char folded_sign = ' '; 503aca7a94dSNamhyung Kim int first = true; 504aca7a94dSNamhyung Kim int extra_offset = 0; 505aca7a94dSNamhyung Kim 506aca7a94dSNamhyung Kim remaining -= cumul; 507aca7a94dSNamhyung Kim 508aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 509a7cb8863SArnaldo Carvalho de Melo char bf[1024], *alloc_str; 510aca7a94dSNamhyung Kim const char *str; 511aca7a94dSNamhyung Kim int color; 512aca7a94dSNamhyung Kim bool was_first = first; 513aca7a94dSNamhyung Kim 514aca7a94dSNamhyung Kim if (first) 515aca7a94dSNamhyung Kim first = false; 516aca7a94dSNamhyung Kim else 517aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 518aca7a94dSNamhyung Kim 519aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 520aca7a94dSNamhyung Kim if (*row_offset != 0) { 521aca7a94dSNamhyung Kim --*row_offset; 522aca7a94dSNamhyung Kim goto do_next; 523aca7a94dSNamhyung Kim } 524aca7a94dSNamhyung Kim 525aca7a94dSNamhyung Kim alloc_str = NULL; 526a7cb8863SArnaldo Carvalho de Melo str = callchain_list__sym_name(chain, bf, sizeof(bf), 527a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 528aca7a94dSNamhyung Kim if (was_first) { 529aca7a94dSNamhyung Kim double percent = cumul * 100.0 / new_total; 530aca7a94dSNamhyung Kim 531aca7a94dSNamhyung Kim if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 532aca7a94dSNamhyung Kim str = "Not enough memory!"; 533aca7a94dSNamhyung Kim else 534aca7a94dSNamhyung Kim str = alloc_str; 535aca7a94dSNamhyung Kim } 536aca7a94dSNamhyung Kim 537aca7a94dSNamhyung Kim color = HE_COLORSET_NORMAL; 53805e8b080SArnaldo Carvalho de Melo width = browser->b.width - (offset + extra_offset + 2); 53905e8b080SArnaldo Carvalho de Melo if (ui_browser__is_current_entry(&browser->b, row)) { 54005e8b080SArnaldo Carvalho de Melo browser->selection = &chain->ms; 541aca7a94dSNamhyung Kim color = HE_COLORSET_SELECTED; 542aca7a94dSNamhyung Kim *is_current_entry = true; 543aca7a94dSNamhyung Kim } 544aca7a94dSNamhyung Kim 54505e8b080SArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, color); 546ca3ff33bSArnaldo Carvalho de Melo hist_browser__gotorc(browser, row, 0); 547aca7a94dSNamhyung Kim slsmg_write_nstring(" ", offset + extra_offset); 548aca7a94dSNamhyung Kim slsmg_printf("%c ", folded_sign); 549aca7a94dSNamhyung Kim slsmg_write_nstring(str, width); 550aca7a94dSNamhyung Kim free(alloc_str); 551aca7a94dSNamhyung Kim 55262c95ae3SArnaldo Carvalho de Melo if (++row == browser->b.rows) 553aca7a94dSNamhyung Kim goto out; 554aca7a94dSNamhyung Kim do_next: 555aca7a94dSNamhyung Kim if (folded_sign == '+') 556aca7a94dSNamhyung Kim break; 557aca7a94dSNamhyung Kim } 558aca7a94dSNamhyung Kim 559aca7a94dSNamhyung Kim if (folded_sign == '-') { 560aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 56105e8b080SArnaldo Carvalho de Melo row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total, 562aca7a94dSNamhyung Kim new_level, row, row_offset, 563aca7a94dSNamhyung Kim is_current_entry); 564aca7a94dSNamhyung Kim } 56562c95ae3SArnaldo Carvalho de Melo if (row == browser->b.rows) 566aca7a94dSNamhyung Kim goto out; 567aca7a94dSNamhyung Kim node = next; 568aca7a94dSNamhyung Kim } 569aca7a94dSNamhyung Kim out: 570aca7a94dSNamhyung Kim return row - first_row; 571aca7a94dSNamhyung Kim } 572aca7a94dSNamhyung Kim 57305e8b080SArnaldo Carvalho de Melo static int hist_browser__show_callchain_node(struct hist_browser *browser, 574aca7a94dSNamhyung Kim struct callchain_node *node, 575aca7a94dSNamhyung Kim int level, unsigned short row, 576aca7a94dSNamhyung Kim off_t *row_offset, 577aca7a94dSNamhyung Kim bool *is_current_entry) 578aca7a94dSNamhyung Kim { 579aca7a94dSNamhyung Kim struct callchain_list *chain; 580aca7a94dSNamhyung Kim int first_row = row, 581aca7a94dSNamhyung Kim offset = level * LEVEL_OFFSET_STEP, 58205e8b080SArnaldo Carvalho de Melo width = browser->b.width - offset; 583aca7a94dSNamhyung Kim char folded_sign = ' '; 584aca7a94dSNamhyung Kim 585aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 586a7cb8863SArnaldo Carvalho de Melo char bf[1024], *s; 587aca7a94dSNamhyung Kim int color; 588aca7a94dSNamhyung Kim 589aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 590aca7a94dSNamhyung Kim 591aca7a94dSNamhyung Kim if (*row_offset != 0) { 592aca7a94dSNamhyung Kim --*row_offset; 593aca7a94dSNamhyung Kim continue; 594aca7a94dSNamhyung Kim } 595aca7a94dSNamhyung Kim 596aca7a94dSNamhyung Kim color = HE_COLORSET_NORMAL; 59705e8b080SArnaldo Carvalho de Melo if (ui_browser__is_current_entry(&browser->b, row)) { 59805e8b080SArnaldo Carvalho de Melo browser->selection = &chain->ms; 599aca7a94dSNamhyung Kim color = HE_COLORSET_SELECTED; 600aca7a94dSNamhyung Kim *is_current_entry = true; 601aca7a94dSNamhyung Kim } 602aca7a94dSNamhyung Kim 603a7cb8863SArnaldo Carvalho de Melo s = callchain_list__sym_name(chain, bf, sizeof(bf), 604a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 605ca3ff33bSArnaldo Carvalho de Melo hist_browser__gotorc(browser, row, 0); 60605e8b080SArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, color); 607aca7a94dSNamhyung Kim slsmg_write_nstring(" ", offset); 608aca7a94dSNamhyung Kim slsmg_printf("%c ", folded_sign); 609aca7a94dSNamhyung Kim slsmg_write_nstring(s, width - 2); 610aca7a94dSNamhyung Kim 61162c95ae3SArnaldo Carvalho de Melo if (++row == browser->b.rows) 612aca7a94dSNamhyung Kim goto out; 613aca7a94dSNamhyung Kim } 614aca7a94dSNamhyung Kim 615aca7a94dSNamhyung Kim if (folded_sign == '-') 61605e8b080SArnaldo Carvalho de Melo row += hist_browser__show_callchain_node_rb_tree(browser, node, 61705e8b080SArnaldo Carvalho de Melo browser->hists->stats.total_period, 618aca7a94dSNamhyung Kim level + 1, row, 619aca7a94dSNamhyung Kim row_offset, 620aca7a94dSNamhyung Kim is_current_entry); 621aca7a94dSNamhyung Kim out: 622aca7a94dSNamhyung Kim return row - first_row; 623aca7a94dSNamhyung Kim } 624aca7a94dSNamhyung Kim 62505e8b080SArnaldo Carvalho de Melo static int hist_browser__show_callchain(struct hist_browser *browser, 626aca7a94dSNamhyung Kim struct rb_root *chain, 627aca7a94dSNamhyung Kim int level, unsigned short row, 628aca7a94dSNamhyung Kim off_t *row_offset, 629aca7a94dSNamhyung Kim bool *is_current_entry) 630aca7a94dSNamhyung Kim { 631aca7a94dSNamhyung Kim struct rb_node *nd; 632aca7a94dSNamhyung Kim int first_row = row; 633aca7a94dSNamhyung Kim 634aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 635aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 636aca7a94dSNamhyung Kim 63705e8b080SArnaldo Carvalho de Melo row += hist_browser__show_callchain_node(browser, node, level, 638aca7a94dSNamhyung Kim row, row_offset, 639aca7a94dSNamhyung Kim is_current_entry); 64062c95ae3SArnaldo Carvalho de Melo if (row == browser->b.rows) 641aca7a94dSNamhyung Kim break; 642aca7a94dSNamhyung Kim } 643aca7a94dSNamhyung Kim 644aca7a94dSNamhyung Kim return row - first_row; 645aca7a94dSNamhyung Kim } 646aca7a94dSNamhyung Kim 64789701460SNamhyung Kim struct hpp_arg { 64889701460SNamhyung Kim struct ui_browser *b; 64989701460SNamhyung Kim char folded_sign; 65089701460SNamhyung Kim bool current_entry; 65189701460SNamhyung Kim }; 65289701460SNamhyung Kim 6532f6d9009SNamhyung Kim static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 6542f6d9009SNamhyung Kim { 6552f6d9009SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 656*d675107cSNamhyung Kim int ret, len; 6572f6d9009SNamhyung Kim va_list args; 6582f6d9009SNamhyung Kim double percent; 6592f6d9009SNamhyung Kim 6602f6d9009SNamhyung Kim va_start(args, fmt); 661*d675107cSNamhyung Kim len = va_arg(args, int); 6622f6d9009SNamhyung Kim percent = va_arg(args, double); 6632f6d9009SNamhyung Kim va_end(args); 6645aed9d24SNamhyung Kim 66589701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 6665aed9d24SNamhyung Kim 667*d675107cSNamhyung Kim ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); 66889701460SNamhyung Kim slsmg_printf("%s", hpp->buf); 66989701460SNamhyung Kim 6702f6d9009SNamhyung Kim advance_hpp(hpp, ret); 6715aed9d24SNamhyung Kim return ret; 672f5951d56SNamhyung Kim } 673f5951d56SNamhyung Kim 674fb821c9eSNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field) \ 6755aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 6765aed9d24SNamhyung Kim { \ 6775aed9d24SNamhyung Kim return he->stat._field; \ 6785aed9d24SNamhyung Kim } \ 6795aed9d24SNamhyung Kim \ 6802c5d4b4aSJiri Olsa static int \ 6812c5d4b4aSJiri Olsa hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ 6822c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 6835aed9d24SNamhyung Kim struct hist_entry *he) \ 6845aed9d24SNamhyung Kim { \ 685*d675107cSNamhyung Kim return __hpp__fmt(hpp, he, __hpp_get_##_field, " %*.2f%%", 6, \ 6862f6d9009SNamhyung Kim __hpp__slsmg_color_printf, true); \ 6875aed9d24SNamhyung Kim } 688f5951d56SNamhyung Kim 6890434ddd2SNamhyung Kim #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 6900434ddd2SNamhyung Kim static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ 6910434ddd2SNamhyung Kim { \ 6920434ddd2SNamhyung Kim return he->stat_acc->_field; \ 6930434ddd2SNamhyung Kim } \ 6940434ddd2SNamhyung Kim \ 6950434ddd2SNamhyung Kim static int \ 6960434ddd2SNamhyung Kim hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ 6970434ddd2SNamhyung Kim struct perf_hpp *hpp, \ 6980434ddd2SNamhyung Kim struct hist_entry *he) \ 6990434ddd2SNamhyung Kim { \ 7000434ddd2SNamhyung Kim if (!symbol_conf.cumulate_callchain) { \ 701*d675107cSNamhyung Kim int ret = scnprintf(hpp->buf, hpp->size, \ 702*d675107cSNamhyung Kim "%*s", 8, "N/A"); \ 7030434ddd2SNamhyung Kim slsmg_printf("%s", hpp->buf); \ 7040434ddd2SNamhyung Kim \ 7050434ddd2SNamhyung Kim return ret; \ 7060434ddd2SNamhyung Kim } \ 707*d675107cSNamhyung Kim return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %*.2f%%", \ 708*d675107cSNamhyung Kim 6, __hpp__slsmg_color_printf, true); \ 7090434ddd2SNamhyung Kim } 7100434ddd2SNamhyung Kim 711fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period) 712fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 713fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us) 714fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 715fb821c9eSNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 7160434ddd2SNamhyung Kim __HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period) 7175aed9d24SNamhyung Kim 7185aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 7190434ddd2SNamhyung Kim #undef __HPP_COLOR_ACC_PERCENT_FN 720f5951d56SNamhyung Kim 721f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 722f5951d56SNamhyung Kim { 723f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 724f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 725f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 726f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 727f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 728f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 729f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 730f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 731f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 732f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 7330434ddd2SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color = 7340434ddd2SNamhyung Kim hist_browser__hpp_color_overhead_acc; 735f5951d56SNamhyung Kim } 736f5951d56SNamhyung Kim 73705e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 738aca7a94dSNamhyung Kim struct hist_entry *entry, 739aca7a94dSNamhyung Kim unsigned short row) 740aca7a94dSNamhyung Kim { 741aca7a94dSNamhyung Kim char s[256]; 7421240005eSJiri Olsa int printed = 0; 74367d25916SNamhyung Kim int width = browser->b.width; 744aca7a94dSNamhyung Kim char folded_sign = ' '; 74505e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 746aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 74763a1a3d8SNamhyung Kim bool first = true; 7481240005eSJiri Olsa struct perf_hpp_fmt *fmt; 749aca7a94dSNamhyung Kim 750aca7a94dSNamhyung Kim if (current_entry) { 75105e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 75205e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 753aca7a94dSNamhyung Kim } 754aca7a94dSNamhyung Kim 755aca7a94dSNamhyung Kim if (symbol_conf.use_callchain) { 756aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 757aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 758aca7a94dSNamhyung Kim } 759aca7a94dSNamhyung Kim 760aca7a94dSNamhyung Kim if (row_offset == 0) { 76189701460SNamhyung Kim struct hpp_arg arg = { 76289701460SNamhyung Kim .b = &browser->b, 76389701460SNamhyung Kim .folded_sign = folded_sign, 76489701460SNamhyung Kim .current_entry = current_entry, 76589701460SNamhyung Kim }; 766f5951d56SNamhyung Kim struct perf_hpp hpp = { 767f5951d56SNamhyung Kim .buf = s, 768f5951d56SNamhyung Kim .size = sizeof(s), 76989701460SNamhyung Kim .ptr = &arg, 770f5951d56SNamhyung Kim }; 771f5951d56SNamhyung Kim 772ca3ff33bSArnaldo Carvalho de Melo hist_browser__gotorc(browser, row, 0); 773f5951d56SNamhyung Kim 7741240005eSJiri Olsa perf_hpp__for_each_format(fmt) { 775e67d49a7SNamhyung Kim if (perf_hpp__should_skip(fmt)) 776e67d49a7SNamhyung Kim continue; 777e67d49a7SNamhyung Kim 778fb821c9eSNamhyung Kim if (current_entry && browser->b.navkeypressed) { 779fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 780fb821c9eSNamhyung Kim HE_COLORSET_SELECTED); 781fb821c9eSNamhyung Kim } else { 782fb821c9eSNamhyung Kim ui_browser__set_color(&browser->b, 783fb821c9eSNamhyung Kim HE_COLORSET_NORMAL); 784fb821c9eSNamhyung Kim } 785fb821c9eSNamhyung Kim 786fb821c9eSNamhyung Kim if (first) { 787fb821c9eSNamhyung Kim if (symbol_conf.use_callchain) { 788fb821c9eSNamhyung Kim slsmg_printf("%c ", folded_sign); 789f5951d56SNamhyung Kim width -= 2; 790f5951d56SNamhyung Kim } 79163a1a3d8SNamhyung Kim first = false; 792fb821c9eSNamhyung Kim } else { 793fb821c9eSNamhyung Kim slsmg_printf(" "); 794fb821c9eSNamhyung Kim width -= 2; 795fb821c9eSNamhyung Kim } 796f5951d56SNamhyung Kim 7971240005eSJiri Olsa if (fmt->color) { 7982c5d4b4aSJiri Olsa width -= fmt->color(fmt, &hpp, entry); 799f5951d56SNamhyung Kim } else { 8002c5d4b4aSJiri Olsa width -= fmt->entry(fmt, &hpp, entry); 801f5951d56SNamhyung Kim slsmg_printf("%s", s); 802f5951d56SNamhyung Kim } 803f5951d56SNamhyung Kim } 804aca7a94dSNamhyung Kim 805aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 80605e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 807aca7a94dSNamhyung Kim width += 1; 808aca7a94dSNamhyung Kim 80926d8b338SNamhyung Kim slsmg_write_nstring("", width); 81026d8b338SNamhyung Kim 811aca7a94dSNamhyung Kim ++row; 812aca7a94dSNamhyung Kim ++printed; 813aca7a94dSNamhyung Kim } else 814aca7a94dSNamhyung Kim --row_offset; 815aca7a94dSNamhyung Kim 81662c95ae3SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.rows) { 81705e8b080SArnaldo Carvalho de Melo printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 818aca7a94dSNamhyung Kim 1, row, &row_offset, 819aca7a94dSNamhyung Kim ¤t_entry); 820aca7a94dSNamhyung Kim if (current_entry) 82105e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 822aca7a94dSNamhyung Kim } 823aca7a94dSNamhyung Kim 824aca7a94dSNamhyung Kim return printed; 825aca7a94dSNamhyung Kim } 826aca7a94dSNamhyung Kim 82781a888feSJiri Olsa static int advance_hpp_check(struct perf_hpp *hpp, int inc) 82881a888feSJiri Olsa { 82981a888feSJiri Olsa advance_hpp(hpp, inc); 83081a888feSJiri Olsa return hpp->size <= 0; 83181a888feSJiri Olsa } 83281a888feSJiri Olsa 83381a888feSJiri Olsa static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists) 83481a888feSJiri Olsa { 83581a888feSJiri Olsa struct perf_hpp dummy_hpp = { 83681a888feSJiri Olsa .buf = buf, 83781a888feSJiri Olsa .size = size, 83881a888feSJiri Olsa }; 83981a888feSJiri Olsa struct perf_hpp_fmt *fmt; 84081a888feSJiri Olsa size_t ret = 0; 84181a888feSJiri Olsa 84281a888feSJiri Olsa if (symbol_conf.use_callchain) { 84381a888feSJiri Olsa ret = scnprintf(buf, size, " "); 84481a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 84581a888feSJiri Olsa return ret; 84681a888feSJiri Olsa } 84781a888feSJiri Olsa 84881a888feSJiri Olsa perf_hpp__for_each_format(fmt) { 84981a888feSJiri Olsa if (perf_hpp__should_skip(fmt)) 85081a888feSJiri Olsa continue; 85181a888feSJiri Olsa 85281a888feSJiri Olsa /* We need to add the length of the columns header. */ 85381a888feSJiri Olsa perf_hpp__reset_width(fmt, hists); 85481a888feSJiri Olsa 85581a888feSJiri Olsa ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); 85681a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 85781a888feSJiri Olsa break; 85881a888feSJiri Olsa 85981a888feSJiri Olsa ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " "); 86081a888feSJiri Olsa if (advance_hpp_check(&dummy_hpp, ret)) 86181a888feSJiri Olsa break; 86281a888feSJiri Olsa } 86381a888feSJiri Olsa 86481a888feSJiri Olsa return ret; 86581a888feSJiri Olsa } 86681a888feSJiri Olsa 867025bf7eaSArnaldo Carvalho de Melo static void hist_browser__show_headers(struct hist_browser *browser) 868025bf7eaSArnaldo Carvalho de Melo { 86981a888feSJiri Olsa char headers[1024]; 87081a888feSJiri Olsa 87181a888feSJiri Olsa hists__scnprintf_headers(headers, sizeof(headers), browser->hists); 872025bf7eaSArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, 0, 0); 873025bf7eaSArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 87481a888feSJiri Olsa slsmg_write_nstring(headers, browser->b.width + 1); 875025bf7eaSArnaldo Carvalho de Melo } 876025bf7eaSArnaldo Carvalho de Melo 877aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 878aca7a94dSNamhyung Kim { 879aca7a94dSNamhyung Kim if (browser->top == NULL) { 880aca7a94dSNamhyung Kim struct hist_browser *hb; 881aca7a94dSNamhyung Kim 882aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 883aca7a94dSNamhyung Kim browser->top = rb_first(&hb->hists->entries); 884aca7a94dSNamhyung Kim } 885aca7a94dSNamhyung Kim } 886aca7a94dSNamhyung Kim 88705e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 888aca7a94dSNamhyung Kim { 889aca7a94dSNamhyung Kim unsigned row = 0; 890025bf7eaSArnaldo Carvalho de Melo u16 header_offset = 0; 891aca7a94dSNamhyung Kim struct rb_node *nd; 89205e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 893aca7a94dSNamhyung Kim 894025bf7eaSArnaldo Carvalho de Melo if (hb->show_headers) { 895025bf7eaSArnaldo Carvalho de Melo hist_browser__show_headers(hb); 896025bf7eaSArnaldo Carvalho de Melo header_offset = 1; 897025bf7eaSArnaldo Carvalho de Melo } 898025bf7eaSArnaldo Carvalho de Melo 89905e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 900aca7a94dSNamhyung Kim 90105e8b080SArnaldo Carvalho de Melo for (nd = browser->top; nd; nd = rb_next(nd)) { 902aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 90314135663SNamhyung Kim float percent; 904aca7a94dSNamhyung Kim 905aca7a94dSNamhyung Kim if (h->filtered) 906aca7a94dSNamhyung Kim continue; 907aca7a94dSNamhyung Kim 90814135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 909064f1981SNamhyung Kim if (percent < hb->min_pcnt) 910064f1981SNamhyung Kim continue; 911064f1981SNamhyung Kim 912aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 91362c95ae3SArnaldo Carvalho de Melo if (row == browser->rows) 914aca7a94dSNamhyung Kim break; 915aca7a94dSNamhyung Kim } 916aca7a94dSNamhyung Kim 917025bf7eaSArnaldo Carvalho de Melo return row + header_offset; 918aca7a94dSNamhyung Kim } 919aca7a94dSNamhyung Kim 920064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 921064f1981SNamhyung Kim float min_pcnt) 922aca7a94dSNamhyung Kim { 923aca7a94dSNamhyung Kim while (nd != NULL) { 924aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 92514135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 926064f1981SNamhyung Kim 927c0f1527bSNamhyung Kim if (!h->filtered && percent >= min_pcnt) 928aca7a94dSNamhyung Kim return nd; 929aca7a94dSNamhyung Kim 930aca7a94dSNamhyung Kim nd = rb_next(nd); 931aca7a94dSNamhyung Kim } 932aca7a94dSNamhyung Kim 933aca7a94dSNamhyung Kim return NULL; 934aca7a94dSNamhyung Kim } 935aca7a94dSNamhyung Kim 936064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 937064f1981SNamhyung Kim float min_pcnt) 938aca7a94dSNamhyung Kim { 939aca7a94dSNamhyung Kim while (nd != NULL) { 940aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 94114135663SNamhyung Kim float percent = hist_entry__get_percent_limit(h); 942064f1981SNamhyung Kim 943064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 944aca7a94dSNamhyung Kim return nd; 945aca7a94dSNamhyung Kim 946aca7a94dSNamhyung Kim nd = rb_prev(nd); 947aca7a94dSNamhyung Kim } 948aca7a94dSNamhyung Kim 949aca7a94dSNamhyung Kim return NULL; 950aca7a94dSNamhyung Kim } 951aca7a94dSNamhyung Kim 95205e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 953aca7a94dSNamhyung Kim off_t offset, int whence) 954aca7a94dSNamhyung Kim { 955aca7a94dSNamhyung Kim struct hist_entry *h; 956aca7a94dSNamhyung Kim struct rb_node *nd; 957aca7a94dSNamhyung Kim bool first = true; 958064f1981SNamhyung Kim struct hist_browser *hb; 959064f1981SNamhyung Kim 960064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 961aca7a94dSNamhyung Kim 96205e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 963aca7a94dSNamhyung Kim return; 964aca7a94dSNamhyung Kim 96505e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 966aca7a94dSNamhyung Kim 967aca7a94dSNamhyung Kim switch (whence) { 968aca7a94dSNamhyung Kim case SEEK_SET: 969064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 97014135663SNamhyung Kim hb->min_pcnt); 971aca7a94dSNamhyung Kim break; 972aca7a94dSNamhyung Kim case SEEK_CUR: 97305e8b080SArnaldo Carvalho de Melo nd = browser->top; 974aca7a94dSNamhyung Kim goto do_offset; 975aca7a94dSNamhyung Kim case SEEK_END: 976064f1981SNamhyung Kim nd = hists__filter_prev_entries(rb_last(browser->entries), 97714135663SNamhyung Kim hb->min_pcnt); 978aca7a94dSNamhyung Kim first = false; 979aca7a94dSNamhyung Kim break; 980aca7a94dSNamhyung Kim default: 981aca7a94dSNamhyung Kim return; 982aca7a94dSNamhyung Kim } 983aca7a94dSNamhyung Kim 984aca7a94dSNamhyung Kim /* 985aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 986aca7a94dSNamhyung Kim * row_offset: 987aca7a94dSNamhyung Kim */ 98805e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 989aca7a94dSNamhyung Kim h->row_offset = 0; 990aca7a94dSNamhyung Kim 991aca7a94dSNamhyung Kim /* 992aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 993aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 994aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 995aca7a94dSNamhyung Kim * 996aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 997aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 998aca7a94dSNamhyung Kim * 999aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 1000aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 1001aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 1002aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 1003aca7a94dSNamhyung Kim */ 1004aca7a94dSNamhyung Kim do_offset: 1005aca7a94dSNamhyung Kim if (offset > 0) { 1006aca7a94dSNamhyung Kim do { 1007aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1008aca7a94dSNamhyung Kim if (h->ms.unfolded) { 1009aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 1010aca7a94dSNamhyung Kim if (offset > remaining) { 1011aca7a94dSNamhyung Kim offset -= remaining; 1012aca7a94dSNamhyung Kim h->row_offset = 0; 1013aca7a94dSNamhyung Kim } else { 1014aca7a94dSNamhyung Kim h->row_offset += offset; 1015aca7a94dSNamhyung Kim offset = 0; 101605e8b080SArnaldo Carvalho de Melo browser->top = nd; 1017aca7a94dSNamhyung Kim break; 1018aca7a94dSNamhyung Kim } 1019aca7a94dSNamhyung Kim } 102014135663SNamhyung Kim nd = hists__filter_entries(rb_next(nd), hb->min_pcnt); 1021aca7a94dSNamhyung Kim if (nd == NULL) 1022aca7a94dSNamhyung Kim break; 1023aca7a94dSNamhyung Kim --offset; 102405e8b080SArnaldo Carvalho de Melo browser->top = nd; 1025aca7a94dSNamhyung Kim } while (offset != 0); 1026aca7a94dSNamhyung Kim } else if (offset < 0) { 1027aca7a94dSNamhyung Kim while (1) { 1028aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1029aca7a94dSNamhyung Kim if (h->ms.unfolded) { 1030aca7a94dSNamhyung Kim if (first) { 1031aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 1032aca7a94dSNamhyung Kim offset += h->row_offset; 1033aca7a94dSNamhyung Kim h->row_offset = 0; 1034aca7a94dSNamhyung Kim } else { 1035aca7a94dSNamhyung Kim h->row_offset += offset; 1036aca7a94dSNamhyung Kim offset = 0; 103705e8b080SArnaldo Carvalho de Melo browser->top = nd; 1038aca7a94dSNamhyung Kim break; 1039aca7a94dSNamhyung Kim } 1040aca7a94dSNamhyung Kim } else { 1041aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 1042aca7a94dSNamhyung Kim offset += h->nr_rows; 1043aca7a94dSNamhyung Kim h->row_offset = 0; 1044aca7a94dSNamhyung Kim } else { 1045aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 1046aca7a94dSNamhyung Kim offset = 0; 104705e8b080SArnaldo Carvalho de Melo browser->top = nd; 1048aca7a94dSNamhyung Kim break; 1049aca7a94dSNamhyung Kim } 1050aca7a94dSNamhyung Kim } 1051aca7a94dSNamhyung Kim } 1052aca7a94dSNamhyung Kim 105314135663SNamhyung Kim nd = hists__filter_prev_entries(rb_prev(nd), 1054064f1981SNamhyung Kim hb->min_pcnt); 1055aca7a94dSNamhyung Kim if (nd == NULL) 1056aca7a94dSNamhyung Kim break; 1057aca7a94dSNamhyung Kim ++offset; 105805e8b080SArnaldo Carvalho de Melo browser->top = nd; 1059aca7a94dSNamhyung Kim if (offset == 0) { 1060aca7a94dSNamhyung Kim /* 1061aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 1062aca7a94dSNamhyung Kim * unfolded, if it is then we should have 1063aca7a94dSNamhyung Kim * row_offset at its last entry. 1064aca7a94dSNamhyung Kim */ 1065aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1066aca7a94dSNamhyung Kim if (h->ms.unfolded) 1067aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 1068aca7a94dSNamhyung Kim break; 1069aca7a94dSNamhyung Kim } 1070aca7a94dSNamhyung Kim first = false; 1071aca7a94dSNamhyung Kim } 1072aca7a94dSNamhyung Kim } else { 107305e8b080SArnaldo Carvalho de Melo browser->top = nd; 1074aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 1075aca7a94dSNamhyung Kim h->row_offset = 0; 1076aca7a94dSNamhyung Kim } 1077aca7a94dSNamhyung Kim } 1078aca7a94dSNamhyung Kim 1079aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser, 1080aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *chain_node, 1081aff3f3f6SArnaldo Carvalho de Melo u64 total, int level, 1082aff3f3f6SArnaldo Carvalho de Melo FILE *fp) 1083aff3f3f6SArnaldo Carvalho de Melo { 1084aff3f3f6SArnaldo Carvalho de Melo struct rb_node *node; 1085aff3f3f6SArnaldo Carvalho de Melo int offset = level * LEVEL_OFFSET_STEP; 1086aff3f3f6SArnaldo Carvalho de Melo u64 new_total, remaining; 1087aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1088aff3f3f6SArnaldo Carvalho de Melo 1089aff3f3f6SArnaldo Carvalho de Melo if (callchain_param.mode == CHAIN_GRAPH_REL) 1090aff3f3f6SArnaldo Carvalho de Melo new_total = chain_node->children_hit; 1091aff3f3f6SArnaldo Carvalho de Melo else 1092aff3f3f6SArnaldo Carvalho de Melo new_total = total; 1093aff3f3f6SArnaldo Carvalho de Melo 1094aff3f3f6SArnaldo Carvalho de Melo remaining = new_total; 1095aff3f3f6SArnaldo Carvalho de Melo node = rb_first(&chain_node->rb_root); 1096aff3f3f6SArnaldo Carvalho de Melo while (node) { 1097aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 1098aff3f3f6SArnaldo Carvalho de Melo struct rb_node *next = rb_next(node); 1099aff3f3f6SArnaldo Carvalho de Melo u64 cumul = callchain_cumul_hits(child); 1100aff3f3f6SArnaldo Carvalho de Melo struct callchain_list *chain; 1101aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 1102aff3f3f6SArnaldo Carvalho de Melo int first = true; 1103aff3f3f6SArnaldo Carvalho de Melo int extra_offset = 0; 1104aff3f3f6SArnaldo Carvalho de Melo 1105aff3f3f6SArnaldo Carvalho de Melo remaining -= cumul; 1106aff3f3f6SArnaldo Carvalho de Melo 1107aff3f3f6SArnaldo Carvalho de Melo list_for_each_entry(chain, &child->val, list) { 1108a7cb8863SArnaldo Carvalho de Melo char bf[1024], *alloc_str; 1109aff3f3f6SArnaldo Carvalho de Melo const char *str; 1110aff3f3f6SArnaldo Carvalho de Melo bool was_first = first; 1111aff3f3f6SArnaldo Carvalho de Melo 1112aff3f3f6SArnaldo Carvalho de Melo if (first) 1113aff3f3f6SArnaldo Carvalho de Melo first = false; 1114aff3f3f6SArnaldo Carvalho de Melo else 1115aff3f3f6SArnaldo Carvalho de Melo extra_offset = LEVEL_OFFSET_STEP; 1116aff3f3f6SArnaldo Carvalho de Melo 1117aff3f3f6SArnaldo Carvalho de Melo folded_sign = callchain_list__folded(chain); 1118aff3f3f6SArnaldo Carvalho de Melo 1119aff3f3f6SArnaldo Carvalho de Melo alloc_str = NULL; 1120a7cb8863SArnaldo Carvalho de Melo str = callchain_list__sym_name(chain, bf, sizeof(bf), 1121a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 1122aff3f3f6SArnaldo Carvalho de Melo if (was_first) { 1123aff3f3f6SArnaldo Carvalho de Melo double percent = cumul * 100.0 / new_total; 1124aff3f3f6SArnaldo Carvalho de Melo 1125aff3f3f6SArnaldo Carvalho de Melo if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 1126aff3f3f6SArnaldo Carvalho de Melo str = "Not enough memory!"; 1127aff3f3f6SArnaldo Carvalho de Melo else 1128aff3f3f6SArnaldo Carvalho de Melo str = alloc_str; 1129aff3f3f6SArnaldo Carvalho de Melo } 1130aff3f3f6SArnaldo Carvalho de Melo 1131aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str); 1132aff3f3f6SArnaldo Carvalho de Melo free(alloc_str); 1133aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '+') 1134aff3f3f6SArnaldo Carvalho de Melo break; 1135aff3f3f6SArnaldo Carvalho de Melo } 1136aff3f3f6SArnaldo Carvalho de Melo 1137aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') { 1138aff3f3f6SArnaldo Carvalho de Melo const int new_level = level + (extra_offset ? 2 : 1); 1139aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total, 1140aff3f3f6SArnaldo Carvalho de Melo new_level, fp); 1141aff3f3f6SArnaldo Carvalho de Melo } 1142aff3f3f6SArnaldo Carvalho de Melo 1143aff3f3f6SArnaldo Carvalho de Melo node = next; 1144aff3f3f6SArnaldo Carvalho de Melo } 1145aff3f3f6SArnaldo Carvalho de Melo 1146aff3f3f6SArnaldo Carvalho de Melo return printed; 1147aff3f3f6SArnaldo Carvalho de Melo } 1148aff3f3f6SArnaldo Carvalho de Melo 1149aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain_node(struct hist_browser *browser, 1150aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *node, 1151aff3f3f6SArnaldo Carvalho de Melo int level, FILE *fp) 1152aff3f3f6SArnaldo Carvalho de Melo { 1153aff3f3f6SArnaldo Carvalho de Melo struct callchain_list *chain; 1154aff3f3f6SArnaldo Carvalho de Melo int offset = level * LEVEL_OFFSET_STEP; 1155aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 1156aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1157aff3f3f6SArnaldo Carvalho de Melo 1158aff3f3f6SArnaldo Carvalho de Melo list_for_each_entry(chain, &node->val, list) { 1159a7cb8863SArnaldo Carvalho de Melo char bf[1024], *s; 1160aff3f3f6SArnaldo Carvalho de Melo 1161aff3f3f6SArnaldo Carvalho de Melo folded_sign = callchain_list__folded(chain); 1162a7cb8863SArnaldo Carvalho de Melo s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso); 1163aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s); 1164aff3f3f6SArnaldo Carvalho de Melo } 1165aff3f3f6SArnaldo Carvalho de Melo 1166aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 1167aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node, 1168aff3f3f6SArnaldo Carvalho de Melo browser->hists->stats.total_period, 1169aff3f3f6SArnaldo Carvalho de Melo level + 1, fp); 1170aff3f3f6SArnaldo Carvalho de Melo return printed; 1171aff3f3f6SArnaldo Carvalho de Melo } 1172aff3f3f6SArnaldo Carvalho de Melo 1173aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1174aff3f3f6SArnaldo Carvalho de Melo struct rb_root *chain, int level, FILE *fp) 1175aff3f3f6SArnaldo Carvalho de Melo { 1176aff3f3f6SArnaldo Carvalho de Melo struct rb_node *nd; 1177aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1178aff3f3f6SArnaldo Carvalho de Melo 1179aff3f3f6SArnaldo Carvalho de Melo for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 1180aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 1181aff3f3f6SArnaldo Carvalho de Melo 1182aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain_node(browser, node, level, fp); 1183aff3f3f6SArnaldo Carvalho de Melo } 1184aff3f3f6SArnaldo Carvalho de Melo 1185aff3f3f6SArnaldo Carvalho de Melo return printed; 1186aff3f3f6SArnaldo Carvalho de Melo } 1187aff3f3f6SArnaldo Carvalho de Melo 1188aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 1189aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 1190aff3f3f6SArnaldo Carvalho de Melo { 1191aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 1192aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1193aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 119426d8b338SNamhyung Kim struct perf_hpp hpp = { 119526d8b338SNamhyung Kim .buf = s, 119626d8b338SNamhyung Kim .size = sizeof(s), 119726d8b338SNamhyung Kim }; 119826d8b338SNamhyung Kim struct perf_hpp_fmt *fmt; 119926d8b338SNamhyung Kim bool first = true; 120026d8b338SNamhyung Kim int ret; 1201aff3f3f6SArnaldo Carvalho de Melo 1202aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1203aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 1204aff3f3f6SArnaldo Carvalho de Melo 1205aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1206aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 1207aff3f3f6SArnaldo Carvalho de Melo 120826d8b338SNamhyung Kim perf_hpp__for_each_format(fmt) { 1209e67d49a7SNamhyung Kim if (perf_hpp__should_skip(fmt)) 1210e67d49a7SNamhyung Kim continue; 1211e67d49a7SNamhyung Kim 121226d8b338SNamhyung Kim if (!first) { 121326d8b338SNamhyung Kim ret = scnprintf(hpp.buf, hpp.size, " "); 121426d8b338SNamhyung Kim advance_hpp(&hpp, ret); 121526d8b338SNamhyung Kim } else 121626d8b338SNamhyung Kim first = false; 1217aff3f3f6SArnaldo Carvalho de Melo 121826d8b338SNamhyung Kim ret = fmt->entry(fmt, &hpp, he); 121926d8b338SNamhyung Kim advance_hpp(&hpp, ret); 122026d8b338SNamhyung Kim } 1221aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", rtrim(s)); 1222aff3f3f6SArnaldo Carvalho de Melo 1223aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 1224aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp); 1225aff3f3f6SArnaldo Carvalho de Melo 1226aff3f3f6SArnaldo Carvalho de Melo return printed; 1227aff3f3f6SArnaldo Carvalho de Melo } 1228aff3f3f6SArnaldo Carvalho de Melo 1229aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1230aff3f3f6SArnaldo Carvalho de Melo { 1231064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1232064f1981SNamhyung Kim browser->min_pcnt); 1233aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1234aff3f3f6SArnaldo Carvalho de Melo 1235aff3f3f6SArnaldo Carvalho de Melo while (nd) { 1236aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1237aff3f3f6SArnaldo Carvalho de Melo 1238aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 123914135663SNamhyung Kim nd = hists__filter_entries(rb_next(nd), browser->min_pcnt); 1240aff3f3f6SArnaldo Carvalho de Melo } 1241aff3f3f6SArnaldo Carvalho de Melo 1242aff3f3f6SArnaldo Carvalho de Melo return printed; 1243aff3f3f6SArnaldo Carvalho de Melo } 1244aff3f3f6SArnaldo Carvalho de Melo 1245aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 1246aff3f3f6SArnaldo Carvalho de Melo { 1247aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 1248aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 1249aff3f3f6SArnaldo Carvalho de Melo 1250aff3f3f6SArnaldo Carvalho de Melo while (1) { 1251aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 1252aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 1253aff3f3f6SArnaldo Carvalho de Melo break; 1254aff3f3f6SArnaldo Carvalho de Melo /* 1255aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 1256aff3f3f6SArnaldo Carvalho de Melo */ 1257aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 1258aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 1259aff3f3f6SArnaldo Carvalho de Melo return -1; 1260aff3f3f6SArnaldo Carvalho de Melo } 1261aff3f3f6SArnaldo Carvalho de Melo } 1262aff3f3f6SArnaldo Carvalho de Melo 1263aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 1264aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 1265aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 12664cc49d4dSKirill A. Shutemov const char *err = strerror_r(errno, bf, sizeof(bf)); 12674cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 1268aff3f3f6SArnaldo Carvalho de Melo return -1; 1269aff3f3f6SArnaldo Carvalho de Melo } 1270aff3f3f6SArnaldo Carvalho de Melo 1271aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 1272aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 1273aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 1274aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 1275aff3f3f6SArnaldo Carvalho de Melo 1276aff3f3f6SArnaldo Carvalho de Melo return 0; 1277aff3f3f6SArnaldo Carvalho de Melo } 1278aff3f3f6SArnaldo Carvalho de Melo 1279aca7a94dSNamhyung Kim static struct hist_browser *hist_browser__new(struct hists *hists) 1280aca7a94dSNamhyung Kim { 128105e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = zalloc(sizeof(*browser)); 1282aca7a94dSNamhyung Kim 128305e8b080SArnaldo Carvalho de Melo if (browser) { 128405e8b080SArnaldo Carvalho de Melo browser->hists = hists; 128505e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 1286357cfff1SArnaldo Carvalho de Melo browser->b.refresh_dimensions = hist_browser__refresh_dimensions; 128705e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 128805e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 1289c8302367SJiri Olsa browser->show_headers = symbol_conf.show_hist_headers; 1290aca7a94dSNamhyung Kim } 1291aca7a94dSNamhyung Kim 129205e8b080SArnaldo Carvalho de Melo return browser; 1293aca7a94dSNamhyung Kim } 1294aca7a94dSNamhyung Kim 129505e8b080SArnaldo Carvalho de Melo static void hist_browser__delete(struct hist_browser *browser) 1296aca7a94dSNamhyung Kim { 129705e8b080SArnaldo Carvalho de Melo free(browser); 1298aca7a94dSNamhyung Kim } 1299aca7a94dSNamhyung Kim 130005e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 1301aca7a94dSNamhyung Kim { 130205e8b080SArnaldo Carvalho de Melo return browser->he_selection; 1303aca7a94dSNamhyung Kim } 1304aca7a94dSNamhyung Kim 130505e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 1306aca7a94dSNamhyung Kim { 130705e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 1308aca7a94dSNamhyung Kim } 1309aca7a94dSNamhyung Kim 1310dd00d486SJiri Olsa static int hists__browser_title(struct hists *hists, char *bf, size_t size) 1311aca7a94dSNamhyung Kim { 1312aca7a94dSNamhyung Kim char unit; 1313aca7a94dSNamhyung Kim int printed; 131405e8b080SArnaldo Carvalho de Melo const struct dso *dso = hists->dso_filter; 131505e8b080SArnaldo Carvalho de Melo const struct thread *thread = hists->thread_filter; 131605e8b080SArnaldo Carvalho de Melo unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 131705e8b080SArnaldo Carvalho de Melo u64 nr_events = hists->stats.total_period; 1318717e263fSNamhyung Kim struct perf_evsel *evsel = hists_to_evsel(hists); 1319dd00d486SJiri Olsa const char *ev_name = perf_evsel__name(evsel); 1320717e263fSNamhyung Kim char buf[512]; 1321717e263fSNamhyung Kim size_t buflen = sizeof(buf); 1322717e263fSNamhyung Kim 1323f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 1324f2148330SNamhyung Kim nr_samples = hists->stats.nr_non_filtered_samples; 1325f2148330SNamhyung Kim nr_events = hists->stats.total_non_filtered_period; 1326f2148330SNamhyung Kim } 1327f2148330SNamhyung Kim 1328759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1329717e263fSNamhyung Kim struct perf_evsel *pos; 1330717e263fSNamhyung Kim 1331717e263fSNamhyung Kim perf_evsel__group_desc(evsel, buf, buflen); 1332717e263fSNamhyung Kim ev_name = buf; 1333717e263fSNamhyung Kim 1334717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 1335f2148330SNamhyung Kim if (symbol_conf.filter_relative) { 1336f2148330SNamhyung Kim nr_samples += pos->hists.stats.nr_non_filtered_samples; 1337f2148330SNamhyung Kim nr_events += pos->hists.stats.total_non_filtered_period; 1338f2148330SNamhyung Kim } else { 1339717e263fSNamhyung Kim nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1340717e263fSNamhyung Kim nr_events += pos->hists.stats.total_period; 1341717e263fSNamhyung Kim } 1342717e263fSNamhyung Kim } 1343f2148330SNamhyung Kim } 1344aca7a94dSNamhyung Kim 1345aca7a94dSNamhyung Kim nr_samples = convert_unit(nr_samples, &unit); 1346aca7a94dSNamhyung Kim printed = scnprintf(bf, size, 1347aca7a94dSNamhyung Kim "Samples: %lu%c of event '%s', Event count (approx.): %lu", 1348aca7a94dSNamhyung Kim nr_samples, unit, ev_name, nr_events); 1349aca7a94dSNamhyung Kim 1350aca7a94dSNamhyung Kim 135105e8b080SArnaldo Carvalho de Melo if (hists->uid_filter_str) 1352aca7a94dSNamhyung Kim printed += snprintf(bf + printed, size - printed, 135305e8b080SArnaldo Carvalho de Melo ", UID: %s", hists->uid_filter_str); 1354aca7a94dSNamhyung Kim if (thread) 1355aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1356aca7a94dSNamhyung Kim ", Thread: %s(%d)", 1357b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 135838051234SAdrian Hunter thread->tid); 1359aca7a94dSNamhyung Kim if (dso) 1360aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1361aca7a94dSNamhyung Kim ", DSO: %s", dso->short_name); 1362aca7a94dSNamhyung Kim return printed; 1363aca7a94dSNamhyung Kim } 1364aca7a94dSNamhyung Kim 1365aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 1366aca7a94dSNamhyung Kim { 1367aca7a94dSNamhyung Kim int i; 1368aca7a94dSNamhyung Kim 136904662523SArnaldo Carvalho de Melo for (i = 0; i < n; ++i) 137004662523SArnaldo Carvalho de Melo zfree(&options[i]); 1371aca7a94dSNamhyung Kim } 1372aca7a94dSNamhyung Kim 1373c77d8d70SFeng Tang /* Check whether the browser is for 'top' or 'report' */ 1374c77d8d70SFeng Tang static inline bool is_report_browser(void *timer) 1375c77d8d70SFeng Tang { 1376c77d8d70SFeng Tang return timer == NULL; 1377c77d8d70SFeng Tang } 1378c77d8d70SFeng Tang 1379341487abSFeng Tang /* 1380341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 1381341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 1382341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 1383341487abSFeng Tang */ 1384341487abSFeng Tang static bool is_input_name_malloced = false; 1385341487abSFeng Tang 1386341487abSFeng Tang static int switch_data_file(void) 1387341487abSFeng Tang { 1388341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 1389341487abSFeng Tang DIR *pwd_dir; 1390341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 1391341487abSFeng Tang struct dirent *dent; 1392341487abSFeng Tang 1393341487abSFeng Tang pwd = getenv("PWD"); 1394341487abSFeng Tang if (!pwd) 1395341487abSFeng Tang return ret; 1396341487abSFeng Tang 1397341487abSFeng Tang pwd_dir = opendir(pwd); 1398341487abSFeng Tang if (!pwd_dir) 1399341487abSFeng Tang return ret; 1400341487abSFeng Tang 1401341487abSFeng Tang memset(options, 0, sizeof(options)); 1402341487abSFeng Tang memset(options, 0, sizeof(abs_path)); 1403341487abSFeng Tang 1404341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 1405341487abSFeng Tang char path[PATH_MAX]; 1406341487abSFeng Tang u64 magic; 1407341487abSFeng Tang char *name = dent->d_name; 1408341487abSFeng Tang FILE *file; 1409341487abSFeng Tang 1410341487abSFeng Tang if (!(dent->d_type == DT_REG)) 1411341487abSFeng Tang continue; 1412341487abSFeng Tang 1413341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 1414341487abSFeng Tang 1415341487abSFeng Tang file = fopen(path, "r"); 1416341487abSFeng Tang if (!file) 1417341487abSFeng Tang continue; 1418341487abSFeng Tang 1419341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 1420341487abSFeng Tang goto close_file_and_continue; 1421341487abSFeng Tang 1422341487abSFeng Tang if (is_perf_magic(magic)) { 1423341487abSFeng Tang options[nr_options] = strdup(name); 1424341487abSFeng Tang if (!options[nr_options]) 1425341487abSFeng Tang goto close_file_and_continue; 1426341487abSFeng Tang 1427341487abSFeng Tang abs_path[nr_options] = strdup(path); 1428341487abSFeng Tang if (!abs_path[nr_options]) { 142974cf249dSArnaldo Carvalho de Melo zfree(&options[nr_options]); 1430341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 1431341487abSFeng Tang fclose(file); 1432341487abSFeng Tang break; 1433341487abSFeng Tang } 1434341487abSFeng Tang 1435341487abSFeng Tang nr_options++; 1436341487abSFeng Tang } 1437341487abSFeng Tang 1438341487abSFeng Tang close_file_and_continue: 1439341487abSFeng Tang fclose(file); 1440341487abSFeng Tang if (nr_options >= 32) { 1441341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 1442341487abSFeng Tang "Only the first 32 files will be listed.\n"); 1443341487abSFeng Tang break; 1444341487abSFeng Tang } 1445341487abSFeng Tang } 1446341487abSFeng Tang closedir(pwd_dir); 1447341487abSFeng Tang 1448341487abSFeng Tang if (nr_options) { 1449341487abSFeng Tang choice = ui__popup_menu(nr_options, options); 1450341487abSFeng Tang if (choice < nr_options && choice >= 0) { 1451341487abSFeng Tang tmp = strdup(abs_path[choice]); 1452341487abSFeng Tang if (tmp) { 1453341487abSFeng Tang if (is_input_name_malloced) 1454341487abSFeng Tang free((void *)input_name); 1455341487abSFeng Tang input_name = tmp; 1456341487abSFeng Tang is_input_name_malloced = true; 1457341487abSFeng Tang ret = 0; 1458341487abSFeng Tang } else 1459341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 1460341487abSFeng Tang } 1461341487abSFeng Tang } 1462341487abSFeng Tang 1463341487abSFeng Tang free_popup_options(options, nr_options); 1464341487abSFeng Tang free_popup_options(abs_path, nr_options); 1465341487abSFeng Tang return ret; 1466341487abSFeng Tang } 1467341487abSFeng Tang 1468112f761fSNamhyung Kim static void hist_browser__update_nr_entries(struct hist_browser *hb) 1469064f1981SNamhyung Kim { 1470064f1981SNamhyung Kim u64 nr_entries = 0; 1471064f1981SNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 1472064f1981SNamhyung Kim 1473268397cbSNamhyung Kim if (hb->min_pcnt == 0) { 1474268397cbSNamhyung Kim hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 1475268397cbSNamhyung Kim return; 1476268397cbSNamhyung Kim } 1477268397cbSNamhyung Kim 147814135663SNamhyung Kim while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 1479064f1981SNamhyung Kim nr_entries++; 1480c481f930SNamhyung Kim nd = rb_next(nd); 1481064f1981SNamhyung Kim } 1482064f1981SNamhyung Kim 1483112f761fSNamhyung Kim hb->nr_non_filtered_entries = nr_entries; 1484064f1981SNamhyung Kim } 1485341487abSFeng Tang 1486aca7a94dSNamhyung Kim static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1487dd00d486SJiri Olsa const char *helpline, 1488aca7a94dSNamhyung Kim bool left_exits, 148968d80758SNamhyung Kim struct hist_browser_timer *hbt, 1490064f1981SNamhyung Kim float min_pcnt, 149168d80758SNamhyung Kim struct perf_session_env *env) 1492aca7a94dSNamhyung Kim { 149305e8b080SArnaldo Carvalho de Melo struct hists *hists = &evsel->hists; 149405e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = hist_browser__new(hists); 1495aca7a94dSNamhyung Kim struct branch_info *bi; 1496aca7a94dSNamhyung Kim struct pstack *fstack; 1497aca7a94dSNamhyung Kim char *options[16]; 1498aca7a94dSNamhyung Kim int nr_options = 0; 1499aca7a94dSNamhyung Kim int key = -1; 1500aca7a94dSNamhyung Kim char buf[64]; 1501cdbab7c2SFeng Tang char script_opt[64]; 15029783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 1503aca7a94dSNamhyung Kim 1504e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 1505e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 1506e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 1507e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 1508e8e684a5SNamhyung Kim "q/ESC/CTRL+C Exit browser\n\n" \ 1509e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 1510e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 1511e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 1512e8e684a5SNamhyung Kim "-> Zoom into DSO/Threads & Annotate current symbol\n" \ 1513e8e684a5SNamhyung Kim "<- Zoom out\n" \ 1514e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 1515e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 1516e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 1517e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 1518105eb30fSNamhyung Kim "F Toggle percentage of filtered entries\n" \ 1519025bf7eaSArnaldo Carvalho de Melo "H Display column headers\n" \ 1520e8e684a5SNamhyung Kim 1521e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 1522e8e684a5SNamhyung Kim const char report_help[] = HIST_BROWSER_HELP_COMMON 15236dd60135SNamhyung Kim "i Show header information\n" 1524e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 1525e8e684a5SNamhyung Kim "r Run available scripts\n" 1526e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 1527e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 1528e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 1529e8e684a5SNamhyung Kim "/ Filter symbol by name"; 1530e8e684a5SNamhyung Kim const char top_help[] = HIST_BROWSER_HELP_COMMON 1531e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 1532e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 1533e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 1534e8e684a5SNamhyung Kim "/ Filter symbol by name"; 1535e8e684a5SNamhyung Kim 1536aca7a94dSNamhyung Kim if (browser == NULL) 1537aca7a94dSNamhyung Kim return -1; 1538aca7a94dSNamhyung Kim 1539064f1981SNamhyung Kim if (min_pcnt) { 1540064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 1541112f761fSNamhyung Kim hist_browser__update_nr_entries(browser); 1542064f1981SNamhyung Kim } 1543064f1981SNamhyung Kim 1544aca7a94dSNamhyung Kim fstack = pstack__new(2); 1545aca7a94dSNamhyung Kim if (fstack == NULL) 1546aca7a94dSNamhyung Kim goto out; 1547aca7a94dSNamhyung Kim 1548aca7a94dSNamhyung Kim ui_helpline__push(helpline); 1549aca7a94dSNamhyung Kim 1550aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 1551aca7a94dSNamhyung Kim 1552aca7a94dSNamhyung Kim while (1) { 1553aca7a94dSNamhyung Kim const struct thread *thread = NULL; 1554aca7a94dSNamhyung Kim const struct dso *dso = NULL; 1555aca7a94dSNamhyung Kim int choice = 0, 1556aca7a94dSNamhyung Kim annotate = -2, zoom_dso = -2, zoom_thread = -2, 1557aca7a94dSNamhyung Kim annotate_f = -2, annotate_t = -2, browse_map = -2; 1558341487abSFeng Tang int scripts_comm = -2, scripts_symbol = -2, 1559341487abSFeng Tang scripts_all = -2, switch_data = -2; 1560aca7a94dSNamhyung Kim 1561aca7a94dSNamhyung Kim nr_options = 0; 1562aca7a94dSNamhyung Kim 1563dd00d486SJiri Olsa key = hist_browser__run(browser, hbt); 1564aca7a94dSNamhyung Kim 1565aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 1566aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 1567aca7a94dSNamhyung Kim dso = browser->selection->map ? browser->selection->map->dso : NULL; 1568aca7a94dSNamhyung Kim } 1569aca7a94dSNamhyung Kim switch (key) { 1570aca7a94dSNamhyung Kim case K_TAB: 1571aca7a94dSNamhyung Kim case K_UNTAB: 1572aca7a94dSNamhyung Kim if (nr_events == 1) 1573aca7a94dSNamhyung Kim continue; 1574aca7a94dSNamhyung Kim /* 1575aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 1576aca7a94dSNamhyung Kim * go to the next or previous 1577aca7a94dSNamhyung Kim */ 1578aca7a94dSNamhyung Kim goto out_free_stack; 1579aca7a94dSNamhyung Kim case 'a': 15809c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) { 1581aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 1582aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 1583aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 1584aca7a94dSNamhyung Kim continue; 1585aca7a94dSNamhyung Kim } 1586aca7a94dSNamhyung Kim 1587aca7a94dSNamhyung Kim if (browser->selection == NULL || 1588aca7a94dSNamhyung Kim browser->selection->sym == NULL || 1589aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 1590aca7a94dSNamhyung Kim continue; 1591aca7a94dSNamhyung Kim goto do_annotate; 1592aff3f3f6SArnaldo Carvalho de Melo case 'P': 1593aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 1594aff3f3f6SArnaldo Carvalho de Melo continue; 1595aca7a94dSNamhyung Kim case 'd': 1596aca7a94dSNamhyung Kim goto zoom_dso; 1597a7cb8863SArnaldo Carvalho de Melo case 'V': 1598a7cb8863SArnaldo Carvalho de Melo browser->show_dso = !browser->show_dso; 1599a7cb8863SArnaldo Carvalho de Melo continue; 1600aca7a94dSNamhyung Kim case 't': 1601aca7a94dSNamhyung Kim goto zoom_thread; 16025a5626b1SArnaldo Carvalho de Melo case '/': 1603aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 1604aca7a94dSNamhyung Kim "Please enter the name of symbol you want to see", 1605aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 1606aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 160705e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 160805e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 1609aca7a94dSNamhyung Kim hist_browser__reset(browser); 1610aca7a94dSNamhyung Kim } 1611aca7a94dSNamhyung Kim continue; 1612cdbab7c2SFeng Tang case 'r': 16139783adf7SNamhyung Kim if (is_report_browser(hbt)) 1614cdbab7c2SFeng Tang goto do_scripts; 1615c77d8d70SFeng Tang continue; 1616341487abSFeng Tang case 's': 1617341487abSFeng Tang if (is_report_browser(hbt)) 1618341487abSFeng Tang goto do_data_switch; 1619341487abSFeng Tang continue; 16206dd60135SNamhyung Kim case 'i': 16216dd60135SNamhyung Kim /* env->arch is NULL for live-mode (i.e. perf top) */ 16226dd60135SNamhyung Kim if (env->arch) 16236dd60135SNamhyung Kim tui__header_window(env); 16246dd60135SNamhyung Kim continue; 1625105eb30fSNamhyung Kim case 'F': 1626105eb30fSNamhyung Kim symbol_conf.filter_relative ^= 1; 1627105eb30fSNamhyung Kim continue; 1628aca7a94dSNamhyung Kim case K_F1: 1629aca7a94dSNamhyung Kim case 'h': 1630aca7a94dSNamhyung Kim case '?': 1631aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 1632e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 1633aca7a94dSNamhyung Kim continue; 1634aca7a94dSNamhyung Kim case K_ENTER: 1635aca7a94dSNamhyung Kim case K_RIGHT: 1636aca7a94dSNamhyung Kim /* menu */ 1637aca7a94dSNamhyung Kim break; 1638aca7a94dSNamhyung Kim case K_LEFT: { 1639aca7a94dSNamhyung Kim const void *top; 1640aca7a94dSNamhyung Kim 1641aca7a94dSNamhyung Kim if (pstack__empty(fstack)) { 1642aca7a94dSNamhyung Kim /* 1643aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 1644aca7a94dSNamhyung Kim */ 1645aca7a94dSNamhyung Kim if (left_exits) 1646aca7a94dSNamhyung Kim goto out_free_stack; 1647aca7a94dSNamhyung Kim continue; 1648aca7a94dSNamhyung Kim } 1649aca7a94dSNamhyung Kim top = pstack__pop(fstack); 1650aca7a94dSNamhyung Kim if (top == &browser->hists->dso_filter) 1651aca7a94dSNamhyung Kim goto zoom_out_dso; 1652aca7a94dSNamhyung Kim if (top == &browser->hists->thread_filter) 1653aca7a94dSNamhyung Kim goto zoom_out_thread; 1654aca7a94dSNamhyung Kim continue; 1655aca7a94dSNamhyung Kim } 1656aca7a94dSNamhyung Kim case K_ESC: 1657aca7a94dSNamhyung Kim if (!left_exits && 1658aca7a94dSNamhyung Kim !ui_browser__dialog_yesno(&browser->b, 1659aca7a94dSNamhyung Kim "Do you really want to exit?")) 1660aca7a94dSNamhyung Kim continue; 1661aca7a94dSNamhyung Kim /* Fall thru */ 1662aca7a94dSNamhyung Kim case 'q': 1663aca7a94dSNamhyung Kim case CTRL('c'): 1664aca7a94dSNamhyung Kim goto out_free_stack; 1665aca7a94dSNamhyung Kim default: 1666aca7a94dSNamhyung Kim continue; 1667aca7a94dSNamhyung Kim } 1668aca7a94dSNamhyung Kim 16699c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) 1670aca7a94dSNamhyung Kim goto add_exit_option; 1671aca7a94dSNamhyung Kim 167255369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 1673aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 1674aca7a94dSNamhyung Kim if (browser->selection != NULL && 1675aca7a94dSNamhyung Kim bi && 1676aca7a94dSNamhyung Kim bi->from.sym != NULL && 1677aca7a94dSNamhyung Kim !bi->from.map->dso->annotate_warned && 1678aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1679aca7a94dSNamhyung Kim bi->from.sym->name) > 0) 1680aca7a94dSNamhyung Kim annotate_f = nr_options++; 1681aca7a94dSNamhyung Kim 1682aca7a94dSNamhyung Kim if (browser->selection != NULL && 1683aca7a94dSNamhyung Kim bi && 1684aca7a94dSNamhyung Kim bi->to.sym != NULL && 1685aca7a94dSNamhyung Kim !bi->to.map->dso->annotate_warned && 1686aca7a94dSNamhyung Kim (bi->to.sym != bi->from.sym || 1687aca7a94dSNamhyung Kim bi->to.map->dso != bi->from.map->dso) && 1688aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1689aca7a94dSNamhyung Kim bi->to.sym->name) > 0) 1690aca7a94dSNamhyung Kim annotate_t = nr_options++; 1691aca7a94dSNamhyung Kim } else { 1692aca7a94dSNamhyung Kim if (browser->selection != NULL && 1693aca7a94dSNamhyung Kim browser->selection->sym != NULL && 1694d755330cSJiri Olsa !browser->selection->map->dso->annotate_warned) { 1695d755330cSJiri Olsa struct annotation *notes; 1696d755330cSJiri Olsa 1697d755330cSJiri Olsa notes = symbol__annotation(browser->selection->sym); 1698d755330cSJiri Olsa 1699d755330cSJiri Olsa if (notes->src && 1700aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1701aca7a94dSNamhyung Kim browser->selection->sym->name) > 0) 1702aca7a94dSNamhyung Kim annotate = nr_options++; 1703aca7a94dSNamhyung Kim } 1704d755330cSJiri Olsa } 1705aca7a94dSNamhyung Kim 1706aca7a94dSNamhyung Kim if (thread != NULL && 1707aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1708aca7a94dSNamhyung Kim (browser->hists->thread_filter ? "out of" : "into"), 1709b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 171038051234SAdrian Hunter thread->tid) > 0) 1711aca7a94dSNamhyung Kim zoom_thread = nr_options++; 1712aca7a94dSNamhyung Kim 1713aca7a94dSNamhyung Kim if (dso != NULL && 1714aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Zoom %s %s DSO", 1715aca7a94dSNamhyung Kim (browser->hists->dso_filter ? "out of" : "into"), 1716aca7a94dSNamhyung Kim (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 1717aca7a94dSNamhyung Kim zoom_dso = nr_options++; 1718aca7a94dSNamhyung Kim 1719aca7a94dSNamhyung Kim if (browser->selection != NULL && 1720aca7a94dSNamhyung Kim browser->selection->map != NULL && 1721aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Browse map details") > 0) 1722aca7a94dSNamhyung Kim browse_map = nr_options++; 1723cdbab7c2SFeng Tang 1724cdbab7c2SFeng Tang /* perf script support */ 1725cdbab7c2SFeng Tang if (browser->he_selection) { 1726cdbab7c2SFeng Tang struct symbol *sym; 1727cdbab7c2SFeng Tang 1728cdbab7c2SFeng Tang if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", 1729b9c5143aSFrederic Weisbecker thread__comm_str(browser->he_selection->thread)) > 0) 1730cdbab7c2SFeng Tang scripts_comm = nr_options++; 1731cdbab7c2SFeng Tang 1732cdbab7c2SFeng Tang sym = browser->he_selection->ms.sym; 1733cdbab7c2SFeng Tang if (sym && sym->namelen && 1734cdbab7c2SFeng Tang asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]", 1735cdbab7c2SFeng Tang sym->name) > 0) 1736cdbab7c2SFeng Tang scripts_symbol = nr_options++; 1737cdbab7c2SFeng Tang } 1738cdbab7c2SFeng Tang 1739cdbab7c2SFeng Tang if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) 1740cdbab7c2SFeng Tang scripts_all = nr_options++; 1741cdbab7c2SFeng Tang 1742341487abSFeng Tang if (is_report_browser(hbt) && asprintf(&options[nr_options], 1743341487abSFeng Tang "Switch to another data file in PWD") > 0) 1744341487abSFeng Tang switch_data = nr_options++; 1745aca7a94dSNamhyung Kim add_exit_option: 1746aca7a94dSNamhyung Kim options[nr_options++] = (char *)"Exit"; 1747aca7a94dSNamhyung Kim retry_popup_menu: 1748aca7a94dSNamhyung Kim choice = ui__popup_menu(nr_options, options); 1749aca7a94dSNamhyung Kim 1750aca7a94dSNamhyung Kim if (choice == nr_options - 1) 1751aca7a94dSNamhyung Kim break; 1752aca7a94dSNamhyung Kim 1753aca7a94dSNamhyung Kim if (choice == -1) { 1754aca7a94dSNamhyung Kim free_popup_options(options, nr_options - 1); 1755aca7a94dSNamhyung Kim continue; 1756aca7a94dSNamhyung Kim } 1757aca7a94dSNamhyung Kim 1758aca7a94dSNamhyung Kim if (choice == annotate || choice == annotate_t || choice == annotate_f) { 1759aca7a94dSNamhyung Kim struct hist_entry *he; 1760d755330cSJiri Olsa struct annotation *notes; 1761aca7a94dSNamhyung Kim int err; 1762aca7a94dSNamhyung Kim do_annotate: 176368d80758SNamhyung Kim if (!objdump_path && perf_session_env__lookup_objdump(env)) 176468d80758SNamhyung Kim continue; 176568d80758SNamhyung Kim 1766aca7a94dSNamhyung Kim he = hist_browser__selected_entry(browser); 1767aca7a94dSNamhyung Kim if (he == NULL) 1768aca7a94dSNamhyung Kim continue; 1769aca7a94dSNamhyung Kim 1770aca7a94dSNamhyung Kim /* 1771aca7a94dSNamhyung Kim * we stash the branch_info symbol + map into the 1772aca7a94dSNamhyung Kim * the ms so we don't have to rewrite all the annotation 1773aca7a94dSNamhyung Kim * code to use branch_info. 1774aca7a94dSNamhyung Kim * in branch mode, the ms struct is not used 1775aca7a94dSNamhyung Kim */ 1776aca7a94dSNamhyung Kim if (choice == annotate_f) { 1777aca7a94dSNamhyung Kim he->ms.sym = he->branch_info->from.sym; 1778aca7a94dSNamhyung Kim he->ms.map = he->branch_info->from.map; 1779aca7a94dSNamhyung Kim } else if (choice == annotate_t) { 1780aca7a94dSNamhyung Kim he->ms.sym = he->branch_info->to.sym; 1781aca7a94dSNamhyung Kim he->ms.map = he->branch_info->to.map; 1782aca7a94dSNamhyung Kim } 1783aca7a94dSNamhyung Kim 1784d755330cSJiri Olsa notes = symbol__annotation(he->ms.sym); 1785d755330cSJiri Olsa if (!notes->src) 1786d755330cSJiri Olsa continue; 1787d755330cSJiri Olsa 1788aca7a94dSNamhyung Kim /* 1789aca7a94dSNamhyung Kim * Don't let this be freed, say, by hists__decay_entry. 1790aca7a94dSNamhyung Kim */ 1791aca7a94dSNamhyung Kim he->used = true; 1792db8fd07aSNamhyung Kim err = hist_entry__tui_annotate(he, evsel, hbt); 1793aca7a94dSNamhyung Kim he->used = false; 1794aca7a94dSNamhyung Kim /* 1795aca7a94dSNamhyung Kim * offer option to annotate the other branch source or target 1796aca7a94dSNamhyung Kim * (if they exists) when returning from annotate 1797aca7a94dSNamhyung Kim */ 1798aca7a94dSNamhyung Kim if ((err == 'q' || err == CTRL('c')) 1799aca7a94dSNamhyung Kim && annotate_t != -2 && annotate_f != -2) 1800aca7a94dSNamhyung Kim goto retry_popup_menu; 1801aca7a94dSNamhyung Kim 1802aca7a94dSNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1803aca7a94dSNamhyung Kim if (err) 1804aca7a94dSNamhyung Kim ui_browser__handle_resize(&browser->b); 1805aca7a94dSNamhyung Kim 1806aca7a94dSNamhyung Kim } else if (choice == browse_map) 1807aca7a94dSNamhyung Kim map__browse(browser->selection->map); 1808aca7a94dSNamhyung Kim else if (choice == zoom_dso) { 1809aca7a94dSNamhyung Kim zoom_dso: 1810aca7a94dSNamhyung Kim if (browser->hists->dso_filter) { 1811aca7a94dSNamhyung Kim pstack__remove(fstack, &browser->hists->dso_filter); 1812aca7a94dSNamhyung Kim zoom_out_dso: 1813aca7a94dSNamhyung Kim ui_helpline__pop(); 1814aca7a94dSNamhyung Kim browser->hists->dso_filter = NULL; 1815f2998422SJiri Olsa perf_hpp__set_elide(HISTC_DSO, false); 1816aca7a94dSNamhyung Kim } else { 1817aca7a94dSNamhyung Kim if (dso == NULL) 1818aca7a94dSNamhyung Kim continue; 1819aca7a94dSNamhyung Kim ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1820aca7a94dSNamhyung Kim dso->kernel ? "the Kernel" : dso->short_name); 1821aca7a94dSNamhyung Kim browser->hists->dso_filter = dso; 1822f2998422SJiri Olsa perf_hpp__set_elide(HISTC_DSO, true); 1823aca7a94dSNamhyung Kim pstack__push(fstack, &browser->hists->dso_filter); 1824aca7a94dSNamhyung Kim } 182505e8b080SArnaldo Carvalho de Melo hists__filter_by_dso(hists); 1826aca7a94dSNamhyung Kim hist_browser__reset(browser); 1827aca7a94dSNamhyung Kim } else if (choice == zoom_thread) { 1828aca7a94dSNamhyung Kim zoom_thread: 1829aca7a94dSNamhyung Kim if (browser->hists->thread_filter) { 1830aca7a94dSNamhyung Kim pstack__remove(fstack, &browser->hists->thread_filter); 1831aca7a94dSNamhyung Kim zoom_out_thread: 1832aca7a94dSNamhyung Kim ui_helpline__pop(); 1833aca7a94dSNamhyung Kim browser->hists->thread_filter = NULL; 1834f2998422SJiri Olsa perf_hpp__set_elide(HISTC_THREAD, false); 1835aca7a94dSNamhyung Kim } else { 1836aca7a94dSNamhyung Kim ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1837b9c5143aSFrederic Weisbecker thread->comm_set ? thread__comm_str(thread) : "", 183838051234SAdrian Hunter thread->tid); 1839aca7a94dSNamhyung Kim browser->hists->thread_filter = thread; 1840f2998422SJiri Olsa perf_hpp__set_elide(HISTC_THREAD, false); 1841aca7a94dSNamhyung Kim pstack__push(fstack, &browser->hists->thread_filter); 1842aca7a94dSNamhyung Kim } 184305e8b080SArnaldo Carvalho de Melo hists__filter_by_thread(hists); 1844aca7a94dSNamhyung Kim hist_browser__reset(browser); 1845aca7a94dSNamhyung Kim } 1846cdbab7c2SFeng Tang /* perf scripts support */ 1847cdbab7c2SFeng Tang else if (choice == scripts_all || choice == scripts_comm || 1848cdbab7c2SFeng Tang choice == scripts_symbol) { 1849cdbab7c2SFeng Tang do_scripts: 1850cdbab7c2SFeng Tang memset(script_opt, 0, 64); 1851cdbab7c2SFeng Tang 1852cdbab7c2SFeng Tang if (choice == scripts_comm) 1853b9c5143aSFrederic Weisbecker sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread)); 1854cdbab7c2SFeng Tang 1855cdbab7c2SFeng Tang if (choice == scripts_symbol) 1856cdbab7c2SFeng Tang sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); 1857cdbab7c2SFeng Tang 1858cdbab7c2SFeng Tang script_browse(script_opt); 1859cdbab7c2SFeng Tang } 1860341487abSFeng Tang /* Switch to another data file */ 1861341487abSFeng Tang else if (choice == switch_data) { 1862341487abSFeng Tang do_data_switch: 1863341487abSFeng Tang if (!switch_data_file()) { 1864341487abSFeng Tang key = K_SWITCH_INPUT_DATA; 1865341487abSFeng Tang break; 1866341487abSFeng Tang } else 1867341487abSFeng Tang ui__warning("Won't switch the data files due to\n" 1868341487abSFeng Tang "no valid data file get selected!\n"); 1869341487abSFeng Tang } 1870aca7a94dSNamhyung Kim } 1871aca7a94dSNamhyung Kim out_free_stack: 1872aca7a94dSNamhyung Kim pstack__delete(fstack); 1873aca7a94dSNamhyung Kim out: 1874aca7a94dSNamhyung Kim hist_browser__delete(browser); 1875aca7a94dSNamhyung Kim free_popup_options(options, nr_options - 1); 1876aca7a94dSNamhyung Kim return key; 1877aca7a94dSNamhyung Kim } 1878aca7a94dSNamhyung Kim 1879aca7a94dSNamhyung Kim struct perf_evsel_menu { 1880aca7a94dSNamhyung Kim struct ui_browser b; 1881aca7a94dSNamhyung Kim struct perf_evsel *selection; 1882aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 1883064f1981SNamhyung Kim float min_pcnt; 188468d80758SNamhyung Kim struct perf_session_env *env; 1885aca7a94dSNamhyung Kim }; 1886aca7a94dSNamhyung Kim 1887aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 1888aca7a94dSNamhyung Kim void *entry, int row) 1889aca7a94dSNamhyung Kim { 1890aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 1891aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 1892aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1893aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 1894aca7a94dSNamhyung Kim unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 18957289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 1896aca7a94dSNamhyung Kim char bf[256], unit; 1897aca7a94dSNamhyung Kim const char *warn = " "; 1898aca7a94dSNamhyung Kim size_t printed; 1899aca7a94dSNamhyung Kim 1900aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1901aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 1902aca7a94dSNamhyung Kim 1903759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1904717e263fSNamhyung Kim struct perf_evsel *pos; 1905717e263fSNamhyung Kim 1906717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 1907717e263fSNamhyung Kim 1908717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 1909717e263fSNamhyung Kim nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1910717e263fSNamhyung Kim } 1911717e263fSNamhyung Kim } 1912717e263fSNamhyung Kim 1913aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 1914aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1915aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 1916aca7a94dSNamhyung Kim slsmg_printf("%s", bf); 1917aca7a94dSNamhyung Kim 1918aca7a94dSNamhyung Kim nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 1919aca7a94dSNamhyung Kim if (nr_events != 0) { 1920aca7a94dSNamhyung Kim menu->lost_events = true; 1921aca7a94dSNamhyung Kim if (!current_entry) 1922aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 1923aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 1924aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 1925aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 1926aca7a94dSNamhyung Kim warn = bf; 1927aca7a94dSNamhyung Kim } 1928aca7a94dSNamhyung Kim 1929aca7a94dSNamhyung Kim slsmg_write_nstring(warn, browser->width - printed); 1930aca7a94dSNamhyung Kim 1931aca7a94dSNamhyung Kim if (current_entry) 1932aca7a94dSNamhyung Kim menu->selection = evsel; 1933aca7a94dSNamhyung Kim } 1934aca7a94dSNamhyung Kim 1935aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 1936aca7a94dSNamhyung Kim int nr_events, const char *help, 19379783adf7SNamhyung Kim struct hist_browser_timer *hbt) 1938aca7a94dSNamhyung Kim { 1939aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 1940aca7a94dSNamhyung Kim struct perf_evsel *pos; 1941dd00d486SJiri Olsa const char *title = "Available samples"; 19429783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 1943aca7a94dSNamhyung Kim int key; 1944aca7a94dSNamhyung Kim 1945aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 1946aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 1947aca7a94dSNamhyung Kim return -1; 1948aca7a94dSNamhyung Kim 1949aca7a94dSNamhyung Kim while (1) { 1950aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 1951aca7a94dSNamhyung Kim 1952aca7a94dSNamhyung Kim switch (key) { 1953aca7a94dSNamhyung Kim case K_TIMER: 19549783adf7SNamhyung Kim hbt->timer(hbt->arg); 1955aca7a94dSNamhyung Kim 1956aca7a94dSNamhyung Kim if (!menu->lost_events_warned && menu->lost_events) { 1957aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 1958aca7a94dSNamhyung Kim menu->lost_events_warned = true; 1959aca7a94dSNamhyung Kim } 1960aca7a94dSNamhyung Kim continue; 1961aca7a94dSNamhyung Kim case K_RIGHT: 1962aca7a94dSNamhyung Kim case K_ENTER: 1963aca7a94dSNamhyung Kim if (!menu->selection) 1964aca7a94dSNamhyung Kim continue; 1965aca7a94dSNamhyung Kim pos = menu->selection; 1966aca7a94dSNamhyung Kim browse_hists: 1967aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 1968aca7a94dSNamhyung Kim /* 1969aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 1970aca7a94dSNamhyung Kim * default evsel resorted hists tree. 1971aca7a94dSNamhyung Kim */ 19729783adf7SNamhyung Kim if (hbt) 19739783adf7SNamhyung Kim hbt->timer(hbt->arg); 1974aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 1975dd00d486SJiri Olsa true, hbt, 1976064f1981SNamhyung Kim menu->min_pcnt, 197768d80758SNamhyung Kim menu->env); 1978aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 1979aca7a94dSNamhyung Kim switch (key) { 1980aca7a94dSNamhyung Kim case K_TAB: 1981aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 19829a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__first(evlist); 1983aca7a94dSNamhyung Kim else 19849a354cdcSArnaldo Carvalho de Melo pos = perf_evsel__next(pos); 1985aca7a94dSNamhyung Kim goto browse_hists; 1986aca7a94dSNamhyung Kim case K_UNTAB: 1987aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 19889a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__last(evlist); 1989aca7a94dSNamhyung Kim else 1990d87fcb4aSArnaldo Carvalho de Melo pos = perf_evsel__prev(pos); 1991aca7a94dSNamhyung Kim goto browse_hists; 1992aca7a94dSNamhyung Kim case K_ESC: 1993aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 1994aca7a94dSNamhyung Kim "Do you really want to exit?")) 1995aca7a94dSNamhyung Kim continue; 1996aca7a94dSNamhyung Kim /* Fall thru */ 1997341487abSFeng Tang case K_SWITCH_INPUT_DATA: 1998aca7a94dSNamhyung Kim case 'q': 1999aca7a94dSNamhyung Kim case CTRL('c'): 2000aca7a94dSNamhyung Kim goto out; 2001aca7a94dSNamhyung Kim default: 2002aca7a94dSNamhyung Kim continue; 2003aca7a94dSNamhyung Kim } 2004aca7a94dSNamhyung Kim case K_LEFT: 2005aca7a94dSNamhyung Kim continue; 2006aca7a94dSNamhyung Kim case K_ESC: 2007aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 2008aca7a94dSNamhyung Kim "Do you really want to exit?")) 2009aca7a94dSNamhyung Kim continue; 2010aca7a94dSNamhyung Kim /* Fall thru */ 2011aca7a94dSNamhyung Kim case 'q': 2012aca7a94dSNamhyung Kim case CTRL('c'): 2013aca7a94dSNamhyung Kim goto out; 2014aca7a94dSNamhyung Kim default: 2015aca7a94dSNamhyung Kim continue; 2016aca7a94dSNamhyung Kim } 2017aca7a94dSNamhyung Kim } 2018aca7a94dSNamhyung Kim 2019aca7a94dSNamhyung Kim out: 2020aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 2021aca7a94dSNamhyung Kim return key; 2022aca7a94dSNamhyung Kim } 2023aca7a94dSNamhyung Kim 2024316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 2025fc24d7c2SNamhyung Kim void *entry) 2026fc24d7c2SNamhyung Kim { 2027fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 2028fc24d7c2SNamhyung Kim 2029fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 2030fc24d7c2SNamhyung Kim return true; 2031fc24d7c2SNamhyung Kim 2032fc24d7c2SNamhyung Kim return false; 2033fc24d7c2SNamhyung Kim } 2034fc24d7c2SNamhyung Kim 2035aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 2036fc24d7c2SNamhyung Kim int nr_entries, const char *help, 203768d80758SNamhyung Kim struct hist_browser_timer *hbt, 2038064f1981SNamhyung Kim float min_pcnt, 203968d80758SNamhyung Kim struct perf_session_env *env) 2040aca7a94dSNamhyung Kim { 2041aca7a94dSNamhyung Kim struct perf_evsel *pos; 2042aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 2043aca7a94dSNamhyung Kim .b = { 2044aca7a94dSNamhyung Kim .entries = &evlist->entries, 2045aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 2046aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 2047aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 2048fc24d7c2SNamhyung Kim .filter = filter_group_entries, 2049fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 2050aca7a94dSNamhyung Kim .priv = evlist, 2051aca7a94dSNamhyung Kim }, 2052064f1981SNamhyung Kim .min_pcnt = min_pcnt, 205368d80758SNamhyung Kim .env = env, 2054aca7a94dSNamhyung Kim }; 2055aca7a94dSNamhyung Kim 2056aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 2057aca7a94dSNamhyung Kim 20580050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 20597289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 2060aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 2061aca7a94dSNamhyung Kim 2062aca7a94dSNamhyung Kim if (menu.b.width < line_len) 2063aca7a94dSNamhyung Kim menu.b.width = line_len; 2064aca7a94dSNamhyung Kim } 2065aca7a94dSNamhyung Kim 2066fc24d7c2SNamhyung Kim return perf_evsel_menu__run(&menu, nr_entries, help, hbt); 2067aca7a94dSNamhyung Kim } 2068aca7a94dSNamhyung Kim 2069aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 207068d80758SNamhyung Kim struct hist_browser_timer *hbt, 2071064f1981SNamhyung Kim float min_pcnt, 207268d80758SNamhyung Kim struct perf_session_env *env) 2073aca7a94dSNamhyung Kim { 2074fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 2075fc24d7c2SNamhyung Kim 2076fc24d7c2SNamhyung Kim single_entry: 2077fc24d7c2SNamhyung Kim if (nr_entries == 1) { 20789a354cdcSArnaldo Carvalho de Melo struct perf_evsel *first = perf_evlist__first(evlist); 2079fc24d7c2SNamhyung Kim 2080fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 2081dd00d486SJiri Olsa false, hbt, min_pcnt, 2082064f1981SNamhyung Kim env); 2083aca7a94dSNamhyung Kim } 2084aca7a94dSNamhyung Kim 2085fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 2086fc24d7c2SNamhyung Kim struct perf_evsel *pos; 2087fc24d7c2SNamhyung Kim 2088fc24d7c2SNamhyung Kim nr_entries = 0; 20890050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 2090fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 2091fc24d7c2SNamhyung Kim nr_entries++; 20920050f7aaSArnaldo Carvalho de Melo } 2093fc24d7c2SNamhyung Kim 2094fc24d7c2SNamhyung Kim if (nr_entries == 1) 2095fc24d7c2SNamhyung Kim goto single_entry; 2096fc24d7c2SNamhyung Kim } 2097fc24d7c2SNamhyung Kim 2098fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 2099064f1981SNamhyung Kim hbt, min_pcnt, env); 2100aca7a94dSNamhyung Kim } 2101