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 1403aca7a94dSNamhyung Kim if (browser == NULL) 1404aca7a94dSNamhyung Kim return -1; 1405aca7a94dSNamhyung Kim 1406064f1981SNamhyung Kim if (min_pcnt) { 1407064f1981SNamhyung Kim browser->min_pcnt = min_pcnt; 1408064f1981SNamhyung Kim hist_browser__update_pcnt_entries(browser); 1409064f1981SNamhyung Kim } 1410064f1981SNamhyung Kim 1411aca7a94dSNamhyung Kim fstack = pstack__new(2); 1412aca7a94dSNamhyung Kim if (fstack == NULL) 1413aca7a94dSNamhyung Kim goto out; 1414aca7a94dSNamhyung Kim 1415aca7a94dSNamhyung Kim ui_helpline__push(helpline); 1416aca7a94dSNamhyung Kim 1417aca7a94dSNamhyung Kim memset(options, 0, sizeof(options)); 1418aca7a94dSNamhyung Kim 1419aca7a94dSNamhyung Kim while (1) { 1420aca7a94dSNamhyung Kim const struct thread *thread = NULL; 1421aca7a94dSNamhyung Kim const struct dso *dso = NULL; 1422aca7a94dSNamhyung Kim int choice = 0, 1423aca7a94dSNamhyung Kim annotate = -2, zoom_dso = -2, zoom_thread = -2, 1424aca7a94dSNamhyung Kim annotate_f = -2, annotate_t = -2, browse_map = -2; 1425341487abSFeng Tang int scripts_comm = -2, scripts_symbol = -2, 1426341487abSFeng Tang scripts_all = -2, switch_data = -2; 1427aca7a94dSNamhyung Kim 1428aca7a94dSNamhyung Kim nr_options = 0; 1429aca7a94dSNamhyung Kim 14309783adf7SNamhyung Kim key = hist_browser__run(browser, ev_name, hbt); 1431aca7a94dSNamhyung Kim 1432aca7a94dSNamhyung Kim if (browser->he_selection != NULL) { 1433aca7a94dSNamhyung Kim thread = hist_browser__selected_thread(browser); 1434aca7a94dSNamhyung Kim dso = browser->selection->map ? browser->selection->map->dso : NULL; 1435aca7a94dSNamhyung Kim } 1436aca7a94dSNamhyung Kim switch (key) { 1437aca7a94dSNamhyung Kim case K_TAB: 1438aca7a94dSNamhyung Kim case K_UNTAB: 1439aca7a94dSNamhyung Kim if (nr_events == 1) 1440aca7a94dSNamhyung Kim continue; 1441aca7a94dSNamhyung Kim /* 1442aca7a94dSNamhyung Kim * Exit the browser, let hists__browser_tree 1443aca7a94dSNamhyung Kim * go to the next or previous 1444aca7a94dSNamhyung Kim */ 1445aca7a94dSNamhyung Kim goto out_free_stack; 1446aca7a94dSNamhyung Kim case 'a': 14479c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) { 1448aca7a94dSNamhyung Kim ui_browser__warning(&browser->b, delay_secs * 2, 1449aca7a94dSNamhyung Kim "Annotation is only available for symbolic views, " 1450aca7a94dSNamhyung Kim "include \"sym*\" in --sort to use it."); 1451aca7a94dSNamhyung Kim continue; 1452aca7a94dSNamhyung Kim } 1453aca7a94dSNamhyung Kim 1454aca7a94dSNamhyung Kim if (browser->selection == NULL || 1455aca7a94dSNamhyung Kim browser->selection->sym == NULL || 1456aca7a94dSNamhyung Kim browser->selection->map->dso->annotate_warned) 1457aca7a94dSNamhyung Kim continue; 1458aca7a94dSNamhyung Kim goto do_annotate; 1459aff3f3f6SArnaldo Carvalho de Melo case 'P': 1460aff3f3f6SArnaldo Carvalho de Melo hist_browser__dump(browser); 1461aff3f3f6SArnaldo Carvalho de Melo continue; 1462aca7a94dSNamhyung Kim case 'd': 1463aca7a94dSNamhyung Kim goto zoom_dso; 1464a7cb8863SArnaldo Carvalho de Melo case 'V': 1465a7cb8863SArnaldo Carvalho de Melo browser->show_dso = !browser->show_dso; 1466a7cb8863SArnaldo Carvalho de Melo continue; 1467aca7a94dSNamhyung Kim case 't': 1468aca7a94dSNamhyung Kim goto zoom_thread; 14695a5626b1SArnaldo Carvalho de Melo case '/': 1470aca7a94dSNamhyung Kim if (ui_browser__input_window("Symbol to show", 1471aca7a94dSNamhyung Kim "Please enter the name of symbol you want to see", 1472aca7a94dSNamhyung Kim buf, "ENTER: OK, ESC: Cancel", 1473aca7a94dSNamhyung Kim delay_secs * 2) == K_ENTER) { 147405e8b080SArnaldo Carvalho de Melo hists->symbol_filter_str = *buf ? buf : NULL; 147505e8b080SArnaldo Carvalho de Melo hists__filter_by_symbol(hists); 1476aca7a94dSNamhyung Kim hist_browser__reset(browser); 1477aca7a94dSNamhyung Kim } 1478aca7a94dSNamhyung Kim continue; 1479cdbab7c2SFeng Tang case 'r': 14809783adf7SNamhyung Kim if (is_report_browser(hbt)) 1481cdbab7c2SFeng Tang goto do_scripts; 1482c77d8d70SFeng Tang continue; 1483341487abSFeng Tang case 's': 1484341487abSFeng Tang if (is_report_browser(hbt)) 1485341487abSFeng Tang goto do_data_switch; 1486341487abSFeng Tang continue; 1487aca7a94dSNamhyung Kim case K_F1: 1488aca7a94dSNamhyung Kim case 'h': 1489aca7a94dSNamhyung Kim case '?': 1490aca7a94dSNamhyung Kim ui_browser__help_window(&browser->b, 1491aca7a94dSNamhyung Kim "h/?/F1 Show this window\n" 1492aca7a94dSNamhyung Kim "UP/DOWN/PGUP\n" 1493aca7a94dSNamhyung Kim "PGDN/SPACE Navigate\n" 1494aca7a94dSNamhyung Kim "q/ESC/CTRL+C Exit browser\n\n" 1495aca7a94dSNamhyung Kim "For multiple event sessions:\n\n" 1496aca7a94dSNamhyung Kim "TAB/UNTAB Switch events\n\n" 1497aca7a94dSNamhyung Kim "For symbolic views (--sort has sym):\n\n" 1498aca7a94dSNamhyung Kim "-> Zoom into DSO/Threads & Annotate current symbol\n" 1499aca7a94dSNamhyung Kim "<- Zoom out\n" 1500aca7a94dSNamhyung Kim "a Annotate current symbol\n" 1501aca7a94dSNamhyung Kim "C Collapse all callchains\n" 1502aca7a94dSNamhyung Kim "E Expand all callchains\n" 1503aca7a94dSNamhyung Kim "d Zoom into current DSO\n" 1504aca7a94dSNamhyung Kim "t Zoom into current Thread\n" 1505c77d8d70SFeng Tang "r Run available scripts('perf report' only)\n" 1506341487abSFeng Tang "s Switch to another data file in PWD ('perf report' only)\n" 1507aff3f3f6SArnaldo Carvalho de Melo "P Print histograms to perf.hist.N\n" 1508a7cb8863SArnaldo Carvalho de Melo "V Verbose (DSO names in callchains, etc)\n" 15095a5626b1SArnaldo Carvalho de Melo "/ Filter symbol by name"); 1510aca7a94dSNamhyung Kim continue; 1511aca7a94dSNamhyung Kim case K_ENTER: 1512aca7a94dSNamhyung Kim case K_RIGHT: 1513aca7a94dSNamhyung Kim /* menu */ 1514aca7a94dSNamhyung Kim break; 1515aca7a94dSNamhyung Kim case K_LEFT: { 1516aca7a94dSNamhyung Kim const void *top; 1517aca7a94dSNamhyung Kim 1518aca7a94dSNamhyung Kim if (pstack__empty(fstack)) { 1519aca7a94dSNamhyung Kim /* 1520aca7a94dSNamhyung Kim * Go back to the perf_evsel_menu__run or other user 1521aca7a94dSNamhyung Kim */ 1522aca7a94dSNamhyung Kim if (left_exits) 1523aca7a94dSNamhyung Kim goto out_free_stack; 1524aca7a94dSNamhyung Kim continue; 1525aca7a94dSNamhyung Kim } 1526aca7a94dSNamhyung Kim top = pstack__pop(fstack); 1527aca7a94dSNamhyung Kim if (top == &browser->hists->dso_filter) 1528aca7a94dSNamhyung Kim goto zoom_out_dso; 1529aca7a94dSNamhyung Kim if (top == &browser->hists->thread_filter) 1530aca7a94dSNamhyung Kim goto zoom_out_thread; 1531aca7a94dSNamhyung Kim continue; 1532aca7a94dSNamhyung Kim } 1533aca7a94dSNamhyung Kim case K_ESC: 1534aca7a94dSNamhyung Kim if (!left_exits && 1535aca7a94dSNamhyung Kim !ui_browser__dialog_yesno(&browser->b, 1536aca7a94dSNamhyung Kim "Do you really want to exit?")) 1537aca7a94dSNamhyung Kim continue; 1538aca7a94dSNamhyung Kim /* Fall thru */ 1539aca7a94dSNamhyung Kim case 'q': 1540aca7a94dSNamhyung Kim case CTRL('c'): 1541aca7a94dSNamhyung Kim goto out_free_stack; 1542aca7a94dSNamhyung Kim default: 1543aca7a94dSNamhyung Kim continue; 1544aca7a94dSNamhyung Kim } 1545aca7a94dSNamhyung Kim 15469c796ec8SArnaldo Carvalho de Melo if (!sort__has_sym) 1547aca7a94dSNamhyung Kim goto add_exit_option; 1548aca7a94dSNamhyung Kim 154955369fc1SNamhyung Kim if (sort__mode == SORT_MODE__BRANCH) { 1550aca7a94dSNamhyung Kim bi = browser->he_selection->branch_info; 1551aca7a94dSNamhyung Kim if (browser->selection != NULL && 1552aca7a94dSNamhyung Kim bi && 1553aca7a94dSNamhyung Kim bi->from.sym != NULL && 1554aca7a94dSNamhyung Kim !bi->from.map->dso->annotate_warned && 1555aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1556aca7a94dSNamhyung Kim bi->from.sym->name) > 0) 1557aca7a94dSNamhyung Kim annotate_f = nr_options++; 1558aca7a94dSNamhyung Kim 1559aca7a94dSNamhyung Kim if (browser->selection != NULL && 1560aca7a94dSNamhyung Kim bi && 1561aca7a94dSNamhyung Kim bi->to.sym != NULL && 1562aca7a94dSNamhyung Kim !bi->to.map->dso->annotate_warned && 1563aca7a94dSNamhyung Kim (bi->to.sym != bi->from.sym || 1564aca7a94dSNamhyung Kim bi->to.map->dso != bi->from.map->dso) && 1565aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1566aca7a94dSNamhyung Kim bi->to.sym->name) > 0) 1567aca7a94dSNamhyung Kim annotate_t = nr_options++; 1568aca7a94dSNamhyung Kim } else { 1569aca7a94dSNamhyung Kim 1570aca7a94dSNamhyung Kim if (browser->selection != NULL && 1571aca7a94dSNamhyung Kim browser->selection->sym != NULL && 1572aca7a94dSNamhyung Kim !browser->selection->map->dso->annotate_warned && 1573aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Annotate %s", 1574aca7a94dSNamhyung Kim browser->selection->sym->name) > 0) 1575aca7a94dSNamhyung Kim annotate = nr_options++; 1576aca7a94dSNamhyung Kim } 1577aca7a94dSNamhyung Kim 1578aca7a94dSNamhyung Kim if (thread != NULL && 1579aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1580aca7a94dSNamhyung Kim (browser->hists->thread_filter ? "out of" : "into"), 1581b9c5143aSFrederic Weisbecker (thread->comm_set ? thread__comm_str(thread) : ""), 158238051234SAdrian Hunter thread->tid) > 0) 1583aca7a94dSNamhyung Kim zoom_thread = nr_options++; 1584aca7a94dSNamhyung Kim 1585aca7a94dSNamhyung Kim if (dso != NULL && 1586aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Zoom %s %s DSO", 1587aca7a94dSNamhyung Kim (browser->hists->dso_filter ? "out of" : "into"), 1588aca7a94dSNamhyung Kim (dso->kernel ? "the Kernel" : dso->short_name)) > 0) 1589aca7a94dSNamhyung Kim zoom_dso = nr_options++; 1590aca7a94dSNamhyung Kim 1591aca7a94dSNamhyung Kim if (browser->selection != NULL && 1592aca7a94dSNamhyung Kim browser->selection->map != NULL && 1593aca7a94dSNamhyung Kim asprintf(&options[nr_options], "Browse map details") > 0) 1594aca7a94dSNamhyung Kim browse_map = nr_options++; 1595cdbab7c2SFeng Tang 1596cdbab7c2SFeng Tang /* perf script support */ 1597cdbab7c2SFeng Tang if (browser->he_selection) { 1598cdbab7c2SFeng Tang struct symbol *sym; 1599cdbab7c2SFeng Tang 1600cdbab7c2SFeng Tang if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]", 1601b9c5143aSFrederic Weisbecker thread__comm_str(browser->he_selection->thread)) > 0) 1602cdbab7c2SFeng Tang scripts_comm = nr_options++; 1603cdbab7c2SFeng Tang 1604cdbab7c2SFeng Tang sym = browser->he_selection->ms.sym; 1605cdbab7c2SFeng Tang if (sym && sym->namelen && 1606cdbab7c2SFeng Tang asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]", 1607cdbab7c2SFeng Tang sym->name) > 0) 1608cdbab7c2SFeng Tang scripts_symbol = nr_options++; 1609cdbab7c2SFeng Tang } 1610cdbab7c2SFeng Tang 1611cdbab7c2SFeng Tang if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) 1612cdbab7c2SFeng Tang scripts_all = nr_options++; 1613cdbab7c2SFeng Tang 1614341487abSFeng Tang if (is_report_browser(hbt) && asprintf(&options[nr_options], 1615341487abSFeng Tang "Switch to another data file in PWD") > 0) 1616341487abSFeng Tang switch_data = nr_options++; 1617aca7a94dSNamhyung Kim add_exit_option: 1618aca7a94dSNamhyung Kim options[nr_options++] = (char *)"Exit"; 1619aca7a94dSNamhyung Kim retry_popup_menu: 1620aca7a94dSNamhyung Kim choice = ui__popup_menu(nr_options, options); 1621aca7a94dSNamhyung Kim 1622aca7a94dSNamhyung Kim if (choice == nr_options - 1) 1623aca7a94dSNamhyung Kim break; 1624aca7a94dSNamhyung Kim 1625aca7a94dSNamhyung Kim if (choice == -1) { 1626aca7a94dSNamhyung Kim free_popup_options(options, nr_options - 1); 1627aca7a94dSNamhyung Kim continue; 1628aca7a94dSNamhyung Kim } 1629aca7a94dSNamhyung Kim 1630aca7a94dSNamhyung Kim if (choice == annotate || choice == annotate_t || choice == annotate_f) { 1631aca7a94dSNamhyung Kim struct hist_entry *he; 1632aca7a94dSNamhyung Kim int err; 1633aca7a94dSNamhyung Kim do_annotate: 163468d80758SNamhyung Kim if (!objdump_path && perf_session_env__lookup_objdump(env)) 163568d80758SNamhyung Kim continue; 163668d80758SNamhyung Kim 1637aca7a94dSNamhyung Kim he = hist_browser__selected_entry(browser); 1638aca7a94dSNamhyung Kim if (he == NULL) 1639aca7a94dSNamhyung Kim continue; 1640aca7a94dSNamhyung Kim 1641aca7a94dSNamhyung Kim /* 1642aca7a94dSNamhyung Kim * we stash the branch_info symbol + map into the 1643aca7a94dSNamhyung Kim * the ms so we don't have to rewrite all the annotation 1644aca7a94dSNamhyung Kim * code to use branch_info. 1645aca7a94dSNamhyung Kim * in branch mode, the ms struct is not used 1646aca7a94dSNamhyung Kim */ 1647aca7a94dSNamhyung Kim if (choice == annotate_f) { 1648aca7a94dSNamhyung Kim he->ms.sym = he->branch_info->from.sym; 1649aca7a94dSNamhyung Kim he->ms.map = he->branch_info->from.map; 1650aca7a94dSNamhyung Kim } else if (choice == annotate_t) { 1651aca7a94dSNamhyung Kim he->ms.sym = he->branch_info->to.sym; 1652aca7a94dSNamhyung Kim he->ms.map = he->branch_info->to.map; 1653aca7a94dSNamhyung Kim } 1654aca7a94dSNamhyung Kim 1655aca7a94dSNamhyung Kim /* 1656aca7a94dSNamhyung Kim * Don't let this be freed, say, by hists__decay_entry. 1657aca7a94dSNamhyung Kim */ 1658aca7a94dSNamhyung Kim he->used = true; 1659db8fd07aSNamhyung Kim err = hist_entry__tui_annotate(he, evsel, hbt); 1660aca7a94dSNamhyung Kim he->used = false; 1661aca7a94dSNamhyung Kim /* 1662aca7a94dSNamhyung Kim * offer option to annotate the other branch source or target 1663aca7a94dSNamhyung Kim * (if they exists) when returning from annotate 1664aca7a94dSNamhyung Kim */ 1665aca7a94dSNamhyung Kim if ((err == 'q' || err == CTRL('c')) 1666aca7a94dSNamhyung Kim && annotate_t != -2 && annotate_f != -2) 1667aca7a94dSNamhyung Kim goto retry_popup_menu; 1668aca7a94dSNamhyung Kim 1669aca7a94dSNamhyung Kim ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1670aca7a94dSNamhyung Kim if (err) 1671aca7a94dSNamhyung Kim ui_browser__handle_resize(&browser->b); 1672aca7a94dSNamhyung Kim 1673aca7a94dSNamhyung Kim } else if (choice == browse_map) 1674aca7a94dSNamhyung Kim map__browse(browser->selection->map); 1675aca7a94dSNamhyung Kim else if (choice == zoom_dso) { 1676aca7a94dSNamhyung Kim zoom_dso: 1677aca7a94dSNamhyung Kim if (browser->hists->dso_filter) { 1678aca7a94dSNamhyung Kim pstack__remove(fstack, &browser->hists->dso_filter); 1679aca7a94dSNamhyung Kim zoom_out_dso: 1680aca7a94dSNamhyung Kim ui_helpline__pop(); 1681aca7a94dSNamhyung Kim browser->hists->dso_filter = NULL; 1682aca7a94dSNamhyung Kim sort_dso.elide = false; 1683aca7a94dSNamhyung Kim } else { 1684aca7a94dSNamhyung Kim if (dso == NULL) 1685aca7a94dSNamhyung Kim continue; 1686aca7a94dSNamhyung Kim ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1687aca7a94dSNamhyung Kim dso->kernel ? "the Kernel" : dso->short_name); 1688aca7a94dSNamhyung Kim browser->hists->dso_filter = dso; 1689aca7a94dSNamhyung Kim sort_dso.elide = true; 1690aca7a94dSNamhyung Kim pstack__push(fstack, &browser->hists->dso_filter); 1691aca7a94dSNamhyung Kim } 169205e8b080SArnaldo Carvalho de Melo hists__filter_by_dso(hists); 1693aca7a94dSNamhyung Kim hist_browser__reset(browser); 1694aca7a94dSNamhyung Kim } else if (choice == zoom_thread) { 1695aca7a94dSNamhyung Kim zoom_thread: 1696aca7a94dSNamhyung Kim if (browser->hists->thread_filter) { 1697aca7a94dSNamhyung Kim pstack__remove(fstack, &browser->hists->thread_filter); 1698aca7a94dSNamhyung Kim zoom_out_thread: 1699aca7a94dSNamhyung Kim ui_helpline__pop(); 1700aca7a94dSNamhyung Kim browser->hists->thread_filter = NULL; 1701aca7a94dSNamhyung Kim sort_thread.elide = false; 1702aca7a94dSNamhyung Kim } else { 1703aca7a94dSNamhyung Kim ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1704b9c5143aSFrederic Weisbecker thread->comm_set ? thread__comm_str(thread) : "", 170538051234SAdrian Hunter thread->tid); 1706aca7a94dSNamhyung Kim browser->hists->thread_filter = thread; 1707aca7a94dSNamhyung Kim sort_thread.elide = true; 1708aca7a94dSNamhyung Kim pstack__push(fstack, &browser->hists->thread_filter); 1709aca7a94dSNamhyung Kim } 171005e8b080SArnaldo Carvalho de Melo hists__filter_by_thread(hists); 1711aca7a94dSNamhyung Kim hist_browser__reset(browser); 1712aca7a94dSNamhyung Kim } 1713cdbab7c2SFeng Tang /* perf scripts support */ 1714cdbab7c2SFeng Tang else if (choice == scripts_all || choice == scripts_comm || 1715cdbab7c2SFeng Tang choice == scripts_symbol) { 1716cdbab7c2SFeng Tang do_scripts: 1717cdbab7c2SFeng Tang memset(script_opt, 0, 64); 1718cdbab7c2SFeng Tang 1719cdbab7c2SFeng Tang if (choice == scripts_comm) 1720b9c5143aSFrederic Weisbecker sprintf(script_opt, " -c %s ", thread__comm_str(browser->he_selection->thread)); 1721cdbab7c2SFeng Tang 1722cdbab7c2SFeng Tang if (choice == scripts_symbol) 1723cdbab7c2SFeng Tang sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name); 1724cdbab7c2SFeng Tang 1725cdbab7c2SFeng Tang script_browse(script_opt); 1726cdbab7c2SFeng Tang } 1727341487abSFeng Tang /* Switch to another data file */ 1728341487abSFeng Tang else if (choice == switch_data) { 1729341487abSFeng Tang do_data_switch: 1730341487abSFeng Tang if (!switch_data_file()) { 1731341487abSFeng Tang key = K_SWITCH_INPUT_DATA; 1732341487abSFeng Tang break; 1733341487abSFeng Tang } else 1734341487abSFeng Tang ui__warning("Won't switch the data files due to\n" 1735341487abSFeng Tang "no valid data file get selected!\n"); 1736341487abSFeng Tang } 1737aca7a94dSNamhyung Kim } 1738aca7a94dSNamhyung Kim out_free_stack: 1739aca7a94dSNamhyung Kim pstack__delete(fstack); 1740aca7a94dSNamhyung Kim out: 1741aca7a94dSNamhyung Kim hist_browser__delete(browser); 1742aca7a94dSNamhyung Kim free_popup_options(options, nr_options - 1); 1743aca7a94dSNamhyung Kim return key; 1744aca7a94dSNamhyung Kim } 1745aca7a94dSNamhyung Kim 1746aca7a94dSNamhyung Kim struct perf_evsel_menu { 1747aca7a94dSNamhyung Kim struct ui_browser b; 1748aca7a94dSNamhyung Kim struct perf_evsel *selection; 1749aca7a94dSNamhyung Kim bool lost_events, lost_events_warned; 1750064f1981SNamhyung Kim float min_pcnt; 175168d80758SNamhyung Kim struct perf_session_env *env; 1752aca7a94dSNamhyung Kim }; 1753aca7a94dSNamhyung Kim 1754aca7a94dSNamhyung Kim static void perf_evsel_menu__write(struct ui_browser *browser, 1755aca7a94dSNamhyung Kim void *entry, int row) 1756aca7a94dSNamhyung Kim { 1757aca7a94dSNamhyung Kim struct perf_evsel_menu *menu = container_of(browser, 1758aca7a94dSNamhyung Kim struct perf_evsel_menu, b); 1759aca7a94dSNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1760aca7a94dSNamhyung Kim bool current_entry = ui_browser__is_current_entry(browser, row); 1761aca7a94dSNamhyung Kim unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 17627289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(evsel); 1763aca7a94dSNamhyung Kim char bf[256], unit; 1764aca7a94dSNamhyung Kim const char *warn = " "; 1765aca7a94dSNamhyung Kim size_t printed; 1766aca7a94dSNamhyung Kim 1767aca7a94dSNamhyung Kim ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1768aca7a94dSNamhyung Kim HE_COLORSET_NORMAL); 1769aca7a94dSNamhyung Kim 1770759ff497SNamhyung Kim if (perf_evsel__is_group_event(evsel)) { 1771717e263fSNamhyung Kim struct perf_evsel *pos; 1772717e263fSNamhyung Kim 1773717e263fSNamhyung Kim ev_name = perf_evsel__group_name(evsel); 1774717e263fSNamhyung Kim 1775717e263fSNamhyung Kim for_each_group_member(pos, evsel) { 1776717e263fSNamhyung Kim nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1777717e263fSNamhyung Kim } 1778717e263fSNamhyung Kim } 1779717e263fSNamhyung Kim 1780aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 1781aca7a94dSNamhyung Kim printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1782aca7a94dSNamhyung Kim unit, unit == ' ' ? "" : " ", ev_name); 1783aca7a94dSNamhyung Kim slsmg_printf("%s", bf); 1784aca7a94dSNamhyung Kim 1785aca7a94dSNamhyung Kim nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 1786aca7a94dSNamhyung Kim if (nr_events != 0) { 1787aca7a94dSNamhyung Kim menu->lost_events = true; 1788aca7a94dSNamhyung Kim if (!current_entry) 1789aca7a94dSNamhyung Kim ui_browser__set_color(browser, HE_COLORSET_TOP); 1790aca7a94dSNamhyung Kim nr_events = convert_unit(nr_events, &unit); 1791aca7a94dSNamhyung Kim printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", 1792aca7a94dSNamhyung Kim nr_events, unit, unit == ' ' ? "" : " "); 1793aca7a94dSNamhyung Kim warn = bf; 1794aca7a94dSNamhyung Kim } 1795aca7a94dSNamhyung Kim 1796aca7a94dSNamhyung Kim slsmg_write_nstring(warn, browser->width - printed); 1797aca7a94dSNamhyung Kim 1798aca7a94dSNamhyung Kim if (current_entry) 1799aca7a94dSNamhyung Kim menu->selection = evsel; 1800aca7a94dSNamhyung Kim } 1801aca7a94dSNamhyung Kim 1802aca7a94dSNamhyung Kim static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 1803aca7a94dSNamhyung Kim int nr_events, const char *help, 18049783adf7SNamhyung Kim struct hist_browser_timer *hbt) 1805aca7a94dSNamhyung Kim { 1806aca7a94dSNamhyung Kim struct perf_evlist *evlist = menu->b.priv; 1807aca7a94dSNamhyung Kim struct perf_evsel *pos; 1808aca7a94dSNamhyung Kim const char *ev_name, *title = "Available samples"; 18099783adf7SNamhyung Kim int delay_secs = hbt ? hbt->refresh : 0; 1810aca7a94dSNamhyung Kim int key; 1811aca7a94dSNamhyung Kim 1812aca7a94dSNamhyung Kim if (ui_browser__show(&menu->b, title, 1813aca7a94dSNamhyung Kim "ESC: exit, ENTER|->: Browse histograms") < 0) 1814aca7a94dSNamhyung Kim return -1; 1815aca7a94dSNamhyung Kim 1816aca7a94dSNamhyung Kim while (1) { 1817aca7a94dSNamhyung Kim key = ui_browser__run(&menu->b, delay_secs); 1818aca7a94dSNamhyung Kim 1819aca7a94dSNamhyung Kim switch (key) { 1820aca7a94dSNamhyung Kim case K_TIMER: 18219783adf7SNamhyung Kim hbt->timer(hbt->arg); 1822aca7a94dSNamhyung Kim 1823aca7a94dSNamhyung Kim if (!menu->lost_events_warned && menu->lost_events) { 1824aca7a94dSNamhyung Kim ui_browser__warn_lost_events(&menu->b); 1825aca7a94dSNamhyung Kim menu->lost_events_warned = true; 1826aca7a94dSNamhyung Kim } 1827aca7a94dSNamhyung Kim continue; 1828aca7a94dSNamhyung Kim case K_RIGHT: 1829aca7a94dSNamhyung Kim case K_ENTER: 1830aca7a94dSNamhyung Kim if (!menu->selection) 1831aca7a94dSNamhyung Kim continue; 1832aca7a94dSNamhyung Kim pos = menu->selection; 1833aca7a94dSNamhyung Kim browse_hists: 1834aca7a94dSNamhyung Kim perf_evlist__set_selected(evlist, pos); 1835aca7a94dSNamhyung Kim /* 1836aca7a94dSNamhyung Kim * Give the calling tool a chance to populate the non 1837aca7a94dSNamhyung Kim * default evsel resorted hists tree. 1838aca7a94dSNamhyung Kim */ 18399783adf7SNamhyung Kim if (hbt) 18409783adf7SNamhyung Kim hbt->timer(hbt->arg); 18417289f83cSArnaldo Carvalho de Melo ev_name = perf_evsel__name(pos); 1842aca7a94dSNamhyung Kim key = perf_evsel__hists_browse(pos, nr_events, help, 184368d80758SNamhyung Kim ev_name, true, hbt, 1844064f1981SNamhyung Kim menu->min_pcnt, 184568d80758SNamhyung Kim menu->env); 1846aca7a94dSNamhyung Kim ui_browser__show_title(&menu->b, title); 1847aca7a94dSNamhyung Kim switch (key) { 1848aca7a94dSNamhyung Kim case K_TAB: 1849aca7a94dSNamhyung Kim if (pos->node.next == &evlist->entries) 1850aca7a94dSNamhyung Kim pos = list_entry(evlist->entries.next, struct perf_evsel, node); 1851aca7a94dSNamhyung Kim else 1852aca7a94dSNamhyung Kim pos = list_entry(pos->node.next, struct perf_evsel, node); 1853aca7a94dSNamhyung Kim goto browse_hists; 1854aca7a94dSNamhyung Kim case K_UNTAB: 1855aca7a94dSNamhyung Kim if (pos->node.prev == &evlist->entries) 1856aca7a94dSNamhyung Kim pos = list_entry(evlist->entries.prev, struct perf_evsel, node); 1857aca7a94dSNamhyung Kim else 1858aca7a94dSNamhyung Kim pos = list_entry(pos->node.prev, struct perf_evsel, node); 1859aca7a94dSNamhyung Kim goto browse_hists; 1860aca7a94dSNamhyung Kim case K_ESC: 1861aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 1862aca7a94dSNamhyung Kim "Do you really want to exit?")) 1863aca7a94dSNamhyung Kim continue; 1864aca7a94dSNamhyung Kim /* Fall thru */ 1865341487abSFeng Tang case K_SWITCH_INPUT_DATA: 1866aca7a94dSNamhyung Kim case 'q': 1867aca7a94dSNamhyung Kim case CTRL('c'): 1868aca7a94dSNamhyung Kim goto out; 1869aca7a94dSNamhyung Kim default: 1870aca7a94dSNamhyung Kim continue; 1871aca7a94dSNamhyung Kim } 1872aca7a94dSNamhyung Kim case K_LEFT: 1873aca7a94dSNamhyung Kim continue; 1874aca7a94dSNamhyung Kim case K_ESC: 1875aca7a94dSNamhyung Kim if (!ui_browser__dialog_yesno(&menu->b, 1876aca7a94dSNamhyung Kim "Do you really want to exit?")) 1877aca7a94dSNamhyung Kim continue; 1878aca7a94dSNamhyung Kim /* Fall thru */ 1879aca7a94dSNamhyung Kim case 'q': 1880aca7a94dSNamhyung Kim case CTRL('c'): 1881aca7a94dSNamhyung Kim goto out; 1882aca7a94dSNamhyung Kim default: 1883aca7a94dSNamhyung Kim continue; 1884aca7a94dSNamhyung Kim } 1885aca7a94dSNamhyung Kim } 1886aca7a94dSNamhyung Kim 1887aca7a94dSNamhyung Kim out: 1888aca7a94dSNamhyung Kim ui_browser__hide(&menu->b); 1889aca7a94dSNamhyung Kim return key; 1890aca7a94dSNamhyung Kim } 1891aca7a94dSNamhyung Kim 1892*316c7136SArnaldo Carvalho de Melo static bool filter_group_entries(struct ui_browser *browser __maybe_unused, 1893fc24d7c2SNamhyung Kim void *entry) 1894fc24d7c2SNamhyung Kim { 1895fc24d7c2SNamhyung Kim struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1896fc24d7c2SNamhyung Kim 1897fc24d7c2SNamhyung Kim if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) 1898fc24d7c2SNamhyung Kim return true; 1899fc24d7c2SNamhyung Kim 1900fc24d7c2SNamhyung Kim return false; 1901fc24d7c2SNamhyung Kim } 1902fc24d7c2SNamhyung Kim 1903aca7a94dSNamhyung Kim static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1904fc24d7c2SNamhyung Kim int nr_entries, const char *help, 190568d80758SNamhyung Kim struct hist_browser_timer *hbt, 1906064f1981SNamhyung Kim float min_pcnt, 190768d80758SNamhyung Kim struct perf_session_env *env) 1908aca7a94dSNamhyung Kim { 1909aca7a94dSNamhyung Kim struct perf_evsel *pos; 1910aca7a94dSNamhyung Kim struct perf_evsel_menu menu = { 1911aca7a94dSNamhyung Kim .b = { 1912aca7a94dSNamhyung Kim .entries = &evlist->entries, 1913aca7a94dSNamhyung Kim .refresh = ui_browser__list_head_refresh, 1914aca7a94dSNamhyung Kim .seek = ui_browser__list_head_seek, 1915aca7a94dSNamhyung Kim .write = perf_evsel_menu__write, 1916fc24d7c2SNamhyung Kim .filter = filter_group_entries, 1917fc24d7c2SNamhyung Kim .nr_entries = nr_entries, 1918aca7a94dSNamhyung Kim .priv = evlist, 1919aca7a94dSNamhyung Kim }, 1920064f1981SNamhyung Kim .min_pcnt = min_pcnt, 192168d80758SNamhyung Kim .env = env, 1922aca7a94dSNamhyung Kim }; 1923aca7a94dSNamhyung Kim 1924aca7a94dSNamhyung Kim ui_helpline__push("Press ESC to exit"); 1925aca7a94dSNamhyung Kim 1926aca7a94dSNamhyung Kim list_for_each_entry(pos, &evlist->entries, node) { 19277289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(pos); 1928aca7a94dSNamhyung Kim size_t line_len = strlen(ev_name) + 7; 1929aca7a94dSNamhyung Kim 1930aca7a94dSNamhyung Kim if (menu.b.width < line_len) 1931aca7a94dSNamhyung Kim menu.b.width = line_len; 1932aca7a94dSNamhyung Kim } 1933aca7a94dSNamhyung Kim 1934fc24d7c2SNamhyung Kim return perf_evsel_menu__run(&menu, nr_entries, help, hbt); 1935aca7a94dSNamhyung Kim } 1936aca7a94dSNamhyung Kim 1937aca7a94dSNamhyung Kim int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 193868d80758SNamhyung Kim struct hist_browser_timer *hbt, 1939064f1981SNamhyung Kim float min_pcnt, 194068d80758SNamhyung Kim struct perf_session_env *env) 1941aca7a94dSNamhyung Kim { 1942fc24d7c2SNamhyung Kim int nr_entries = evlist->nr_entries; 1943fc24d7c2SNamhyung Kim 1944fc24d7c2SNamhyung Kim single_entry: 1945fc24d7c2SNamhyung Kim if (nr_entries == 1) { 1946aca7a94dSNamhyung Kim struct perf_evsel *first = list_entry(evlist->entries.next, 1947aca7a94dSNamhyung Kim struct perf_evsel, node); 19487289f83cSArnaldo Carvalho de Melo const char *ev_name = perf_evsel__name(first); 1949fc24d7c2SNamhyung Kim 1950fc24d7c2SNamhyung Kim return perf_evsel__hists_browse(first, nr_entries, help, 1951064f1981SNamhyung Kim ev_name, false, hbt, min_pcnt, 1952064f1981SNamhyung Kim env); 1953aca7a94dSNamhyung Kim } 1954aca7a94dSNamhyung Kim 1955fc24d7c2SNamhyung Kim if (symbol_conf.event_group) { 1956fc24d7c2SNamhyung Kim struct perf_evsel *pos; 1957fc24d7c2SNamhyung Kim 1958fc24d7c2SNamhyung Kim nr_entries = 0; 1959fc24d7c2SNamhyung Kim list_for_each_entry(pos, &evlist->entries, node) 1960fc24d7c2SNamhyung Kim if (perf_evsel__is_group_leader(pos)) 1961fc24d7c2SNamhyung Kim nr_entries++; 1962fc24d7c2SNamhyung Kim 1963fc24d7c2SNamhyung Kim if (nr_entries == 1) 1964fc24d7c2SNamhyung Kim goto single_entry; 1965fc24d7c2SNamhyung Kim } 1966fc24d7c2SNamhyung Kim 1967fc24d7c2SNamhyung Kim return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, 1968064f1981SNamhyung Kim hbt, min_pcnt, env); 1969aca7a94dSNamhyung Kim } 1970