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" 20aca7a94dSNamhyung Kim 21aca7a94dSNamhyung Kim struct hist_browser { 22aca7a94dSNamhyung Kim struct ui_browser b; 23aca7a94dSNamhyung Kim struct hists *hists; 24aca7a94dSNamhyung Kim struct hist_entry *he_selection; 25aca7a94dSNamhyung Kim struct map_symbol *selection; 26aff3f3f6SArnaldo Carvalho de Melo int print_seq; 27a7cb8863SArnaldo Carvalho de Melo bool show_dso; 28064f1981SNamhyung Kim float min_pcnt; 29064f1981SNamhyung Kim u64 nr_pcnt_entries; 30aca7a94dSNamhyung Kim }; 31aca7a94dSNamhyung Kim 32f5951d56SNamhyung Kim extern void hist_browser__init_hpp(void); 33f5951d56SNamhyung Kim 3405e8b080SArnaldo Carvalho de Melo static int hists__browser_title(struct hists *hists, char *bf, size_t size, 35aca7a94dSNamhyung Kim const char *ev_name); 36aca7a94dSNamhyung Kim 3705e8b080SArnaldo Carvalho de Melo static void hist_browser__refresh_dimensions(struct hist_browser *browser) 38aca7a94dSNamhyung Kim { 39aca7a94dSNamhyung Kim /* 3 == +/- toggle symbol before actual hist_entry rendering */ 4005e8b080SArnaldo Carvalho de Melo browser->b.width = 3 + (hists__sort_list_width(browser->hists) + 41aca7a94dSNamhyung Kim sizeof("[k]")); 42aca7a94dSNamhyung Kim } 43aca7a94dSNamhyung Kim 4405e8b080SArnaldo Carvalho de Melo static void hist_browser__reset(struct hist_browser *browser) 45aca7a94dSNamhyung Kim { 4605e8b080SArnaldo Carvalho de Melo browser->b.nr_entries = browser->hists->nr_entries; 4705e8b080SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(browser); 4805e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 49aca7a94dSNamhyung Kim } 50aca7a94dSNamhyung Kim 51aca7a94dSNamhyung Kim static char tree__folded_sign(bool unfolded) 52aca7a94dSNamhyung Kim { 53aca7a94dSNamhyung Kim return unfolded ? '-' : '+'; 54aca7a94dSNamhyung Kim } 55aca7a94dSNamhyung Kim 5605e8b080SArnaldo Carvalho de Melo static char map_symbol__folded(const struct map_symbol *ms) 57aca7a94dSNamhyung Kim { 5805e8b080SArnaldo Carvalho de Melo return ms->has_children ? tree__folded_sign(ms->unfolded) : ' '; 59aca7a94dSNamhyung Kim } 60aca7a94dSNamhyung Kim 6105e8b080SArnaldo Carvalho de Melo static char hist_entry__folded(const struct hist_entry *he) 62aca7a94dSNamhyung Kim { 6305e8b080SArnaldo Carvalho de Melo return map_symbol__folded(&he->ms); 64aca7a94dSNamhyung Kim } 65aca7a94dSNamhyung Kim 6605e8b080SArnaldo Carvalho de Melo static char callchain_list__folded(const struct callchain_list *cl) 67aca7a94dSNamhyung Kim { 6805e8b080SArnaldo Carvalho de Melo return map_symbol__folded(&cl->ms); 69aca7a94dSNamhyung Kim } 70aca7a94dSNamhyung Kim 7105e8b080SArnaldo Carvalho de Melo static void map_symbol__set_folding(struct map_symbol *ms, bool unfold) 72aca7a94dSNamhyung Kim { 7305e8b080SArnaldo Carvalho de Melo ms->unfolded = unfold ? ms->has_children : false; 74aca7a94dSNamhyung Kim } 75aca7a94dSNamhyung Kim 7605e8b080SArnaldo Carvalho de Melo static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 77aca7a94dSNamhyung Kim { 78aca7a94dSNamhyung Kim int n = 0; 79aca7a94dSNamhyung Kim struct rb_node *nd; 80aca7a94dSNamhyung Kim 8105e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 82aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 83aca7a94dSNamhyung Kim struct callchain_list *chain; 84aca7a94dSNamhyung Kim char folded_sign = ' '; /* No children */ 85aca7a94dSNamhyung Kim 86aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 87aca7a94dSNamhyung Kim ++n; 88aca7a94dSNamhyung Kim /* We need this because we may not have children */ 89aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 90aca7a94dSNamhyung Kim if (folded_sign == '+') 91aca7a94dSNamhyung Kim break; 92aca7a94dSNamhyung Kim } 93aca7a94dSNamhyung Kim 94aca7a94dSNamhyung Kim if (folded_sign == '-') /* Have children and they're unfolded */ 95aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(child); 96aca7a94dSNamhyung Kim } 97aca7a94dSNamhyung Kim 98aca7a94dSNamhyung Kim return n; 99aca7a94dSNamhyung Kim } 100aca7a94dSNamhyung Kim 101aca7a94dSNamhyung Kim static int callchain_node__count_rows(struct callchain_node *node) 102aca7a94dSNamhyung Kim { 103aca7a94dSNamhyung Kim struct callchain_list *chain; 104aca7a94dSNamhyung Kim bool unfolded = false; 105aca7a94dSNamhyung Kim int n = 0; 106aca7a94dSNamhyung Kim 107aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 108aca7a94dSNamhyung Kim ++n; 109aca7a94dSNamhyung Kim unfolded = chain->ms.unfolded; 110aca7a94dSNamhyung Kim } 111aca7a94dSNamhyung Kim 112aca7a94dSNamhyung Kim if (unfolded) 113aca7a94dSNamhyung Kim n += callchain_node__count_rows_rb_tree(node); 114aca7a94dSNamhyung Kim 115aca7a94dSNamhyung Kim return n; 116aca7a94dSNamhyung Kim } 117aca7a94dSNamhyung Kim 118aca7a94dSNamhyung Kim static int callchain__count_rows(struct rb_root *chain) 119aca7a94dSNamhyung Kim { 120aca7a94dSNamhyung Kim struct rb_node *nd; 121aca7a94dSNamhyung Kim int n = 0; 122aca7a94dSNamhyung Kim 123aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 124aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 125aca7a94dSNamhyung Kim n += callchain_node__count_rows(node); 126aca7a94dSNamhyung Kim } 127aca7a94dSNamhyung Kim 128aca7a94dSNamhyung Kim return n; 129aca7a94dSNamhyung Kim } 130aca7a94dSNamhyung Kim 13105e8b080SArnaldo Carvalho de Melo static bool map_symbol__toggle_fold(struct map_symbol *ms) 132aca7a94dSNamhyung Kim { 13305e8b080SArnaldo Carvalho de Melo if (!ms) 134aca7a94dSNamhyung Kim return false; 135aca7a94dSNamhyung Kim 13605e8b080SArnaldo Carvalho de Melo if (!ms->has_children) 137aca7a94dSNamhyung Kim return false; 138aca7a94dSNamhyung Kim 13905e8b080SArnaldo Carvalho de Melo ms->unfolded = !ms->unfolded; 140aca7a94dSNamhyung Kim return true; 141aca7a94dSNamhyung Kim } 142aca7a94dSNamhyung Kim 14305e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children_rb_tree(struct callchain_node *node) 144aca7a94dSNamhyung Kim { 14505e8b080SArnaldo Carvalho de Melo struct rb_node *nd = rb_first(&node->rb_root); 146aca7a94dSNamhyung Kim 14705e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 148aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 149aca7a94dSNamhyung Kim struct callchain_list *chain; 150aca7a94dSNamhyung Kim bool first = true; 151aca7a94dSNamhyung Kim 152aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 153aca7a94dSNamhyung Kim if (first) { 154aca7a94dSNamhyung Kim first = false; 155aca7a94dSNamhyung Kim chain->ms.has_children = chain->list.next != &child->val || 156aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 157aca7a94dSNamhyung Kim } else 158aca7a94dSNamhyung Kim chain->ms.has_children = chain->list.next == &child->val && 159aca7a94dSNamhyung Kim !RB_EMPTY_ROOT(&child->rb_root); 160aca7a94dSNamhyung Kim } 161aca7a94dSNamhyung Kim 162aca7a94dSNamhyung Kim callchain_node__init_have_children_rb_tree(child); 163aca7a94dSNamhyung Kim } 164aca7a94dSNamhyung Kim } 165aca7a94dSNamhyung Kim 16605e8b080SArnaldo Carvalho de Melo static void callchain_node__init_have_children(struct callchain_node *node) 167aca7a94dSNamhyung Kim { 168aca7a94dSNamhyung Kim struct callchain_list *chain; 169aca7a94dSNamhyung Kim 17005e8b080SArnaldo Carvalho de Melo list_for_each_entry(chain, &node->val, list) 17105e8b080SArnaldo Carvalho de Melo chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); 172aca7a94dSNamhyung Kim 17305e8b080SArnaldo Carvalho de Melo callchain_node__init_have_children_rb_tree(node); 174aca7a94dSNamhyung Kim } 175aca7a94dSNamhyung Kim 17605e8b080SArnaldo Carvalho de Melo static void callchain__init_have_children(struct rb_root *root) 177aca7a94dSNamhyung Kim { 178aca7a94dSNamhyung Kim struct rb_node *nd; 179aca7a94dSNamhyung Kim 18005e8b080SArnaldo Carvalho de Melo for (nd = rb_first(root); nd; nd = rb_next(nd)) { 181aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 182aca7a94dSNamhyung Kim callchain_node__init_have_children(node); 183aca7a94dSNamhyung Kim } 184aca7a94dSNamhyung Kim } 185aca7a94dSNamhyung Kim 18605e8b080SArnaldo Carvalho de Melo static void hist_entry__init_have_children(struct hist_entry *he) 187aca7a94dSNamhyung Kim { 18805e8b080SArnaldo Carvalho de Melo if (!he->init_have_children) { 18905e8b080SArnaldo Carvalho de Melo he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 19005e8b080SArnaldo Carvalho de Melo callchain__init_have_children(&he->sorted_chain); 19105e8b080SArnaldo Carvalho de Melo he->init_have_children = true; 192aca7a94dSNamhyung Kim } 193aca7a94dSNamhyung Kim } 194aca7a94dSNamhyung Kim 19505e8b080SArnaldo Carvalho de Melo static bool hist_browser__toggle_fold(struct hist_browser *browser) 196aca7a94dSNamhyung Kim { 19705e8b080SArnaldo Carvalho de Melo if (map_symbol__toggle_fold(browser->selection)) { 19805e8b080SArnaldo Carvalho de Melo struct hist_entry *he = browser->he_selection; 199aca7a94dSNamhyung Kim 200aca7a94dSNamhyung Kim hist_entry__init_have_children(he); 20105e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries -= he->nr_rows; 202aca7a94dSNamhyung Kim 203aca7a94dSNamhyung Kim if (he->ms.unfolded) 204aca7a94dSNamhyung Kim he->nr_rows = callchain__count_rows(&he->sorted_chain); 205aca7a94dSNamhyung Kim else 206aca7a94dSNamhyung Kim he->nr_rows = 0; 20705e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries += he->nr_rows; 20805e8b080SArnaldo Carvalho de Melo browser->b.nr_entries = browser->hists->nr_entries; 209aca7a94dSNamhyung Kim 210aca7a94dSNamhyung Kim return true; 211aca7a94dSNamhyung Kim } 212aca7a94dSNamhyung Kim 213aca7a94dSNamhyung Kim /* If it doesn't have children, no toggling performed */ 214aca7a94dSNamhyung Kim return false; 215aca7a94dSNamhyung Kim } 216aca7a94dSNamhyung Kim 21705e8b080SArnaldo Carvalho de Melo static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold) 218aca7a94dSNamhyung Kim { 219aca7a94dSNamhyung Kim int n = 0; 220aca7a94dSNamhyung Kim struct rb_node *nd; 221aca7a94dSNamhyung Kim 22205e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 223aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 224aca7a94dSNamhyung Kim struct callchain_list *chain; 225aca7a94dSNamhyung Kim bool has_children = false; 226aca7a94dSNamhyung Kim 227aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 228aca7a94dSNamhyung Kim ++n; 229aca7a94dSNamhyung Kim map_symbol__set_folding(&chain->ms, unfold); 230aca7a94dSNamhyung Kim has_children = chain->ms.has_children; 231aca7a94dSNamhyung Kim } 232aca7a94dSNamhyung Kim 233aca7a94dSNamhyung Kim if (has_children) 234aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(child, unfold); 235aca7a94dSNamhyung Kim } 236aca7a94dSNamhyung Kim 237aca7a94dSNamhyung Kim return n; 238aca7a94dSNamhyung Kim } 239aca7a94dSNamhyung Kim 240aca7a94dSNamhyung Kim static int callchain_node__set_folding(struct callchain_node *node, bool unfold) 241aca7a94dSNamhyung Kim { 242aca7a94dSNamhyung Kim struct callchain_list *chain; 243aca7a94dSNamhyung Kim bool has_children = false; 244aca7a94dSNamhyung Kim int n = 0; 245aca7a94dSNamhyung Kim 246aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 247aca7a94dSNamhyung Kim ++n; 248aca7a94dSNamhyung Kim map_symbol__set_folding(&chain->ms, unfold); 249aca7a94dSNamhyung Kim has_children = chain->ms.has_children; 250aca7a94dSNamhyung Kim } 251aca7a94dSNamhyung Kim 252aca7a94dSNamhyung Kim if (has_children) 253aca7a94dSNamhyung Kim n += callchain_node__set_folding_rb_tree(node, unfold); 254aca7a94dSNamhyung Kim 255aca7a94dSNamhyung Kim return n; 256aca7a94dSNamhyung Kim } 257aca7a94dSNamhyung Kim 258aca7a94dSNamhyung Kim static int callchain__set_folding(struct rb_root *chain, bool unfold) 259aca7a94dSNamhyung Kim { 260aca7a94dSNamhyung Kim struct rb_node *nd; 261aca7a94dSNamhyung Kim int n = 0; 262aca7a94dSNamhyung Kim 263aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 264aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 265aca7a94dSNamhyung Kim n += callchain_node__set_folding(node, unfold); 266aca7a94dSNamhyung Kim } 267aca7a94dSNamhyung Kim 268aca7a94dSNamhyung Kim return n; 269aca7a94dSNamhyung Kim } 270aca7a94dSNamhyung Kim 27105e8b080SArnaldo Carvalho de Melo static void hist_entry__set_folding(struct hist_entry *he, bool unfold) 272aca7a94dSNamhyung Kim { 27305e8b080SArnaldo Carvalho de Melo hist_entry__init_have_children(he); 27405e8b080SArnaldo Carvalho de Melo map_symbol__set_folding(&he->ms, unfold); 275aca7a94dSNamhyung Kim 27605e8b080SArnaldo Carvalho de Melo if (he->ms.has_children) { 27705e8b080SArnaldo Carvalho de Melo int n = callchain__set_folding(&he->sorted_chain, unfold); 27805e8b080SArnaldo Carvalho de Melo he->nr_rows = unfold ? n : 0; 279aca7a94dSNamhyung Kim } else 28005e8b080SArnaldo Carvalho de Melo he->nr_rows = 0; 281aca7a94dSNamhyung Kim } 282aca7a94dSNamhyung Kim 28305e8b080SArnaldo Carvalho de Melo static void hists__set_folding(struct hists *hists, bool unfold) 284aca7a94dSNamhyung Kim { 285aca7a94dSNamhyung Kim struct rb_node *nd; 286aca7a94dSNamhyung Kim 28705e8b080SArnaldo Carvalho de Melo hists->nr_entries = 0; 288aca7a94dSNamhyung Kim 28905e8b080SArnaldo Carvalho de Melo for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 290aca7a94dSNamhyung Kim struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 291aca7a94dSNamhyung Kim hist_entry__set_folding(he, unfold); 29205e8b080SArnaldo Carvalho de Melo hists->nr_entries += 1 + he->nr_rows; 293aca7a94dSNamhyung Kim } 294aca7a94dSNamhyung Kim } 295aca7a94dSNamhyung Kim 29605e8b080SArnaldo Carvalho de Melo static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 297aca7a94dSNamhyung Kim { 29805e8b080SArnaldo Carvalho de Melo hists__set_folding(browser->hists, unfold); 29905e8b080SArnaldo Carvalho de Melo browser->b.nr_entries = browser->hists->nr_entries; 300aca7a94dSNamhyung Kim /* Go to the start, we may be way after valid entries after a collapse */ 30105e8b080SArnaldo Carvalho de Melo ui_browser__reset_index(&browser->b); 302aca7a94dSNamhyung Kim } 303aca7a94dSNamhyung Kim 304aca7a94dSNamhyung Kim static void ui_browser__warn_lost_events(struct ui_browser *browser) 305aca7a94dSNamhyung Kim { 306aca7a94dSNamhyung Kim ui_browser__warning(browser, 4, 307aca7a94dSNamhyung Kim "Events are being lost, check IO/CPU overload!\n\n" 308aca7a94dSNamhyung Kim "You may want to run 'perf' using a RT scheduler policy:\n\n" 309aca7a94dSNamhyung Kim " perf top -r 80\n\n" 310aca7a94dSNamhyung Kim "Or reduce the sampling frequency."); 311aca7a94dSNamhyung Kim } 312aca7a94dSNamhyung Kim 313fa5df943SNamhyung Kim static void hist_browser__update_pcnt_entries(struct hist_browser *hb); 314fa5df943SNamhyung Kim 31505e8b080SArnaldo Carvalho de Melo static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 3169783adf7SNamhyung Kim struct hist_browser_timer *hbt) 317aca7a94dSNamhyung Kim { 318aca7a94dSNamhyung Kim int key; 319aca7a94dSNamhyung Kim char title[160]; 3209783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 321aca7a94dSNamhyung Kim 32205e8b080SArnaldo Carvalho de Melo browser->b.entries = &browser->hists->entries; 32305e8b080SArnaldo Carvalho de Melo browser->b.nr_entries = browser->hists->nr_entries; 324064f1981SNamhyung Kim if (browser->min_pcnt) 325064f1981SNamhyung Kim browser->b.nr_entries = browser->nr_pcnt_entries; 326aca7a94dSNamhyung Kim 32705e8b080SArnaldo Carvalho de Melo hist_browser__refresh_dimensions(browser); 32805e8b080SArnaldo Carvalho de Melo hists__browser_title(browser->hists, title, sizeof(title), ev_name); 329aca7a94dSNamhyung Kim 33005e8b080SArnaldo Carvalho de Melo if (ui_browser__show(&browser->b, title, 331aca7a94dSNamhyung Kim "Press '?' for help on key bindings") < 0) 332aca7a94dSNamhyung Kim return -1; 333aca7a94dSNamhyung Kim 334aca7a94dSNamhyung Kim while (1) { 33505e8b080SArnaldo Carvalho de Melo key = ui_browser__run(&browser->b, delay_secs); 336aca7a94dSNamhyung Kim 337aca7a94dSNamhyung Kim switch (key) { 338fa5df943SNamhyung Kim case K_TIMER: { 339fa5df943SNamhyung Kim u64 nr_entries; 3409783adf7SNamhyung Kim hbt->timer(hbt->arg); 341fa5df943SNamhyung Kim 342fa5df943SNamhyung Kim if (browser->min_pcnt) { 343fa5df943SNamhyung Kim hist_browser__update_pcnt_entries(browser); 344fa5df943SNamhyung Kim nr_entries = browser->nr_pcnt_entries; 345fa5df943SNamhyung Kim } else { 346fa5df943SNamhyung Kim nr_entries = browser->hists->nr_entries; 347fa5df943SNamhyung Kim } 348fa5df943SNamhyung Kim 349fa5df943SNamhyung Kim ui_browser__update_nr_entries(&browser->b, nr_entries); 350aca7a94dSNamhyung Kim 35105e8b080SArnaldo Carvalho de Melo if (browser->hists->stats.nr_lost_warned != 35205e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]) { 35305e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_lost_warned = 35405e8b080SArnaldo Carvalho de Melo browser->hists->stats.nr_events[PERF_RECORD_LOST]; 35505e8b080SArnaldo Carvalho de Melo ui_browser__warn_lost_events(&browser->b); 356aca7a94dSNamhyung Kim } 357aca7a94dSNamhyung Kim 35805e8b080SArnaldo Carvalho de Melo hists__browser_title(browser->hists, title, sizeof(title), ev_name); 35905e8b080SArnaldo Carvalho de Melo ui_browser__show_title(&browser->b, title); 360aca7a94dSNamhyung Kim continue; 361fa5df943SNamhyung Kim } 362aca7a94dSNamhyung Kim case 'D': { /* Debug */ 363aca7a94dSNamhyung Kim static int seq; 36405e8b080SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(browser->b.top, 365aca7a94dSNamhyung Kim struct hist_entry, rb_node); 366aca7a94dSNamhyung Kim ui_helpline__pop(); 367aca7a94dSNamhyung Kim ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", 36805e8b080SArnaldo Carvalho de Melo seq++, browser->b.nr_entries, 36905e8b080SArnaldo Carvalho de Melo browser->hists->nr_entries, 37005e8b080SArnaldo Carvalho de Melo browser->b.height, 37105e8b080SArnaldo Carvalho de Melo browser->b.index, 37205e8b080SArnaldo Carvalho de Melo browser->b.top_idx, 373aca7a94dSNamhyung Kim h->row_offset, h->nr_rows); 374aca7a94dSNamhyung Kim } 375aca7a94dSNamhyung Kim break; 376aca7a94dSNamhyung Kim case 'C': 377aca7a94dSNamhyung Kim /* Collapse the whole world. */ 37805e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, false); 379aca7a94dSNamhyung Kim break; 380aca7a94dSNamhyung Kim case 'E': 381aca7a94dSNamhyung Kim /* Expand the whole world. */ 38205e8b080SArnaldo Carvalho de Melo hist_browser__set_folding(browser, true); 383aca7a94dSNamhyung Kim break; 384aca7a94dSNamhyung Kim case K_ENTER: 38505e8b080SArnaldo Carvalho de Melo if (hist_browser__toggle_fold(browser)) 386aca7a94dSNamhyung Kim break; 387aca7a94dSNamhyung Kim /* fall thru */ 388aca7a94dSNamhyung Kim default: 389aca7a94dSNamhyung Kim goto out; 390aca7a94dSNamhyung Kim } 391aca7a94dSNamhyung Kim } 392aca7a94dSNamhyung Kim out: 39305e8b080SArnaldo Carvalho de Melo ui_browser__hide(&browser->b); 394aca7a94dSNamhyung Kim return key; 395aca7a94dSNamhyung Kim } 396aca7a94dSNamhyung Kim 39705e8b080SArnaldo Carvalho de Melo static char *callchain_list__sym_name(struct callchain_list *cl, 398a7cb8863SArnaldo Carvalho de Melo char *bf, size_t bfsize, bool show_dso) 399aca7a94dSNamhyung Kim { 400a7cb8863SArnaldo Carvalho de Melo int printed; 401aca7a94dSNamhyung Kim 402a7cb8863SArnaldo Carvalho de Melo if (cl->ms.sym) 403a7cb8863SArnaldo Carvalho de Melo printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name); 404a7cb8863SArnaldo Carvalho de Melo else 405a7cb8863SArnaldo Carvalho de Melo printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip); 406a7cb8863SArnaldo Carvalho de Melo 407a7cb8863SArnaldo Carvalho de Melo if (show_dso) 408a7cb8863SArnaldo Carvalho de Melo scnprintf(bf + printed, bfsize - printed, " %s", 409a7cb8863SArnaldo Carvalho de Melo cl->ms.map ? cl->ms.map->dso->short_name : "unknown"); 410a7cb8863SArnaldo Carvalho de Melo 411aca7a94dSNamhyung Kim return bf; 412aca7a94dSNamhyung Kim } 413aca7a94dSNamhyung Kim 414aca7a94dSNamhyung Kim #define LEVEL_OFFSET_STEP 3 415aca7a94dSNamhyung Kim 41605e8b080SArnaldo Carvalho de Melo static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser, 417aca7a94dSNamhyung Kim struct callchain_node *chain_node, 418aca7a94dSNamhyung Kim u64 total, int level, 419aca7a94dSNamhyung Kim unsigned short row, 420aca7a94dSNamhyung Kim off_t *row_offset, 421aca7a94dSNamhyung Kim bool *is_current_entry) 422aca7a94dSNamhyung Kim { 423aca7a94dSNamhyung Kim struct rb_node *node; 424aca7a94dSNamhyung Kim int first_row = row, width, offset = level * LEVEL_OFFSET_STEP; 425aca7a94dSNamhyung Kim u64 new_total, remaining; 426aca7a94dSNamhyung Kim 427aca7a94dSNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 428aca7a94dSNamhyung Kim new_total = chain_node->children_hit; 429aca7a94dSNamhyung Kim else 430aca7a94dSNamhyung Kim new_total = total; 431aca7a94dSNamhyung Kim 432aca7a94dSNamhyung Kim remaining = new_total; 433aca7a94dSNamhyung Kim node = rb_first(&chain_node->rb_root); 434aca7a94dSNamhyung Kim while (node) { 435aca7a94dSNamhyung Kim struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 436aca7a94dSNamhyung Kim struct rb_node *next = rb_next(node); 437aca7a94dSNamhyung Kim u64 cumul = callchain_cumul_hits(child); 438aca7a94dSNamhyung Kim struct callchain_list *chain; 439aca7a94dSNamhyung Kim char folded_sign = ' '; 440aca7a94dSNamhyung Kim int first = true; 441aca7a94dSNamhyung Kim int extra_offset = 0; 442aca7a94dSNamhyung Kim 443aca7a94dSNamhyung Kim remaining -= cumul; 444aca7a94dSNamhyung Kim 445aca7a94dSNamhyung Kim list_for_each_entry(chain, &child->val, list) { 446a7cb8863SArnaldo Carvalho de Melo char bf[1024], *alloc_str; 447aca7a94dSNamhyung Kim const char *str; 448aca7a94dSNamhyung Kim int color; 449aca7a94dSNamhyung Kim bool was_first = first; 450aca7a94dSNamhyung Kim 451aca7a94dSNamhyung Kim if (first) 452aca7a94dSNamhyung Kim first = false; 453aca7a94dSNamhyung Kim else 454aca7a94dSNamhyung Kim extra_offset = LEVEL_OFFSET_STEP; 455aca7a94dSNamhyung Kim 456aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 457aca7a94dSNamhyung Kim if (*row_offset != 0) { 458aca7a94dSNamhyung Kim --*row_offset; 459aca7a94dSNamhyung Kim goto do_next; 460aca7a94dSNamhyung Kim } 461aca7a94dSNamhyung Kim 462aca7a94dSNamhyung Kim alloc_str = NULL; 463a7cb8863SArnaldo Carvalho de Melo str = callchain_list__sym_name(chain, bf, sizeof(bf), 464a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 465aca7a94dSNamhyung Kim if (was_first) { 466aca7a94dSNamhyung Kim double percent = cumul * 100.0 / new_total; 467aca7a94dSNamhyung Kim 468aca7a94dSNamhyung Kim if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 469aca7a94dSNamhyung Kim str = "Not enough memory!"; 470aca7a94dSNamhyung Kim else 471aca7a94dSNamhyung Kim str = alloc_str; 472aca7a94dSNamhyung Kim } 473aca7a94dSNamhyung Kim 474aca7a94dSNamhyung Kim color = HE_COLORSET_NORMAL; 47505e8b080SArnaldo Carvalho de Melo width = browser->b.width - (offset + extra_offset + 2); 47605e8b080SArnaldo Carvalho de Melo if (ui_browser__is_current_entry(&browser->b, row)) { 47705e8b080SArnaldo Carvalho de Melo browser->selection = &chain->ms; 478aca7a94dSNamhyung Kim color = HE_COLORSET_SELECTED; 479aca7a94dSNamhyung Kim *is_current_entry = true; 480aca7a94dSNamhyung Kim } 481aca7a94dSNamhyung Kim 48205e8b080SArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, color); 48305e8b080SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 484aca7a94dSNamhyung Kim slsmg_write_nstring(" ", offset + extra_offset); 485aca7a94dSNamhyung Kim slsmg_printf("%c ", folded_sign); 486aca7a94dSNamhyung Kim slsmg_write_nstring(str, width); 487aca7a94dSNamhyung Kim free(alloc_str); 488aca7a94dSNamhyung Kim 48905e8b080SArnaldo Carvalho de Melo if (++row == browser->b.height) 490aca7a94dSNamhyung Kim goto out; 491aca7a94dSNamhyung Kim do_next: 492aca7a94dSNamhyung Kim if (folded_sign == '+') 493aca7a94dSNamhyung Kim break; 494aca7a94dSNamhyung Kim } 495aca7a94dSNamhyung Kim 496aca7a94dSNamhyung Kim if (folded_sign == '-') { 497aca7a94dSNamhyung Kim const int new_level = level + (extra_offset ? 2 : 1); 49805e8b080SArnaldo Carvalho de Melo row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total, 499aca7a94dSNamhyung Kim new_level, row, row_offset, 500aca7a94dSNamhyung Kim is_current_entry); 501aca7a94dSNamhyung Kim } 50205e8b080SArnaldo Carvalho de Melo if (row == browser->b.height) 503aca7a94dSNamhyung Kim goto out; 504aca7a94dSNamhyung Kim node = next; 505aca7a94dSNamhyung Kim } 506aca7a94dSNamhyung Kim out: 507aca7a94dSNamhyung Kim return row - first_row; 508aca7a94dSNamhyung Kim } 509aca7a94dSNamhyung Kim 51005e8b080SArnaldo Carvalho de Melo static int hist_browser__show_callchain_node(struct hist_browser *browser, 511aca7a94dSNamhyung Kim struct callchain_node *node, 512aca7a94dSNamhyung Kim int level, unsigned short row, 513aca7a94dSNamhyung Kim off_t *row_offset, 514aca7a94dSNamhyung Kim bool *is_current_entry) 515aca7a94dSNamhyung Kim { 516aca7a94dSNamhyung Kim struct callchain_list *chain; 517aca7a94dSNamhyung Kim int first_row = row, 518aca7a94dSNamhyung Kim offset = level * LEVEL_OFFSET_STEP, 51905e8b080SArnaldo Carvalho de Melo width = browser->b.width - offset; 520aca7a94dSNamhyung Kim char folded_sign = ' '; 521aca7a94dSNamhyung Kim 522aca7a94dSNamhyung Kim list_for_each_entry(chain, &node->val, list) { 523a7cb8863SArnaldo Carvalho de Melo char bf[1024], *s; 524aca7a94dSNamhyung Kim int color; 525aca7a94dSNamhyung Kim 526aca7a94dSNamhyung Kim folded_sign = callchain_list__folded(chain); 527aca7a94dSNamhyung Kim 528aca7a94dSNamhyung Kim if (*row_offset != 0) { 529aca7a94dSNamhyung Kim --*row_offset; 530aca7a94dSNamhyung Kim continue; 531aca7a94dSNamhyung Kim } 532aca7a94dSNamhyung Kim 533aca7a94dSNamhyung Kim color = HE_COLORSET_NORMAL; 53405e8b080SArnaldo Carvalho de Melo if (ui_browser__is_current_entry(&browser->b, row)) { 53505e8b080SArnaldo Carvalho de Melo browser->selection = &chain->ms; 536aca7a94dSNamhyung Kim color = HE_COLORSET_SELECTED; 537aca7a94dSNamhyung Kim *is_current_entry = true; 538aca7a94dSNamhyung Kim } 539aca7a94dSNamhyung Kim 540a7cb8863SArnaldo Carvalho de Melo s = callchain_list__sym_name(chain, bf, sizeof(bf), 541a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 54205e8b080SArnaldo Carvalho de Melo ui_browser__gotorc(&browser->b, row, 0); 54305e8b080SArnaldo Carvalho de Melo ui_browser__set_color(&browser->b, color); 544aca7a94dSNamhyung Kim slsmg_write_nstring(" ", offset); 545aca7a94dSNamhyung Kim slsmg_printf("%c ", folded_sign); 546aca7a94dSNamhyung Kim slsmg_write_nstring(s, width - 2); 547aca7a94dSNamhyung Kim 54805e8b080SArnaldo Carvalho de Melo if (++row == browser->b.height) 549aca7a94dSNamhyung Kim goto out; 550aca7a94dSNamhyung Kim } 551aca7a94dSNamhyung Kim 552aca7a94dSNamhyung Kim if (folded_sign == '-') 55305e8b080SArnaldo Carvalho de Melo row += hist_browser__show_callchain_node_rb_tree(browser, node, 55405e8b080SArnaldo Carvalho de Melo browser->hists->stats.total_period, 555aca7a94dSNamhyung Kim level + 1, row, 556aca7a94dSNamhyung Kim row_offset, 557aca7a94dSNamhyung Kim is_current_entry); 558aca7a94dSNamhyung Kim out: 559aca7a94dSNamhyung Kim return row - first_row; 560aca7a94dSNamhyung Kim } 561aca7a94dSNamhyung Kim 56205e8b080SArnaldo Carvalho de Melo static int hist_browser__show_callchain(struct hist_browser *browser, 563aca7a94dSNamhyung Kim struct rb_root *chain, 564aca7a94dSNamhyung Kim int level, unsigned short row, 565aca7a94dSNamhyung Kim off_t *row_offset, 566aca7a94dSNamhyung Kim bool *is_current_entry) 567aca7a94dSNamhyung Kim { 568aca7a94dSNamhyung Kim struct rb_node *nd; 569aca7a94dSNamhyung Kim int first_row = row; 570aca7a94dSNamhyung Kim 571aca7a94dSNamhyung Kim for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 572aca7a94dSNamhyung Kim struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 573aca7a94dSNamhyung Kim 57405e8b080SArnaldo Carvalho de Melo row += hist_browser__show_callchain_node(browser, node, level, 575aca7a94dSNamhyung Kim row, row_offset, 576aca7a94dSNamhyung Kim is_current_entry); 57705e8b080SArnaldo Carvalho de Melo if (row == browser->b.height) 578aca7a94dSNamhyung Kim break; 579aca7a94dSNamhyung Kim } 580aca7a94dSNamhyung Kim 581aca7a94dSNamhyung Kim return row - first_row; 582aca7a94dSNamhyung Kim } 583aca7a94dSNamhyung Kim 58489701460SNamhyung Kim struct hpp_arg { 58589701460SNamhyung Kim struct ui_browser *b; 58689701460SNamhyung Kim char folded_sign; 58789701460SNamhyung Kim bool current_entry; 58889701460SNamhyung Kim }; 58989701460SNamhyung Kim 59089701460SNamhyung Kim static int __hpp__color_callchain(struct hpp_arg *arg) 5915aed9d24SNamhyung Kim { 59289701460SNamhyung Kim if (!symbol_conf.use_callchain) 59389701460SNamhyung Kim return 0; 59489701460SNamhyung Kim 59589701460SNamhyung Kim slsmg_printf("%c ", arg->folded_sign); 59689701460SNamhyung Kim return 2; 59789701460SNamhyung Kim } 59889701460SNamhyung Kim 59989701460SNamhyung Kim static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, 60089701460SNamhyung Kim u64 (*get_field)(struct hist_entry *), 60189701460SNamhyung Kim int (*callchain_cb)(struct hpp_arg *)) 60289701460SNamhyung Kim { 60389701460SNamhyung Kim int ret = 0; 6045aed9d24SNamhyung Kim double percent = 0.0; 6055aed9d24SNamhyung Kim struct hists *hists = he->hists; 60689701460SNamhyung Kim struct hpp_arg *arg = hpp->ptr; 6075aed9d24SNamhyung Kim 6085aed9d24SNamhyung Kim if (hists->stats.total_period) 6095aed9d24SNamhyung Kim percent = 100.0 * get_field(he) / hists->stats.total_period; 6105aed9d24SNamhyung Kim 61189701460SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 6125aed9d24SNamhyung Kim 61389701460SNamhyung Kim if (callchain_cb) 61489701460SNamhyung Kim ret += callchain_cb(arg); 61589701460SNamhyung Kim 61689701460SNamhyung Kim ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); 61789701460SNamhyung Kim slsmg_printf("%s", hpp->buf); 61889701460SNamhyung Kim 619371d8c40SNamhyung Kim if (symbol_conf.event_group) { 620371d8c40SNamhyung Kim int prev_idx, idx_delta; 621371d8c40SNamhyung Kim struct perf_evsel *evsel = hists_to_evsel(hists); 622371d8c40SNamhyung Kim struct hist_entry *pair; 623371d8c40SNamhyung Kim int nr_members = evsel->nr_members; 624371d8c40SNamhyung Kim 625371d8c40SNamhyung Kim if (nr_members <= 1) 626371d8c40SNamhyung Kim goto out; 627371d8c40SNamhyung Kim 628371d8c40SNamhyung Kim prev_idx = perf_evsel__group_idx(evsel); 629371d8c40SNamhyung Kim 630371d8c40SNamhyung Kim list_for_each_entry(pair, &he->pairs.head, pairs.node) { 631371d8c40SNamhyung Kim u64 period = get_field(pair); 632371d8c40SNamhyung Kim u64 total = pair->hists->stats.total_period; 633371d8c40SNamhyung Kim 634371d8c40SNamhyung Kim if (!total) 635371d8c40SNamhyung Kim continue; 636371d8c40SNamhyung Kim 637371d8c40SNamhyung Kim evsel = hists_to_evsel(pair->hists); 638371d8c40SNamhyung Kim idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; 639371d8c40SNamhyung Kim 640371d8c40SNamhyung Kim while (idx_delta--) { 641371d8c40SNamhyung Kim /* 642371d8c40SNamhyung Kim * zero-fill group members in the middle which 643371d8c40SNamhyung Kim * have no sample 644371d8c40SNamhyung Kim */ 645371d8c40SNamhyung Kim ui_browser__set_percent_color(arg->b, 0.0, 646371d8c40SNamhyung Kim arg->current_entry); 647371d8c40SNamhyung Kim ret += scnprintf(hpp->buf, hpp->size, 648371d8c40SNamhyung Kim " %6.2f%%", 0.0); 649371d8c40SNamhyung Kim slsmg_printf("%s", hpp->buf); 650371d8c40SNamhyung Kim } 651371d8c40SNamhyung Kim 652371d8c40SNamhyung Kim percent = 100.0 * period / total; 653371d8c40SNamhyung Kim ui_browser__set_percent_color(arg->b, percent, 654371d8c40SNamhyung Kim arg->current_entry); 655371d8c40SNamhyung Kim ret += scnprintf(hpp->buf, hpp->size, 656371d8c40SNamhyung Kim " %6.2f%%", percent); 657371d8c40SNamhyung Kim slsmg_printf("%s", hpp->buf); 658371d8c40SNamhyung Kim 659371d8c40SNamhyung Kim prev_idx = perf_evsel__group_idx(evsel); 660371d8c40SNamhyung Kim } 661371d8c40SNamhyung Kim 662371d8c40SNamhyung Kim idx_delta = nr_members - prev_idx - 1; 663371d8c40SNamhyung Kim 664371d8c40SNamhyung Kim while (idx_delta--) { 665371d8c40SNamhyung Kim /* 666371d8c40SNamhyung Kim * zero-fill group members at last which have no sample 667371d8c40SNamhyung Kim */ 668371d8c40SNamhyung Kim ui_browser__set_percent_color(arg->b, 0.0, 669371d8c40SNamhyung Kim arg->current_entry); 670371d8c40SNamhyung Kim ret += scnprintf(hpp->buf, hpp->size, 671371d8c40SNamhyung Kim " %6.2f%%", 0.0); 672371d8c40SNamhyung Kim slsmg_printf("%s", hpp->buf); 673371d8c40SNamhyung Kim } 674371d8c40SNamhyung Kim } 675371d8c40SNamhyung Kim out: 67689701460SNamhyung Kim if (!arg->current_entry || !arg->b->navkeypressed) 67789701460SNamhyung Kim ui_browser__set_color(arg->b, HE_COLORSET_NORMAL); 67889701460SNamhyung Kim 6795aed9d24SNamhyung Kim return ret; 680f5951d56SNamhyung Kim } 681f5951d56SNamhyung Kim 68289701460SNamhyung Kim #define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \ 6835aed9d24SNamhyung Kim static u64 __hpp_get_##_field(struct hist_entry *he) \ 6845aed9d24SNamhyung Kim { \ 6855aed9d24SNamhyung Kim return he->stat._field; \ 6865aed9d24SNamhyung Kim } \ 6875aed9d24SNamhyung Kim \ 6882c5d4b4aSJiri Olsa static int \ 6892c5d4b4aSJiri Olsa hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ 6902c5d4b4aSJiri Olsa struct perf_hpp *hpp, \ 6915aed9d24SNamhyung Kim struct hist_entry *he) \ 6925aed9d24SNamhyung Kim { \ 69389701460SNamhyung Kim return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ 6945aed9d24SNamhyung Kim } 695f5951d56SNamhyung Kim 69689701460SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain) 69789701460SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL) 69889701460SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL) 69989701460SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL) 70089701460SNamhyung Kim __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL) 7015aed9d24SNamhyung Kim 7025aed9d24SNamhyung Kim #undef __HPP_COLOR_PERCENT_FN 703f5951d56SNamhyung Kim 704f5951d56SNamhyung Kim void hist_browser__init_hpp(void) 705f5951d56SNamhyung Kim { 7061d77822eSJiri Olsa perf_hpp__init(); 707f5951d56SNamhyung Kim 708f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD].color = 709f5951d56SNamhyung Kim hist_browser__hpp_color_overhead; 710f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 711f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_sys; 712f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_US].color = 713f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_us; 714f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = 715f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_sys; 716f5951d56SNamhyung Kim perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 717f5951d56SNamhyung Kim hist_browser__hpp_color_overhead_guest_us; 718f5951d56SNamhyung Kim } 719f5951d56SNamhyung Kim 72005e8b080SArnaldo Carvalho de Melo static int hist_browser__show_entry(struct hist_browser *browser, 721aca7a94dSNamhyung Kim struct hist_entry *entry, 722aca7a94dSNamhyung Kim unsigned short row) 723aca7a94dSNamhyung Kim { 724aca7a94dSNamhyung Kim char s[256]; 7251240005eSJiri Olsa int printed = 0; 72667d25916SNamhyung Kim int width = browser->b.width; 727aca7a94dSNamhyung Kim char folded_sign = ' '; 72805e8b080SArnaldo Carvalho de Melo bool current_entry = ui_browser__is_current_entry(&browser->b, row); 729aca7a94dSNamhyung Kim off_t row_offset = entry->row_offset; 73063a1a3d8SNamhyung Kim bool first = true; 7311240005eSJiri Olsa struct perf_hpp_fmt *fmt; 732aca7a94dSNamhyung Kim 733aca7a94dSNamhyung Kim if (current_entry) { 73405e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 73505e8b080SArnaldo Carvalho de Melo browser->selection = &entry->ms; 736aca7a94dSNamhyung Kim } 737aca7a94dSNamhyung Kim 738aca7a94dSNamhyung Kim if (symbol_conf.use_callchain) { 739aca7a94dSNamhyung Kim hist_entry__init_have_children(entry); 740aca7a94dSNamhyung Kim folded_sign = hist_entry__folded(entry); 741aca7a94dSNamhyung Kim } 742aca7a94dSNamhyung Kim 743aca7a94dSNamhyung Kim if (row_offset == 0) { 74489701460SNamhyung Kim struct hpp_arg arg = { 74589701460SNamhyung Kim .b = &browser->b, 74689701460SNamhyung Kim .folded_sign = folded_sign, 74789701460SNamhyung Kim .current_entry = current_entry, 74889701460SNamhyung Kim }; 749f5951d56SNamhyung Kim struct perf_hpp hpp = { 750f5951d56SNamhyung Kim .buf = s, 751f5951d56SNamhyung Kim .size = sizeof(s), 75289701460SNamhyung Kim .ptr = &arg, 753f5951d56SNamhyung Kim }; 754f5951d56SNamhyung Kim 75567d25916SNamhyung Kim ui_browser__gotorc(&browser->b, row, 0); 756f5951d56SNamhyung Kim 7571240005eSJiri Olsa perf_hpp__for_each_format(fmt) { 75863a1a3d8SNamhyung Kim if (!first) { 759f5951d56SNamhyung Kim slsmg_printf(" "); 760f5951d56SNamhyung Kim width -= 2; 761f5951d56SNamhyung Kim } 76263a1a3d8SNamhyung Kim first = false; 763f5951d56SNamhyung Kim 7641240005eSJiri Olsa if (fmt->color) { 7652c5d4b4aSJiri Olsa width -= fmt->color(fmt, &hpp, entry); 766f5951d56SNamhyung Kim } else { 7672c5d4b4aSJiri Olsa width -= fmt->entry(fmt, &hpp, entry); 768f5951d56SNamhyung Kim slsmg_printf("%s", s); 769f5951d56SNamhyung Kim } 770f5951d56SNamhyung Kim } 771aca7a94dSNamhyung Kim 772aca7a94dSNamhyung Kim /* The scroll bar isn't being used */ 77305e8b080SArnaldo Carvalho de Melo if (!browser->b.navkeypressed) 774aca7a94dSNamhyung Kim width += 1; 775aca7a94dSNamhyung Kim 776f5951d56SNamhyung Kim hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists); 777aca7a94dSNamhyung Kim slsmg_write_nstring(s, width); 778aca7a94dSNamhyung Kim ++row; 779aca7a94dSNamhyung Kim ++printed; 780aca7a94dSNamhyung Kim } else 781aca7a94dSNamhyung Kim --row_offset; 782aca7a94dSNamhyung Kim 78305e8b080SArnaldo Carvalho de Melo if (folded_sign == '-' && row != browser->b.height) { 78405e8b080SArnaldo Carvalho de Melo printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 785aca7a94dSNamhyung Kim 1, row, &row_offset, 786aca7a94dSNamhyung Kim ¤t_entry); 787aca7a94dSNamhyung Kim if (current_entry) 78805e8b080SArnaldo Carvalho de Melo browser->he_selection = entry; 789aca7a94dSNamhyung Kim } 790aca7a94dSNamhyung Kim 791aca7a94dSNamhyung Kim return printed; 792aca7a94dSNamhyung Kim } 793aca7a94dSNamhyung Kim 794aca7a94dSNamhyung Kim static void ui_browser__hists_init_top(struct ui_browser *browser) 795aca7a94dSNamhyung Kim { 796aca7a94dSNamhyung Kim if (browser->top == NULL) { 797aca7a94dSNamhyung Kim struct hist_browser *hb; 798aca7a94dSNamhyung Kim 799aca7a94dSNamhyung Kim hb = container_of(browser, struct hist_browser, b); 800aca7a94dSNamhyung Kim browser->top = rb_first(&hb->hists->entries); 801aca7a94dSNamhyung Kim } 802aca7a94dSNamhyung Kim } 803aca7a94dSNamhyung Kim 80405e8b080SArnaldo Carvalho de Melo static unsigned int hist_browser__refresh(struct ui_browser *browser) 805aca7a94dSNamhyung Kim { 806aca7a94dSNamhyung Kim unsigned row = 0; 807aca7a94dSNamhyung Kim struct rb_node *nd; 80805e8b080SArnaldo Carvalho de Melo struct hist_browser *hb = container_of(browser, struct hist_browser, b); 809aca7a94dSNamhyung Kim 81005e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 811aca7a94dSNamhyung Kim 81205e8b080SArnaldo Carvalho de Melo for (nd = browser->top; nd; nd = rb_next(nd)) { 813aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 814064f1981SNamhyung Kim float percent = h->stat.period * 100.0 / 815064f1981SNamhyung Kim hb->hists->stats.total_period; 816aca7a94dSNamhyung Kim 817aca7a94dSNamhyung Kim if (h->filtered) 818aca7a94dSNamhyung Kim continue; 819aca7a94dSNamhyung Kim 820064f1981SNamhyung Kim if (percent < hb->min_pcnt) 821064f1981SNamhyung Kim continue; 822064f1981SNamhyung Kim 823aca7a94dSNamhyung Kim row += hist_browser__show_entry(hb, h, row); 82405e8b080SArnaldo Carvalho de Melo if (row == browser->height) 825aca7a94dSNamhyung Kim break; 826aca7a94dSNamhyung Kim } 827aca7a94dSNamhyung Kim 828aca7a94dSNamhyung Kim return row; 829aca7a94dSNamhyung Kim } 830aca7a94dSNamhyung Kim 831064f1981SNamhyung Kim static struct rb_node *hists__filter_entries(struct rb_node *nd, 832064f1981SNamhyung Kim struct hists *hists, 833064f1981SNamhyung Kim float min_pcnt) 834aca7a94dSNamhyung Kim { 835aca7a94dSNamhyung Kim while (nd != NULL) { 836aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 837064f1981SNamhyung Kim float percent = h->stat.period * 100.0 / 838064f1981SNamhyung Kim hists->stats.total_period; 839064f1981SNamhyung Kim 840064f1981SNamhyung Kim if (percent < min_pcnt) 841064f1981SNamhyung Kim return NULL; 842064f1981SNamhyung Kim 843aca7a94dSNamhyung Kim if (!h->filtered) 844aca7a94dSNamhyung Kim return nd; 845aca7a94dSNamhyung Kim 846aca7a94dSNamhyung Kim nd = rb_next(nd); 847aca7a94dSNamhyung Kim } 848aca7a94dSNamhyung Kim 849aca7a94dSNamhyung Kim return NULL; 850aca7a94dSNamhyung Kim } 851aca7a94dSNamhyung Kim 852064f1981SNamhyung Kim static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 853064f1981SNamhyung Kim struct hists *hists, 854064f1981SNamhyung Kim float min_pcnt) 855aca7a94dSNamhyung Kim { 856aca7a94dSNamhyung Kim while (nd != NULL) { 857aca7a94dSNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 858064f1981SNamhyung Kim float percent = h->stat.period * 100.0 / 859064f1981SNamhyung Kim hists->stats.total_period; 860064f1981SNamhyung Kim 861064f1981SNamhyung Kim if (!h->filtered && percent >= min_pcnt) 862aca7a94dSNamhyung Kim return nd; 863aca7a94dSNamhyung Kim 864aca7a94dSNamhyung Kim nd = rb_prev(nd); 865aca7a94dSNamhyung Kim } 866aca7a94dSNamhyung Kim 867aca7a94dSNamhyung Kim return NULL; 868aca7a94dSNamhyung Kim } 869aca7a94dSNamhyung Kim 87005e8b080SArnaldo Carvalho de Melo static void ui_browser__hists_seek(struct ui_browser *browser, 871aca7a94dSNamhyung Kim off_t offset, int whence) 872aca7a94dSNamhyung Kim { 873aca7a94dSNamhyung Kim struct hist_entry *h; 874aca7a94dSNamhyung Kim struct rb_node *nd; 875aca7a94dSNamhyung Kim bool first = true; 876064f1981SNamhyung Kim struct hist_browser *hb; 877064f1981SNamhyung Kim 878064f1981SNamhyung Kim hb = container_of(browser, struct hist_browser, b); 879aca7a94dSNamhyung Kim 88005e8b080SArnaldo Carvalho de Melo if (browser->nr_entries == 0) 881aca7a94dSNamhyung Kim return; 882aca7a94dSNamhyung Kim 88305e8b080SArnaldo Carvalho de Melo ui_browser__hists_init_top(browser); 884aca7a94dSNamhyung Kim 885aca7a94dSNamhyung Kim switch (whence) { 886aca7a94dSNamhyung Kim case SEEK_SET: 887064f1981SNamhyung Kim nd = hists__filter_entries(rb_first(browser->entries), 888064f1981SNamhyung Kim hb->hists, hb->min_pcnt); 889aca7a94dSNamhyung Kim break; 890aca7a94dSNamhyung Kim case SEEK_CUR: 89105e8b080SArnaldo Carvalho de Melo nd = browser->top; 892aca7a94dSNamhyung Kim goto do_offset; 893aca7a94dSNamhyung Kim case SEEK_END: 894064f1981SNamhyung Kim nd = hists__filter_prev_entries(rb_last(browser->entries), 895064f1981SNamhyung Kim hb->hists, hb->min_pcnt); 896aca7a94dSNamhyung Kim first = false; 897aca7a94dSNamhyung Kim break; 898aca7a94dSNamhyung Kim default: 899aca7a94dSNamhyung Kim return; 900aca7a94dSNamhyung Kim } 901aca7a94dSNamhyung Kim 902aca7a94dSNamhyung Kim /* 903aca7a94dSNamhyung Kim * Moves not relative to the first visible entry invalidates its 904aca7a94dSNamhyung Kim * row_offset: 905aca7a94dSNamhyung Kim */ 90605e8b080SArnaldo Carvalho de Melo h = rb_entry(browser->top, struct hist_entry, rb_node); 907aca7a94dSNamhyung Kim h->row_offset = 0; 908aca7a94dSNamhyung Kim 909aca7a94dSNamhyung Kim /* 910aca7a94dSNamhyung Kim * Here we have to check if nd is expanded (+), if it is we can't go 911aca7a94dSNamhyung Kim * the next top level hist_entry, instead we must compute an offset of 912aca7a94dSNamhyung Kim * what _not_ to show and not change the first visible entry. 913aca7a94dSNamhyung Kim * 914aca7a94dSNamhyung Kim * This offset increments when we are going from top to bottom and 915aca7a94dSNamhyung Kim * decreases when we're going from bottom to top. 916aca7a94dSNamhyung Kim * 917aca7a94dSNamhyung Kim * As we don't have backpointers to the top level in the callchains 918aca7a94dSNamhyung Kim * structure, we need to always print the whole hist_entry callchain, 919aca7a94dSNamhyung Kim * skipping the first ones that are before the first visible entry 920aca7a94dSNamhyung Kim * and stop when we printed enough lines to fill the screen. 921aca7a94dSNamhyung Kim */ 922aca7a94dSNamhyung Kim do_offset: 923aca7a94dSNamhyung Kim if (offset > 0) { 924aca7a94dSNamhyung Kim do { 925aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 926aca7a94dSNamhyung Kim if (h->ms.unfolded) { 927aca7a94dSNamhyung Kim u16 remaining = h->nr_rows - h->row_offset; 928aca7a94dSNamhyung Kim if (offset > remaining) { 929aca7a94dSNamhyung Kim offset -= remaining; 930aca7a94dSNamhyung Kim h->row_offset = 0; 931aca7a94dSNamhyung Kim } else { 932aca7a94dSNamhyung Kim h->row_offset += offset; 933aca7a94dSNamhyung Kim offset = 0; 93405e8b080SArnaldo Carvalho de Melo browser->top = nd; 935aca7a94dSNamhyung Kim break; 936aca7a94dSNamhyung Kim } 937aca7a94dSNamhyung Kim } 938064f1981SNamhyung Kim nd = hists__filter_entries(rb_next(nd), hb->hists, 939064f1981SNamhyung Kim hb->min_pcnt); 940aca7a94dSNamhyung Kim if (nd == NULL) 941aca7a94dSNamhyung Kim break; 942aca7a94dSNamhyung Kim --offset; 94305e8b080SArnaldo Carvalho de Melo browser->top = nd; 944aca7a94dSNamhyung Kim } while (offset != 0); 945aca7a94dSNamhyung Kim } else if (offset < 0) { 946aca7a94dSNamhyung Kim while (1) { 947aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 948aca7a94dSNamhyung Kim if (h->ms.unfolded) { 949aca7a94dSNamhyung Kim if (first) { 950aca7a94dSNamhyung Kim if (-offset > h->row_offset) { 951aca7a94dSNamhyung Kim offset += h->row_offset; 952aca7a94dSNamhyung Kim h->row_offset = 0; 953aca7a94dSNamhyung Kim } else { 954aca7a94dSNamhyung Kim h->row_offset += offset; 955aca7a94dSNamhyung Kim offset = 0; 95605e8b080SArnaldo Carvalho de Melo browser->top = nd; 957aca7a94dSNamhyung Kim break; 958aca7a94dSNamhyung Kim } 959aca7a94dSNamhyung Kim } else { 960aca7a94dSNamhyung Kim if (-offset > h->nr_rows) { 961aca7a94dSNamhyung Kim offset += h->nr_rows; 962aca7a94dSNamhyung Kim h->row_offset = 0; 963aca7a94dSNamhyung Kim } else { 964aca7a94dSNamhyung Kim h->row_offset = h->nr_rows + offset; 965aca7a94dSNamhyung Kim offset = 0; 96605e8b080SArnaldo Carvalho de Melo browser->top = nd; 967aca7a94dSNamhyung Kim break; 968aca7a94dSNamhyung Kim } 969aca7a94dSNamhyung Kim } 970aca7a94dSNamhyung Kim } 971aca7a94dSNamhyung Kim 972064f1981SNamhyung Kim nd = hists__filter_prev_entries(rb_prev(nd), hb->hists, 973064f1981SNamhyung Kim hb->min_pcnt); 974aca7a94dSNamhyung Kim if (nd == NULL) 975aca7a94dSNamhyung Kim break; 976aca7a94dSNamhyung Kim ++offset; 97705e8b080SArnaldo Carvalho de Melo browser->top = nd; 978aca7a94dSNamhyung Kim if (offset == 0) { 979aca7a94dSNamhyung Kim /* 980aca7a94dSNamhyung Kim * Last unfiltered hist_entry, check if it is 981aca7a94dSNamhyung Kim * unfolded, if it is then we should have 982aca7a94dSNamhyung Kim * row_offset at its last entry. 983aca7a94dSNamhyung Kim */ 984aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 985aca7a94dSNamhyung Kim if (h->ms.unfolded) 986aca7a94dSNamhyung Kim h->row_offset = h->nr_rows; 987aca7a94dSNamhyung Kim break; 988aca7a94dSNamhyung Kim } 989aca7a94dSNamhyung Kim first = false; 990aca7a94dSNamhyung Kim } 991aca7a94dSNamhyung Kim } else { 99205e8b080SArnaldo Carvalho de Melo browser->top = nd; 993aca7a94dSNamhyung Kim h = rb_entry(nd, struct hist_entry, rb_node); 994aca7a94dSNamhyung Kim h->row_offset = 0; 995aca7a94dSNamhyung Kim } 996aca7a94dSNamhyung Kim } 997aca7a94dSNamhyung Kim 998aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser, 999aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *chain_node, 1000aff3f3f6SArnaldo Carvalho de Melo u64 total, int level, 1001aff3f3f6SArnaldo Carvalho de Melo FILE *fp) 1002aff3f3f6SArnaldo Carvalho de Melo { 1003aff3f3f6SArnaldo Carvalho de Melo struct rb_node *node; 1004aff3f3f6SArnaldo Carvalho de Melo int offset = level * LEVEL_OFFSET_STEP; 1005aff3f3f6SArnaldo Carvalho de Melo u64 new_total, remaining; 1006aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1007aff3f3f6SArnaldo Carvalho de Melo 1008aff3f3f6SArnaldo Carvalho de Melo if (callchain_param.mode == CHAIN_GRAPH_REL) 1009aff3f3f6SArnaldo Carvalho de Melo new_total = chain_node->children_hit; 1010aff3f3f6SArnaldo Carvalho de Melo else 1011aff3f3f6SArnaldo Carvalho de Melo new_total = total; 1012aff3f3f6SArnaldo Carvalho de Melo 1013aff3f3f6SArnaldo Carvalho de Melo remaining = new_total; 1014aff3f3f6SArnaldo Carvalho de Melo node = rb_first(&chain_node->rb_root); 1015aff3f3f6SArnaldo Carvalho de Melo while (node) { 1016aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 1017aff3f3f6SArnaldo Carvalho de Melo struct rb_node *next = rb_next(node); 1018aff3f3f6SArnaldo Carvalho de Melo u64 cumul = callchain_cumul_hits(child); 1019aff3f3f6SArnaldo Carvalho de Melo struct callchain_list *chain; 1020aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 1021aff3f3f6SArnaldo Carvalho de Melo int first = true; 1022aff3f3f6SArnaldo Carvalho de Melo int extra_offset = 0; 1023aff3f3f6SArnaldo Carvalho de Melo 1024aff3f3f6SArnaldo Carvalho de Melo remaining -= cumul; 1025aff3f3f6SArnaldo Carvalho de Melo 1026aff3f3f6SArnaldo Carvalho de Melo list_for_each_entry(chain, &child->val, list) { 1027a7cb8863SArnaldo Carvalho de Melo char bf[1024], *alloc_str; 1028aff3f3f6SArnaldo Carvalho de Melo const char *str; 1029aff3f3f6SArnaldo Carvalho de Melo bool was_first = first; 1030aff3f3f6SArnaldo Carvalho de Melo 1031aff3f3f6SArnaldo Carvalho de Melo if (first) 1032aff3f3f6SArnaldo Carvalho de Melo first = false; 1033aff3f3f6SArnaldo Carvalho de Melo else 1034aff3f3f6SArnaldo Carvalho de Melo extra_offset = LEVEL_OFFSET_STEP; 1035aff3f3f6SArnaldo Carvalho de Melo 1036aff3f3f6SArnaldo Carvalho de Melo folded_sign = callchain_list__folded(chain); 1037aff3f3f6SArnaldo Carvalho de Melo 1038aff3f3f6SArnaldo Carvalho de Melo alloc_str = NULL; 1039a7cb8863SArnaldo Carvalho de Melo str = callchain_list__sym_name(chain, bf, sizeof(bf), 1040a7cb8863SArnaldo Carvalho de Melo browser->show_dso); 1041aff3f3f6SArnaldo Carvalho de Melo if (was_first) { 1042aff3f3f6SArnaldo Carvalho de Melo double percent = cumul * 100.0 / new_total; 1043aff3f3f6SArnaldo Carvalho de Melo 1044aff3f3f6SArnaldo Carvalho de Melo if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 1045aff3f3f6SArnaldo Carvalho de Melo str = "Not enough memory!"; 1046aff3f3f6SArnaldo Carvalho de Melo else 1047aff3f3f6SArnaldo Carvalho de Melo str = alloc_str; 1048aff3f3f6SArnaldo Carvalho de Melo } 1049aff3f3f6SArnaldo Carvalho de Melo 1050aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str); 1051aff3f3f6SArnaldo Carvalho de Melo free(alloc_str); 1052aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '+') 1053aff3f3f6SArnaldo Carvalho de Melo break; 1054aff3f3f6SArnaldo Carvalho de Melo } 1055aff3f3f6SArnaldo Carvalho de Melo 1056aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') { 1057aff3f3f6SArnaldo Carvalho de Melo const int new_level = level + (extra_offset ? 2 : 1); 1058aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total, 1059aff3f3f6SArnaldo Carvalho de Melo new_level, fp); 1060aff3f3f6SArnaldo Carvalho de Melo } 1061aff3f3f6SArnaldo Carvalho de Melo 1062aff3f3f6SArnaldo Carvalho de Melo node = next; 1063aff3f3f6SArnaldo Carvalho de Melo } 1064aff3f3f6SArnaldo Carvalho de Melo 1065aff3f3f6SArnaldo Carvalho de Melo return printed; 1066aff3f3f6SArnaldo Carvalho de Melo } 1067aff3f3f6SArnaldo Carvalho de Melo 1068aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain_node(struct hist_browser *browser, 1069aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *node, 1070aff3f3f6SArnaldo Carvalho de Melo int level, FILE *fp) 1071aff3f3f6SArnaldo Carvalho de Melo { 1072aff3f3f6SArnaldo Carvalho de Melo struct callchain_list *chain; 1073aff3f3f6SArnaldo Carvalho de Melo int offset = level * LEVEL_OFFSET_STEP; 1074aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 1075aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1076aff3f3f6SArnaldo Carvalho de Melo 1077aff3f3f6SArnaldo Carvalho de Melo list_for_each_entry(chain, &node->val, list) { 1078a7cb8863SArnaldo Carvalho de Melo char bf[1024], *s; 1079aff3f3f6SArnaldo Carvalho de Melo 1080aff3f3f6SArnaldo Carvalho de Melo folded_sign = callchain_list__folded(chain); 1081a7cb8863SArnaldo Carvalho de Melo s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso); 1082aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s); 1083aff3f3f6SArnaldo Carvalho de Melo } 1084aff3f3f6SArnaldo Carvalho de Melo 1085aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 1086aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node, 1087aff3f3f6SArnaldo Carvalho de Melo browser->hists->stats.total_period, 1088aff3f3f6SArnaldo Carvalho de Melo level + 1, fp); 1089aff3f3f6SArnaldo Carvalho de Melo return printed; 1090aff3f3f6SArnaldo Carvalho de Melo } 1091aff3f3f6SArnaldo Carvalho de Melo 1092aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1093aff3f3f6SArnaldo Carvalho de Melo struct rb_root *chain, int level, FILE *fp) 1094aff3f3f6SArnaldo Carvalho de Melo { 1095aff3f3f6SArnaldo Carvalho de Melo struct rb_node *nd; 1096aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1097aff3f3f6SArnaldo Carvalho de Melo 1098aff3f3f6SArnaldo Carvalho de Melo for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 1099aff3f3f6SArnaldo Carvalho de Melo struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 1100aff3f3f6SArnaldo Carvalho de Melo 1101aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain_node(browser, node, level, fp); 1102aff3f3f6SArnaldo Carvalho de Melo } 1103aff3f3f6SArnaldo Carvalho de Melo 1104aff3f3f6SArnaldo Carvalho de Melo return printed; 1105aff3f3f6SArnaldo Carvalho de Melo } 1106aff3f3f6SArnaldo Carvalho de Melo 1107aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf_entry(struct hist_browser *browser, 1108aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *he, FILE *fp) 1109aff3f3f6SArnaldo Carvalho de Melo { 1110aff3f3f6SArnaldo Carvalho de Melo char s[8192]; 1111aff3f3f6SArnaldo Carvalho de Melo double percent; 1112aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1113aff3f3f6SArnaldo Carvalho de Melo char folded_sign = ' '; 1114aff3f3f6SArnaldo Carvalho de Melo 1115aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1116aff3f3f6SArnaldo Carvalho de Melo folded_sign = hist_entry__folded(he); 1117aff3f3f6SArnaldo Carvalho de Melo 1118000078bcSNamhyung Kim hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists); 1119b24c28f7SNamhyung Kim percent = (he->stat.period * 100.0) / browser->hists->stats.total_period; 1120aff3f3f6SArnaldo Carvalho de Melo 1121aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.use_callchain) 1122aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%c ", folded_sign); 1123aff3f3f6SArnaldo Carvalho de Melo 1124aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, " %5.2f%%", percent); 1125aff3f3f6SArnaldo Carvalho de Melo 1126aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.show_nr_samples) 1127b24c28f7SNamhyung Kim printed += fprintf(fp, " %11u", he->stat.nr_events); 1128aff3f3f6SArnaldo Carvalho de Melo 1129aff3f3f6SArnaldo Carvalho de Melo if (symbol_conf.show_total_period) 1130b24c28f7SNamhyung Kim printed += fprintf(fp, " %12" PRIu64, he->stat.period); 1131aff3f3f6SArnaldo Carvalho de Melo 1132aff3f3f6SArnaldo Carvalho de Melo printed += fprintf(fp, "%s\n", rtrim(s)); 1133aff3f3f6SArnaldo Carvalho de Melo 1134aff3f3f6SArnaldo Carvalho de Melo if (folded_sign == '-') 1135aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp); 1136aff3f3f6SArnaldo Carvalho de Melo 1137aff3f3f6SArnaldo Carvalho de Melo return printed; 1138aff3f3f6SArnaldo Carvalho de Melo } 1139aff3f3f6SArnaldo Carvalho de Melo 1140aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1141aff3f3f6SArnaldo Carvalho de Melo { 1142064f1981SNamhyung Kim struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1143064f1981SNamhyung Kim browser->hists, 1144064f1981SNamhyung Kim browser->min_pcnt); 1145aff3f3f6SArnaldo Carvalho de Melo int printed = 0; 1146aff3f3f6SArnaldo Carvalho de Melo 1147aff3f3f6SArnaldo Carvalho de Melo while (nd) { 1148aff3f3f6SArnaldo Carvalho de Melo struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1149aff3f3f6SArnaldo Carvalho de Melo 1150aff3f3f6SArnaldo Carvalho de Melo printed += hist_browser__fprintf_entry(browser, h, fp); 1151064f1981SNamhyung Kim nd = hists__filter_entries(rb_next(nd), browser->hists, 1152064f1981SNamhyung Kim browser->min_pcnt); 1153aff3f3f6SArnaldo Carvalho de Melo } 1154aff3f3f6SArnaldo Carvalho de Melo 1155aff3f3f6SArnaldo Carvalho de Melo return printed; 1156aff3f3f6SArnaldo Carvalho de Melo } 1157aff3f3f6SArnaldo Carvalho de Melo 1158aff3f3f6SArnaldo Carvalho de Melo static int hist_browser__dump(struct hist_browser *browser) 1159aff3f3f6SArnaldo Carvalho de Melo { 1160aff3f3f6SArnaldo Carvalho de Melo char filename[64]; 1161aff3f3f6SArnaldo Carvalho de Melo FILE *fp; 1162aff3f3f6SArnaldo Carvalho de Melo 1163aff3f3f6SArnaldo Carvalho de Melo while (1) { 1164aff3f3f6SArnaldo Carvalho de Melo scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); 1165aff3f3f6SArnaldo Carvalho de Melo if (access(filename, F_OK)) 1166aff3f3f6SArnaldo Carvalho de Melo break; 1167aff3f3f6SArnaldo Carvalho de Melo /* 1168aff3f3f6SArnaldo Carvalho de Melo * XXX: Just an arbitrary lazy upper limit 1169aff3f3f6SArnaldo Carvalho de Melo */ 1170aff3f3f6SArnaldo Carvalho de Melo if (++browser->print_seq == 8192) { 1171aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); 1172aff3f3f6SArnaldo Carvalho de Melo return -1; 1173aff3f3f6SArnaldo Carvalho de Melo } 1174aff3f3f6SArnaldo Carvalho de Melo } 1175aff3f3f6SArnaldo Carvalho de Melo 1176aff3f3f6SArnaldo Carvalho de Melo fp = fopen(filename, "w"); 1177aff3f3f6SArnaldo Carvalho de Melo if (fp == NULL) { 1178aff3f3f6SArnaldo Carvalho de Melo char bf[64]; 11794cc49d4dSKirill A. Shutemov const char *err = strerror_r(errno, bf, sizeof(bf)); 11804cc49d4dSKirill A. Shutemov ui_helpline__fpush("Couldn't write to %s: %s", filename, err); 1181aff3f3f6SArnaldo Carvalho de Melo return -1; 1182aff3f3f6SArnaldo Carvalho de Melo } 1183aff3f3f6SArnaldo Carvalho de Melo 1184aff3f3f6SArnaldo Carvalho de Melo ++browser->print_seq; 1185aff3f3f6SArnaldo Carvalho de Melo hist_browser__fprintf(browser, fp); 1186aff3f3f6SArnaldo Carvalho de Melo fclose(fp); 1187aff3f3f6SArnaldo Carvalho de Melo ui_helpline__fpush("%s written!", filename); 1188aff3f3f6SArnaldo Carvalho de Melo 1189aff3f3f6SArnaldo Carvalho de Melo return 0; 1190aff3f3f6SArnaldo Carvalho de Melo } 1191aff3f3f6SArnaldo Carvalho de Melo 1192aca7a94dSNamhyung Kim static struct hist_browser *hist_browser__new(struct hists *hists) 1193aca7a94dSNamhyung Kim { 119405e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = zalloc(sizeof(*browser)); 1195aca7a94dSNamhyung Kim 119605e8b080SArnaldo Carvalho de Melo if (browser) { 119705e8b080SArnaldo Carvalho de Melo browser->hists = hists; 119805e8b080SArnaldo Carvalho de Melo browser->b.refresh = hist_browser__refresh; 119905e8b080SArnaldo Carvalho de Melo browser->b.seek = ui_browser__hists_seek; 120005e8b080SArnaldo Carvalho de Melo browser->b.use_navkeypressed = true; 1201aca7a94dSNamhyung Kim } 1202aca7a94dSNamhyung Kim 120305e8b080SArnaldo Carvalho de Melo return browser; 1204aca7a94dSNamhyung Kim } 1205aca7a94dSNamhyung Kim 120605e8b080SArnaldo Carvalho de Melo static void hist_browser__delete(struct hist_browser *browser) 1207aca7a94dSNamhyung Kim { 120805e8b080SArnaldo Carvalho de Melo free(browser); 1209aca7a94dSNamhyung Kim } 1210aca7a94dSNamhyung Kim 121105e8b080SArnaldo Carvalho de Melo static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser) 1212aca7a94dSNamhyung Kim { 121305e8b080SArnaldo Carvalho de Melo return browser->he_selection; 1214aca7a94dSNamhyung Kim } 1215aca7a94dSNamhyung Kim 121605e8b080SArnaldo Carvalho de Melo static struct thread *hist_browser__selected_thread(struct hist_browser *browser) 1217aca7a94dSNamhyung Kim { 121805e8b080SArnaldo Carvalho de Melo return browser->he_selection->thread; 1219aca7a94dSNamhyung Kim } 1220aca7a94dSNamhyung Kim 122105e8b080SArnaldo Carvalho de Melo static int hists__browser_title(struct hists *hists, char *bf, size_t size, 1222aca7a94dSNamhyung Kim const char *ev_name) 1223aca7a94dSNamhyung Kim { 1224aca7a94dSNamhyung Kim char unit; 1225aca7a94dSNamhyung Kim int printed; 122605e8b080SArnaldo Carvalho de Melo const struct dso *dso = hists->dso_filter; 122705e8b080SArnaldo Carvalho de Melo const struct thread *thread = hists->thread_filter; 122805e8b080SArnaldo Carvalho de Melo unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 122905e8b080SArnaldo Carvalho de Melo u64 nr_events = hists->stats.total_period; 1230717e263fSNamhyung Kim struct perf_evsel *evsel = hists_to_evsel(hists); 1231717e263fSNamhyung Kim char buf[512]; 1232717e263fSNamhyung Kim size_t buflen = sizeof(buf); 1233717e263fSNamhyung Kim 1234759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1235717e263fSNamhyung Kim struct perf_evsel *pos; 1236717e263fSNamhyung Kim 1237717e263fSNamhyung Kim perf_evsel__group_desc(evsel, buf, buflen); 1238717e263fSNamhyung Kim ev_name = buf; 1239717e263fSNamhyung Kim 1240717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 1241717e263fSNamhyung Kim nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1242717e263fSNamhyung Kim nr_events += pos->hists.stats.total_period; 1243717e263fSNamhyung Kim } 1244717e263fSNamhyung Kim } 1245aca7a94dSNamhyung Kim 1246aca7a94dSNamhyung Kim nr_samples = convert_unit(nr_samples, &unit); 1247aca7a94dSNamhyung Kim printed = scnprintf(bf, size, 1248aca7a94dSNamhyung Kim "Samples: %lu%c of event '%s', Event count (approx.): %lu", 1249aca7a94dSNamhyung Kim nr_samples, unit, ev_name, nr_events); 1250aca7a94dSNamhyung Kim 1251aca7a94dSNamhyung Kim 125205e8b080SArnaldo Carvalho de Melo if (hists->uid_filter_str) 1253aca7a94dSNamhyung Kim printed += snprintf(bf + printed, size - printed, 125405e8b080SArnaldo Carvalho de Melo ", UID: %s", hists->uid_filter_str); 1255aca7a94dSNamhyung Kim if (thread) 1256aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1257aca7a94dSNamhyung Kim ", Thread: %s(%d)", 1258b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 125938051234SAdrian Hunter thread->tid); 1260aca7a94dSNamhyung Kim if (dso) 1261aca7a94dSNamhyung Kim printed += scnprintf(bf + printed, size - printed, 1262aca7a94dSNamhyung Kim ", DSO: %s", dso->short_name); 1263aca7a94dSNamhyung Kim return printed; 1264aca7a94dSNamhyung Kim } 1265aca7a94dSNamhyung Kim 1266aca7a94dSNamhyung Kim static inline void free_popup_options(char **options, int n) 1267aca7a94dSNamhyung Kim { 1268aca7a94dSNamhyung Kim int i; 1269aca7a94dSNamhyung Kim 1270aca7a94dSNamhyung Kim for (i = 0; i < n; ++i) { 1271aca7a94dSNamhyung Kim free(options[i]); 1272aca7a94dSNamhyung Kim options[i] = NULL; 1273aca7a94dSNamhyung Kim } 1274aca7a94dSNamhyung Kim } 1275aca7a94dSNamhyung Kim 1276c77d8d70SFeng Tang /* Check whether the browser is for 'top' or 'report' */ 1277c77d8d70SFeng Tang static inline bool is_report_browser(void *timer) 1278c77d8d70SFeng Tang { 1279c77d8d70SFeng Tang return timer == NULL; 1280c77d8d70SFeng Tang } 1281c77d8d70SFeng Tang 1282341487abSFeng Tang /* 1283341487abSFeng Tang * Only runtime switching of perf data file will make "input_name" point 1284341487abSFeng Tang * to a malloced buffer. So add "is_input_name_malloced" flag to decide 1285341487abSFeng Tang * whether we need to call free() for current "input_name" during the switch. 1286341487abSFeng Tang */ 1287341487abSFeng Tang static bool is_input_name_malloced = false; 1288341487abSFeng Tang 1289341487abSFeng Tang static int switch_data_file(void) 1290341487abSFeng Tang { 1291341487abSFeng Tang char *pwd, *options[32], *abs_path[32], *tmp; 1292341487abSFeng Tang DIR *pwd_dir; 1293341487abSFeng Tang int nr_options = 0, choice = -1, ret = -1; 1294341487abSFeng Tang struct dirent *dent; 1295341487abSFeng Tang 1296341487abSFeng Tang pwd = getenv("PWD"); 1297341487abSFeng Tang if (!pwd) 1298341487abSFeng Tang return ret; 1299341487abSFeng Tang 1300341487abSFeng Tang pwd_dir = opendir(pwd); 1301341487abSFeng Tang if (!pwd_dir) 1302341487abSFeng Tang return ret; 1303341487abSFeng Tang 1304341487abSFeng Tang memset(options, 0, sizeof(options)); 1305341487abSFeng Tang memset(options, 0, sizeof(abs_path)); 1306341487abSFeng Tang 1307341487abSFeng Tang while ((dent = readdir(pwd_dir))) { 1308341487abSFeng Tang char path[PATH_MAX]; 1309341487abSFeng Tang u64 magic; 1310341487abSFeng Tang char *name = dent->d_name; 1311341487abSFeng Tang FILE *file; 1312341487abSFeng Tang 1313341487abSFeng Tang if (!(dent->d_type == DT_REG)) 1314341487abSFeng Tang continue; 1315341487abSFeng Tang 1316341487abSFeng Tang snprintf(path, sizeof(path), "%s/%s", pwd, name); 1317341487abSFeng Tang 1318341487abSFeng Tang file = fopen(path, "r"); 1319341487abSFeng Tang if (!file) 1320341487abSFeng Tang continue; 1321341487abSFeng Tang 1322341487abSFeng Tang if (fread(&magic, 1, 8, file) < 8) 1323341487abSFeng Tang goto close_file_and_continue; 1324341487abSFeng Tang 1325341487abSFeng Tang if (is_perf_magic(magic)) { 1326341487abSFeng Tang options[nr_options] = strdup(name); 1327341487abSFeng Tang if (!options[nr_options]) 1328341487abSFeng Tang goto close_file_and_continue; 1329341487abSFeng Tang 1330341487abSFeng Tang abs_path[nr_options] = strdup(path); 1331341487abSFeng Tang if (!abs_path[nr_options]) { 1332341487abSFeng Tang free(options[nr_options]); 1333341487abSFeng Tang ui__warning("Can't search all data files due to memory shortage.\n"); 1334341487abSFeng Tang fclose(file); 1335341487abSFeng Tang break; 1336341487abSFeng Tang } 1337341487abSFeng Tang 1338341487abSFeng Tang nr_options++; 1339341487abSFeng Tang } 1340341487abSFeng Tang 1341341487abSFeng Tang close_file_and_continue: 1342341487abSFeng Tang fclose(file); 1343341487abSFeng Tang if (nr_options >= 32) { 1344341487abSFeng Tang ui__warning("Too many perf data files in PWD!\n" 1345341487abSFeng Tang "Only the first 32 files will be listed.\n"); 1346341487abSFeng Tang break; 1347341487abSFeng Tang } 1348341487abSFeng Tang } 1349341487abSFeng Tang closedir(pwd_dir); 1350341487abSFeng Tang 1351341487abSFeng Tang if (nr_options) { 1352341487abSFeng Tang choice = ui__popup_menu(nr_options, options); 1353341487abSFeng Tang if (choice < nr_options && choice >= 0) { 1354341487abSFeng Tang tmp = strdup(abs_path[choice]); 1355341487abSFeng Tang if (tmp) { 1356341487abSFeng Tang if (is_input_name_malloced) 1357341487abSFeng Tang free((void *)input_name); 1358341487abSFeng Tang input_name = tmp; 1359341487abSFeng Tang is_input_name_malloced = true; 1360341487abSFeng Tang ret = 0; 1361341487abSFeng Tang } else 1362341487abSFeng Tang ui__warning("Data switch failed due to memory shortage!\n"); 1363341487abSFeng Tang } 1364341487abSFeng Tang } 1365341487abSFeng Tang 1366341487abSFeng Tang free_popup_options(options, nr_options); 1367341487abSFeng Tang free_popup_options(abs_path, nr_options); 1368341487abSFeng Tang return ret; 1369341487abSFeng Tang } 1370341487abSFeng Tang 1371064f1981SNamhyung Kim static void hist_browser__update_pcnt_entries(struct hist_browser *hb) 1372064f1981SNamhyung Kim { 1373064f1981SNamhyung Kim u64 nr_entries = 0; 1374064f1981SNamhyung Kim struct rb_node *nd = rb_first(&hb->hists->entries); 1375064f1981SNamhyung Kim 1376064f1981SNamhyung Kim while (nd) { 1377064f1981SNamhyung Kim nr_entries++; 1378064f1981SNamhyung Kim nd = hists__filter_entries(rb_next(nd), hb->hists, 1379064f1981SNamhyung Kim hb->min_pcnt); 1380064f1981SNamhyung Kim } 1381064f1981SNamhyung Kim 1382064f1981SNamhyung Kim hb->nr_pcnt_entries = nr_entries; 1383064f1981SNamhyung Kim } 1384341487abSFeng Tang 1385aca7a94dSNamhyung Kim static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1386aca7a94dSNamhyung Kim const char *helpline, const char *ev_name, 1387aca7a94dSNamhyung Kim bool left_exits, 138868d80758SNamhyung Kim struct hist_browser_timer *hbt, 1389064f1981SNamhyung Kim float min_pcnt, 139068d80758SNamhyung Kim struct perf_session_env *env) 1391aca7a94dSNamhyung Kim { 139205e8b080SArnaldo Carvalho de Melo struct hists *hists = &evsel->hists; 139305e8b080SArnaldo Carvalho de Melo struct hist_browser *browser = hist_browser__new(hists); 1394aca7a94dSNamhyung Kim struct branch_info *bi; 1395aca7a94dSNamhyung Kim struct pstack *fstack; 1396aca7a94dSNamhyung Kim char *options[16]; 1397aca7a94dSNamhyung Kim int nr_options = 0; 1398aca7a94dSNamhyung Kim int key = -1; 1399aca7a94dSNamhyung Kim char buf[64]; 1400cdbab7c2SFeng Tang char script_opt[64]; 14019783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 1402aca7a94dSNamhyung Kim 1403*e8e684a5SNamhyung Kim #define HIST_BROWSER_HELP_COMMON \ 1404*e8e684a5SNamhyung Kim "h/?/F1 Show this window\n" \ 1405*e8e684a5SNamhyung Kim "UP/DOWN/PGUP\n" \ 1406*e8e684a5SNamhyung Kim "PGDN/SPACE Navigate\n" \ 1407*e8e684a5SNamhyung Kim "q/ESC/CTRL+C Exit browser\n\n" \ 1408*e8e684a5SNamhyung Kim "For multiple event sessions:\n\n" \ 1409*e8e684a5SNamhyung Kim "TAB/UNTAB Switch events\n\n" \ 1410*e8e684a5SNamhyung Kim "For symbolic views (--sort has sym):\n\n" \ 1411*e8e684a5SNamhyung Kim "-> Zoom into DSO/Threads & Annotate current symbol\n" \ 1412*e8e684a5SNamhyung Kim "<- Zoom out\n" \ 1413*e8e684a5SNamhyung Kim "a Annotate current symbol\n" \ 1414*e8e684a5SNamhyung Kim "C Collapse all callchains\n" \ 1415*e8e684a5SNamhyung Kim "d Zoom into current DSO\n" \ 1416*e8e684a5SNamhyung Kim "E Expand all callchains\n" \ 1417*e8e684a5SNamhyung Kim 1418*e8e684a5SNamhyung Kim /* help messages are sorted by lexical order of the hotkey */ 1419*e8e684a5SNamhyung Kim const char report_help[] = HIST_BROWSER_HELP_COMMON 1420*e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 1421*e8e684a5SNamhyung Kim "r Run available scripts\n" 1422*e8e684a5SNamhyung Kim "s Switch to another data file in PWD\n" 1423*e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 1424*e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 1425*e8e684a5SNamhyung Kim "/ Filter symbol by name"; 1426*e8e684a5SNamhyung Kim const char top_help[] = HIST_BROWSER_HELP_COMMON 1427*e8e684a5SNamhyung Kim "P Print histograms to perf.hist.N\n" 1428*e8e684a5SNamhyung Kim "t Zoom into current Thread\n" 1429*e8e684a5SNamhyung Kim "V Verbose (DSO names in callchains, etc)\n" 1430*e8e684a5SNamhyung Kim "/ Filter symbol by name"; 1431*e8e684a5SNamhyung Kim 1432aca7a94dSNamhyung Kim if (browser == NULL) 1433aca7a94dSNamhyung Kim return -1; 1434aca7a94dSNamhyung Kim 1435064f1981SNamhyung Kim if (min_pcnt) { 1436064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 1437064f1981SNamhyung Kim hist_browser__update_pcnt_entries(browser); 1438064f1981SNamhyung Kim } 1439064f1981SNamhyung Kim 1440aca7a94dSNamhyung Kim fstack = pstack__new(2); 1441aca7a94dSNamhyung Kim if (fstack == NULL) 1442aca7a94dSNamhyung Kim goto out; 1443aca7a94dSNamhyung Kim 1444aca7a94dSNamhyung Kim ui_helpline__push(helpline); 1445aca7a94dSNamhyung Kim 1446aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 1447aca7a94dSNamhyung Kim 1448aca7a94dSNamhyung Kim while (1) { 1449aca7a94dSNamhyung Kim const struct thread *thread = NULL; 1450aca7a94dSNamhyung Kim const struct dso *dso = NULL; 1451aca7a94dSNamhyung Kim int choice = 0, 1452aca7a94dSNamhyung Kim annotate = -2, zoom_dso = -2, zoom_thread = -2, 1453aca7a94dSNamhyung Kim annotate_f = -2, annotate_t = -2, browse_map = -2; 1454341487abSFeng Tang int scripts_comm = -2, scripts_symbol = -2, 1455341487abSFeng Tang scripts_all = -2, switch_data = -2; 1456aca7a94dSNamhyung Kim 1457aca7a94dSNamhyung Kim nr_options = 0; 1458aca7a94dSNamhyung Kim 14599783adf7SNamhyung Kim key = hist_browser__run(browser, ev_name, hbt); 1460aca7a94dSNamhyung Kim 1461aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 1462aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 1463aca7a94dSNamhyung Kim dso = browser->selection->map ? browser->selection->map->dso : NULL; 1464aca7a94dSNamhyung Kim } 1465aca7a94dSNamhyung Kim switch (key) { 1466aca7a94dSNamhyung Kim case K_TAB: 1467aca7a94dSNamhyung Kim case K_UNTAB: 1468aca7a94dSNamhyung Kim if (nr_events == 1) 1469aca7a94dSNamhyung Kim continue; 1470aca7a94dSNamhyung Kim /* 1471aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 1472aca7a94dSNamhyung Kim * go to the next or previous 1473aca7a94dSNamhyung Kim */ 1474aca7a94dSNamhyung Kim goto out_free_stack; 1475aca7a94dSNamhyung Kim case 'a': 14769c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) { 1477aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 1478aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 1479aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 1480aca7a94dSNamhyung Kim continue; 1481aca7a94dSNamhyung Kim } 1482aca7a94dSNamhyung Kim 1483aca7a94dSNamhyung Kim if (browser->selection == NULL || 1484aca7a94dSNamhyung Kim browser->selection->sym == NULL || 1485aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 1486aca7a94dSNamhyung Kim continue; 1487aca7a94dSNamhyung Kim goto do_annotate; 1488aff3f3f6SArnaldo Carvalho de Melo case 'P': 1489aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 1490aff3f3f6SArnaldo Carvalho de Melo continue; 1491aca7a94dSNamhyung Kim case 'd': 1492aca7a94dSNamhyung Kim goto zoom_dso; 1493a7cb8863SArnaldo Carvalho de Melo case 'V': 1494a7cb8863SArnaldo Carvalho de Melo browser->show_dso = !browser->show_dso; 1495a7cb8863SArnaldo Carvalho de Melo continue; 1496aca7a94dSNamhyung Kim case 't': 1497aca7a94dSNamhyung Kim goto zoom_thread; 14985a5626b1SArnaldo Carvalho de Melo case '/': 1499aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 1500aca7a94dSNamhyung Kim "Please enter the name of symbol you want to see", 1501aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 1502aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 150305e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 150405e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 1505aca7a94dSNamhyung Kim hist_browser__reset(browser); 1506aca7a94dSNamhyung Kim } 1507aca7a94dSNamhyung Kim continue; 1508cdbab7c2SFeng Tang case 'r': 15099783adf7SNamhyung Kim if (is_report_browser(hbt)) 1510cdbab7c2SFeng Tang goto do_scripts; 1511c77d8d70SFeng Tang continue; 1512341487abSFeng Tang case 's': 1513341487abSFeng Tang if (is_report_browser(hbt)) 1514341487abSFeng Tang goto do_data_switch; 1515341487abSFeng Tang continue; 1516aca7a94dSNamhyung Kim case K_F1: 1517aca7a94dSNamhyung Kim case 'h': 1518aca7a94dSNamhyung Kim case '?': 1519aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 1520*e8e684a5SNamhyung Kim is_report_browser(hbt) ? report_help : top_help); 1521aca7a94dSNamhyung Kim continue; 1522aca7a94dSNamhyung Kim case K_ENTER: 1523aca7a94dSNamhyung Kim case K_RIGHT: 1524aca7a94dSNamhyung Kim /* menu */ 1525aca7a94dSNamhyung Kim break; 1526aca7a94dSNamhyung Kim case K_LEFT: { 1527aca7a94dSNamhyung Kim const void *top; 1528aca7a94dSNamhyung Kim 1529aca7a94dSNamhyung Kim if (pstack__empty(fstack)) { 1530aca7a94dSNamhyung Kim /* 1531aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 1532aca7a94dSNamhyung Kim */ 1533aca7a94dSNamhyung Kim if (left_exits) 1534aca7a94dSNamhyung Kim goto out_free_stack; 1535aca7a94dSNamhyung Kim continue; 1536aca7a94dSNamhyung Kim } 1537aca7a94dSNamhyung Kim top = pstack__pop(fstack); 1538aca7a94dSNamhyung Kim if (top == &browser->hists->dso_filter) 1539aca7a94dSNamhyung Kim goto zoom_out_dso; 1540aca7a94dSNamhyung Kim if (top == &browser->hists->thread_filter) 1541aca7a94dSNamhyung Kim goto zoom_out_thread; 1542aca7a94dSNamhyung Kim continue; 1543aca7a94dSNamhyung Kim } 1544aca7a94dSNamhyung Kim case K_ESC: 1545aca7a94dSNamhyung Kim if (!left_exits && 1546aca7a94dSNamhyung Kim !ui_browser__dialog_yesno(&browser->b, 1547aca7a94dSNamhyung Kim "Do you really want to exit?")) 1548aca7a94dSNamhyung Kim continue; 1549aca7a94dSNamhyung Kim /* Fall thru */ 1550aca7a94dSNamhyung Kim case 'q': 1551aca7a94dSNamhyung Kim case CTRL('c'): 1552aca7a94dSNamhyung Kim goto out_free_stack; 1553aca7a94dSNamhyung Kim default: 1554aca7a94dSNamhyung Kim continue; 1555aca7a94dSNamhyung Kim } 1556aca7a94dSNamhyung Kim 15579c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) 1558aca7a94dSNamhyung Kim goto add_exit_option; 1559aca7a94dSNamhyung Kim 156055369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 1561aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 1562aca7a94dSNamhyung Kim if (browser->selection != NULL && 1563aca7a94dSNamhyung Kim bi && 1564aca7a94dSNamhyung Kim bi->from.sym != NULL && 1565aca7a94dSNamhyung Kim !bi->from.map->dso->annotate_warned && 1566aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1567aca7a94dSNamhyung Kim bi->from.sym->name) > 0) 1568aca7a94dSNamhyung Kim annotate_f = nr_options++; 1569aca7a94dSNamhyung Kim 1570aca7a94dSNamhyung Kim if (browser->selection != NULL && 1571aca7a94dSNamhyung Kim bi && 1572aca7a94dSNamhyung Kim bi->to.sym != NULL && 1573aca7a94dSNamhyung Kim !bi->to.map->dso->annotate_warned && 1574aca7a94dSNamhyung Kim (bi->to.sym != bi->from.sym || 1575aca7a94dSNamhyung Kim bi->to.map->dso != bi->from.map->dso) && 1576aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1577aca7a94dSNamhyung Kim bi->to.sym->name) > 0) 1578aca7a94dSNamhyung Kim annotate_t = nr_options++; 1579aca7a94dSNamhyung Kim } else { 1580aca7a94dSNamhyung Kim 1581aca7a94dSNamhyung Kim if (browser->selection != NULL && 1582aca7a94dSNamhyung Kim browser->selection->sym != NULL && 1583aca7a94dSNamhyung Kim !browser->selection->map->dso->annotate_warned && 1584aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1585aca7a94dSNamhyung Kim browser->selection->sym->name) > 0) 1586aca7a94dSNamhyung Kim annotate = nr_options++; 1587aca7a94dSNamhyung Kim } 1588aca7a94dSNamhyung Kim 1589aca7a94dSNamhyung Kim if (thread != NULL && 1590aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1591aca7a94dSNamhyung Kim (browser->hists->thread_filter ? "out of" : "into"), 1592b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 159338051234SAdrian Hunter thread->tid) > 0) 1594aca7a94dSNamhyung Kim zoom_thread = nr_options++; 1595aca7a94dSNamhyung Kim 1596aca7a94dSNamhyung Kim if (dso != NULL && 1597aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Zoom %s %s DSO", 1598aca7a94dSNamhyung Kim (browser->hists->dso_filter ? "out of" : "into"), 1599aca7a94dSNamhyung Kim (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 1600aca7a94dSNamhyung Kim zoom_dso = nr_options++; 1601aca7a94dSNamhyung Kim 1602aca7a94dSNamhyung Kim if (browser->selection != NULL && 1603aca7a94dSNamhyung Kim browser->selection->map != NULL && 1604aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Browse map details") > 0) 1605aca7a94dSNamhyung Kim browse_map = nr_options++; 1606cdbab7c2SFeng Tang 1607cdbab7c2SFeng Tang /* perf script support */ 1608cdbab7c2SFeng Tang if (browser->he_selection) { 1609cdbab7c2SFeng Tang struct symbol *sym; 1610cdbab7c2SFeng Tang 1611cdbab7c2SFeng Tang if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", 1612b9c5143aSFrederic Weisbecker thread__comm_str(browser->he_selection->thread)) > 0) 1613cdbab7c2SFeng Tang scripts_comm = nr_options++; 1614cdbab7c2SFeng Tang 1615cdbab7c2SFeng Tang sym = browser->he_selection->ms.sym; 1616cdbab7c2SFeng Tang if (sym && sym->namelen && 1617cdbab7c2SFeng Tang asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]", 1618cdbab7c2SFeng Tang sym->name) > 0) 1619cdbab7c2SFeng Tang scripts_symbol = nr_options++; 1620cdbab7c2SFeng Tang } 1621cdbab7c2SFeng Tang 1622cdbab7c2SFeng Tang if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) 1623cdbab7c2SFeng Tang scripts_all = nr_options++; 1624cdbab7c2SFeng Tang 1625341487abSFeng Tang if (is_report_browser(hbt) && asprintf(&options[nr_options], 1626341487abSFeng Tang "Switch to another data file in PWD") > 0) 1627341487abSFeng Tang switch_data = nr_options++; 1628aca7a94dSNamhyung Kim add_exit_option: 1629aca7a94dSNamhyung Kim options[nr_options++] = (char *)"Exit"; 1630aca7a94dSNamhyung Kim retry_popup_menu: 1631aca7a94dSNamhyung Kim choice = ui__popup_menu(nr_options, options); 1632aca7a94dSNamhyung Kim 1633aca7a94dSNamhyung Kim if (choice == nr_options - 1) 1634aca7a94dSNamhyung Kim break; 1635aca7a94dSNamhyung Kim 1636aca7a94dSNamhyung Kim if (choice == -1) { 1637aca7a94dSNamhyung Kim free_popup_options(options, nr_options - 1); 1638aca7a94dSNamhyung Kim continue; 1639aca7a94dSNamhyung Kim } 1640aca7a94dSNamhyung Kim 1641aca7a94dSNamhyung Kim if (choice == annotate || choice == annotate_t || choice == annotate_f) { 1642aca7a94dSNamhyung Kim struct hist_entry *he; 1643aca7a94dSNamhyung Kim int err; 1644aca7a94dSNamhyung Kim do_annotate: 164568d80758SNamhyung Kim if (!objdump_path && perf_session_env__lookup_objdump(env)) 164668d80758SNamhyung Kim continue; 164768d80758SNamhyung Kim 1648aca7a94dSNamhyung Kim he = hist_browser__selected_entry(browser); 1649aca7a94dSNamhyung Kim if (he == NULL) 1650aca7a94dSNamhyung Kim continue; 1651aca7a94dSNamhyung Kim 1652aca7a94dSNamhyung Kim /* 1653aca7a94dSNamhyung Kim * we stash the branch_info symbol + map into the 1654aca7a94dSNamhyung Kim * the ms so we don't have to rewrite all the annotation 1655aca7a94dSNamhyung Kim * code to use branch_info. 1656aca7a94dSNamhyung Kim * in branch mode, the ms struct is not used 1657aca7a94dSNamhyung Kim */ 1658aca7a94dSNamhyung Kim if (choice == annotate_f) { 1659aca7a94dSNamhyung Kim he->ms.sym = he->branch_info->from.sym; 1660aca7a94dSNamhyung Kim he->ms.map = he->branch_info->from.map; 1661aca7a94dSNamhyung Kim } else if (choice == annotate_t) { 1662aca7a94dSNamhyung Kim he->ms.sym = he->branch_info->to.sym; 1663aca7a94dSNamhyung Kim he->ms.map = he->branch_info->to.map; 1664aca7a94dSNamhyung Kim } 1665aca7a94dSNamhyung Kim 1666aca7a94dSNamhyung Kim /* 1667aca7a94dSNamhyung Kim * Don't let this be freed, say, by hists__decay_entry. 1668aca7a94dSNamhyung Kim */ 1669aca7a94dSNamhyung Kim he->used = true; 1670db8fd07aSNamhyung Kim err = hist_entry__tui_annotate(he, evsel, hbt); 1671aca7a94dSNamhyung Kim he->used = false; 1672aca7a94dSNamhyung Kim /* 1673aca7a94dSNamhyung Kim * offer option to annotate the other branch source or target 1674aca7a94dSNamhyung Kim * (if they exists) when returning from annotate 1675aca7a94dSNamhyung Kim */ 1676aca7a94dSNamhyung Kim if ((err == 'q' || err == CTRL('c')) 1677aca7a94dSNamhyung Kim && annotate_t != -2 && annotate_f != -2) 1678aca7a94dSNamhyung Kim goto retry_popup_menu; 1679aca7a94dSNamhyung Kim 1680aca7a94dSNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1681aca7a94dSNamhyung Kim if (err) 1682aca7a94dSNamhyung Kim ui_browser__handle_resize(&browser->b); 1683aca7a94dSNamhyung Kim 1684aca7a94dSNamhyung Kim } else if (choice == browse_map) 1685aca7a94dSNamhyung Kim map__browse(browser->selection->map); 1686aca7a94dSNamhyung Kim else if (choice == zoom_dso) { 1687aca7a94dSNamhyung Kim zoom_dso: 1688aca7a94dSNamhyung Kim if (browser->hists->dso_filter) { 1689aca7a94dSNamhyung Kim pstack__remove(fstack, &browser->hists->dso_filter); 1690aca7a94dSNamhyung Kim zoom_out_dso: 1691aca7a94dSNamhyung Kim ui_helpline__pop(); 1692aca7a94dSNamhyung Kim browser->hists->dso_filter = NULL; 1693aca7a94dSNamhyung Kim sort_dso.elide = false; 1694aca7a94dSNamhyung Kim } else { 1695aca7a94dSNamhyung Kim if (dso == NULL) 1696aca7a94dSNamhyung Kim continue; 1697aca7a94dSNamhyung Kim ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1698aca7a94dSNamhyung Kim dso->kernel ? "the Kernel" : dso->short_name); 1699aca7a94dSNamhyung Kim browser->hists->dso_filter = dso; 1700aca7a94dSNamhyung Kim sort_dso.elide = true; 1701aca7a94dSNamhyung Kim pstack__push(fstack, &browser->hists->dso_filter); 1702aca7a94dSNamhyung Kim } 170305e8b080SArnaldo Carvalho de Melo hists__filter_by_dso(hists); 1704aca7a94dSNamhyung Kim hist_browser__reset(browser); 1705aca7a94dSNamhyung Kim } else if (choice == zoom_thread) { 1706aca7a94dSNamhyung Kim zoom_thread: 1707aca7a94dSNamhyung Kim if (browser->hists->thread_filter) { 1708aca7a94dSNamhyung Kim pstack__remove(fstack, &browser->hists->thread_filter); 1709aca7a94dSNamhyung Kim zoom_out_thread: 1710aca7a94dSNamhyung Kim ui_helpline__pop(); 1711aca7a94dSNamhyung Kim browser->hists->thread_filter = NULL; 1712aca7a94dSNamhyung Kim sort_thread.elide = false; 1713aca7a94dSNamhyung Kim } else { 1714aca7a94dSNamhyung Kim ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1715b9c5143aSFrederic Weisbecker thread->comm_set ? thread__comm_str(thread) : "", 171638051234SAdrian Hunter thread->tid); 1717aca7a94dSNamhyung Kim browser->hists->thread_filter = thread; 1718aca7a94dSNamhyung Kim sort_thread.elide = true; 1719aca7a94dSNamhyung Kim pstack__push(fstack, &browser->hists->thread_filter); 1720aca7a94dSNamhyung Kim } 172105e8b080SArnaldo Carvalho de Melo hists__filter_by_thread(hists); 1722aca7a94dSNamhyung Kim hist_browser__reset(browser); 1723aca7a94dSNamhyung Kim } 1724cdbab7c2SFeng Tang /* perf scripts support */ 1725cdbab7c2SFeng Tang else if (choice == scripts_all || choice == scripts_comm || 1726cdbab7c2SFeng Tang choice == scripts_symbol) { 1727cdbab7c2SFeng Tang do_scripts: 1728cdbab7c2SFeng Tang memset(script_opt, 0, 64); 1729cdbab7c2SFeng Tang 1730cdbab7c2SFeng Tang if (choice == scripts_comm) 1731b9c5143aSFrederic Weisbecker sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread)); 1732cdbab7c2SFeng Tang 1733cdbab7c2SFeng Tang if (choice == scripts_symbol) 1734cdbab7c2SFeng Tang sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); 1735cdbab7c2SFeng Tang 1736cdbab7c2SFeng Tang script_browse(script_opt); 1737cdbab7c2SFeng Tang } 1738341487abSFeng Tang /* Switch to another data file */ 1739341487abSFeng Tang else if (choice == switch_data) { 1740341487abSFeng Tang do_data_switch: 1741341487abSFeng Tang if (!switch_data_file()) { 1742341487abSFeng Tang key = K_SWITCH_INPUT_DATA; 1743341487abSFeng Tang break; 1744341487abSFeng Tang } else 1745341487abSFeng Tang ui__warning("Won't switch the data files due to\n" 1746341487abSFeng Tang "no valid data file get selected!\n"); 1747341487abSFeng Tang } 1748aca7a94dSNamhyung Kim } 1749aca7a94dSNamhyung Kim out_free_stack: 1750aca7a94dSNamhyung Kim pstack__delete(fstack); 1751aca7a94dSNamhyung Kim out: 1752aca7a94dSNamhyung Kim hist_browser__delete(browser); 1753aca7a94dSNamhyung Kim free_popup_options(options, nr_options - 1); 1754aca7a94dSNamhyung Kim return key; 1755aca7a94dSNamhyung Kim } 1756aca7a94dSNamhyung Kim 1757aca7a94dSNamhyung Kim struct perf_evsel_menu { 1758aca7a94dSNamhyung Kim struct ui_browser b; 1759aca7a94dSNamhyung Kim struct perf_evsel *selection; 1760aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 1761064f1981SNamhyung Kim float min_pcnt; 176268d80758SNamhyung Kim struct perf_session_env *env; 1763aca7a94dSNamhyung Kim }; 1764aca7a94dSNamhyung Kim 1765aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 1766aca7a94dSNamhyung Kim void *entry, int row) 1767aca7a94dSNamhyung Kim { 1768aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 1769aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 1770aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1771aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 1772aca7a94dSNamhyung Kim unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 17737289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 1774aca7a94dSNamhyung Kim char bf[256], unit; 1775aca7a94dSNamhyung Kim const char *warn = " "; 1776aca7a94dSNamhyung Kim size_t printed; 1777aca7a94dSNamhyung Kim 1778aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1779aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 1780aca7a94dSNamhyung Kim 1781759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1782717e263fSNamhyung Kim struct perf_evsel *pos; 1783717e263fSNamhyung Kim 1784717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 1785717e263fSNamhyung Kim 1786717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 1787717e263fSNamhyung Kim nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1788717e263fSNamhyung Kim } 1789717e263fSNamhyung Kim } 1790717e263fSNamhyung Kim 1791aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 1792aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1793aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 1794aca7a94dSNamhyung Kim slsmg_printf("%s", bf); 1795aca7a94dSNamhyung Kim 1796aca7a94dSNamhyung Kim nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 1797aca7a94dSNamhyung Kim if (nr_events != 0) { 1798aca7a94dSNamhyung Kim menu->lost_events = true; 1799aca7a94dSNamhyung Kim if (!current_entry) 1800aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 1801aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 1802aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 1803aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 1804aca7a94dSNamhyung Kim warn = bf; 1805aca7a94dSNamhyung Kim } 1806aca7a94dSNamhyung Kim 1807aca7a94dSNamhyung Kim slsmg_write_nstring(warn, browser->width - printed); 1808aca7a94dSNamhyung Kim 1809aca7a94dSNamhyung Kim if (current_entry) 1810aca7a94dSNamhyung Kim menu->selection = evsel; 1811aca7a94dSNamhyung Kim } 1812aca7a94dSNamhyung Kim 1813aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 1814aca7a94dSNamhyung Kim int nr_events, const char *help, 18159783adf7SNamhyung Kim struct hist_browser_timer *hbt) 1816aca7a94dSNamhyung Kim { 1817aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 1818aca7a94dSNamhyung Kim struct perf_evsel *pos; 1819aca7a94dSNamhyung Kim const char *ev_name, *title = "Available samples"; 18209783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 1821aca7a94dSNamhyung Kim int key; 1822aca7a94dSNamhyung Kim 1823aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 1824aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 1825aca7a94dSNamhyung Kim return -1; 1826aca7a94dSNamhyung Kim 1827aca7a94dSNamhyung Kim while (1) { 1828aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 1829aca7a94dSNamhyung Kim 1830aca7a94dSNamhyung Kim switch (key) { 1831aca7a94dSNamhyung Kim case K_TIMER: 18329783adf7SNamhyung Kim hbt->timer(hbt->arg); 1833aca7a94dSNamhyung Kim 1834aca7a94dSNamhyung Kim if (!menu->lost_events_warned && menu->lost_events) { 1835aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 1836aca7a94dSNamhyung Kim menu->lost_events_warned = true; 1837aca7a94dSNamhyung Kim } 1838aca7a94dSNamhyung Kim continue; 1839aca7a94dSNamhyung Kim case K_RIGHT: 1840aca7a94dSNamhyung Kim case K_ENTER: 1841aca7a94dSNamhyung Kim if (!menu->selection) 1842aca7a94dSNamhyung Kim continue; 1843aca7a94dSNamhyung Kim pos = menu->selection; 1844aca7a94dSNamhyung Kim browse_hists: 1845aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 1846aca7a94dSNamhyung Kim /* 1847aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 1848aca7a94dSNamhyung Kim * default evsel resorted hists tree. 1849aca7a94dSNamhyung Kim */ 18509783adf7SNamhyung Kim if (hbt) 18519783adf7SNamhyung Kim hbt->timer(hbt->arg); 18527289f83cSArnaldo Carvalho de Melo ev_name = perf_evsel__name(pos); 1853aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 185468d80758SNamhyung Kim ev_name, true, hbt, 1855064f1981SNamhyung Kim menu->min_pcnt, 185668d80758SNamhyung Kim menu->env); 1857aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 1858aca7a94dSNamhyung Kim switch (key) { 1859aca7a94dSNamhyung Kim case K_TAB: 1860aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 18619a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__first(evlist); 1862aca7a94dSNamhyung Kim else 18639a354cdcSArnaldo Carvalho de Melo pos = perf_evsel__next(pos); 1864aca7a94dSNamhyung Kim goto browse_hists; 1865aca7a94dSNamhyung Kim case K_UNTAB: 1866aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 18679a354cdcSArnaldo Carvalho de Melo pos = perf_evlist__last(evlist); 1868aca7a94dSNamhyung Kim else 1869d87fcb4aSArnaldo Carvalho de Melo pos = perf_evsel__prev(pos); 1870aca7a94dSNamhyung Kim goto browse_hists; 1871aca7a94dSNamhyung Kim case K_ESC: 1872aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 1873aca7a94dSNamhyung Kim "Do you really want to exit?")) 1874aca7a94dSNamhyung Kim continue; 1875aca7a94dSNamhyung Kim /* Fall thru */ 1876341487abSFeng Tang case K_SWITCH_INPUT_DATA: 1877aca7a94dSNamhyung Kim case 'q': 1878aca7a94dSNamhyung Kim case CTRL('c'): 1879aca7a94dSNamhyung Kim goto out; 1880aca7a94dSNamhyung Kim default: 1881aca7a94dSNamhyung Kim continue; 1882aca7a94dSNamhyung Kim } 1883aca7a94dSNamhyung Kim case K_LEFT: 1884aca7a94dSNamhyung Kim continue; 1885aca7a94dSNamhyung Kim case K_ESC: 1886aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 1887aca7a94dSNamhyung Kim "Do you really want to exit?")) 1888aca7a94dSNamhyung Kim continue; 1889aca7a94dSNamhyung Kim /* Fall thru */ 1890aca7a94dSNamhyung Kim case 'q': 1891aca7a94dSNamhyung Kim case CTRL('c'): 1892aca7a94dSNamhyung Kim goto out; 1893aca7a94dSNamhyung Kim default: 1894aca7a94dSNamhyung Kim continue; 1895aca7a94dSNamhyung Kim } 1896aca7a94dSNamhyung Kim } 1897aca7a94dSNamhyung Kim 1898aca7a94dSNamhyung Kim out: 1899aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 1900aca7a94dSNamhyung Kim return key; 1901aca7a94dSNamhyung Kim } 1902aca7a94dSNamhyung Kim 1903316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 1904fc24d7c2SNamhyung Kim void *entry) 1905fc24d7c2SNamhyung Kim { 1906fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1907fc24d7c2SNamhyung Kim 1908fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 1909fc24d7c2SNamhyung Kim return true; 1910fc24d7c2SNamhyung Kim 1911fc24d7c2SNamhyung Kim return false; 1912fc24d7c2SNamhyung Kim } 1913fc24d7c2SNamhyung Kim 1914aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1915fc24d7c2SNamhyung Kim int nr_entries, const char *help, 191668d80758SNamhyung Kim struct hist_browser_timer *hbt, 1917064f1981SNamhyung Kim float min_pcnt, 191868d80758SNamhyung Kim struct perf_session_env *env) 1919aca7a94dSNamhyung Kim { 1920aca7a94dSNamhyung Kim struct perf_evsel *pos; 1921aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 1922aca7a94dSNamhyung Kim .b = { 1923aca7a94dSNamhyung Kim .entries = &evlist->entries, 1924aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 1925aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 1926aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 1927fc24d7c2SNamhyung Kim .filter = filter_group_entries, 1928fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 1929aca7a94dSNamhyung Kim .priv = evlist, 1930aca7a94dSNamhyung Kim }, 1931064f1981SNamhyung Kim .min_pcnt = min_pcnt, 193268d80758SNamhyung Kim .env = env, 1933aca7a94dSNamhyung Kim }; 1934aca7a94dSNamhyung Kim 1935aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 1936aca7a94dSNamhyung Kim 1937aca7a94dSNamhyung Kim list_for_each_entry(pos, &evlist->entries, node) { 19387289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 1939aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 1940aca7a94dSNamhyung Kim 1941aca7a94dSNamhyung Kim if (menu.b.width < line_len) 1942aca7a94dSNamhyung Kim menu.b.width = line_len; 1943aca7a94dSNamhyung Kim } 1944aca7a94dSNamhyung Kim 1945fc24d7c2SNamhyung Kim return perf_evsel_menu__run(&menu, nr_entries, help, hbt); 1946aca7a94dSNamhyung Kim } 1947aca7a94dSNamhyung Kim 1948aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 194968d80758SNamhyung Kim struct hist_browser_timer *hbt, 1950064f1981SNamhyung Kim float min_pcnt, 195168d80758SNamhyung Kim struct perf_session_env *env) 1952aca7a94dSNamhyung Kim { 1953fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 1954fc24d7c2SNamhyung Kim 1955fc24d7c2SNamhyung Kim single_entry: 1956fc24d7c2SNamhyung Kim if (nr_entries == 1) { 19579a354cdcSArnaldo Carvalho de Melo struct perf_evsel *first = perf_evlist__first(evlist); 19587289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(first); 1959fc24d7c2SNamhyung Kim 1960fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 1961064f1981SNamhyung Kim ev_name, false, hbt, min_pcnt, 1962064f1981SNamhyung Kim env); 1963aca7a94dSNamhyung Kim } 1964aca7a94dSNamhyung Kim 1965fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 1966fc24d7c2SNamhyung Kim struct perf_evsel *pos; 1967fc24d7c2SNamhyung Kim 1968fc24d7c2SNamhyung Kim nr_entries = 0; 1969fc24d7c2SNamhyung Kim list_for_each_entry(pos, &evlist->entries, node) 1970fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 1971fc24d7c2SNamhyung Kim nr_entries++; 1972fc24d7c2SNamhyung Kim 1973fc24d7c2SNamhyung Kim if (nr_entries == 1) 1974fc24d7c2SNamhyung Kim goto single_entry; 1975fc24d7c2SNamhyung Kim } 1976fc24d7c2SNamhyung Kim 1977fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 1978064f1981SNamhyung Kim hbt, min_pcnt, env); 1979aca7a94dSNamhyung Kim } 1980