Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210// SPDX-License-Identifier: GPL-2.0/* * C2C function browser - TUI front end for function-level sharing analysis */
#include <errno.h>#include <inttypes.h>#include <stdlib.h>#include <sys/ttydefaults.h>#include <linux/rbtree.h>#include <linux/zalloc.h>
#include "../browser.h"#include "../keysyms.h"#include "../libslang.h"#include "../ui.h"#include "../../util/c2c.h"#include "../../util/debug.h"#include "../../util/hist.h"#include "../../util/symbol.h"#include "hists.h"
struct c2c_function_browser { struct hist_browser hb; unsigned int (*orig_refresh)(struct ui_browser *browser); int (*browse_cacheline)(struct hist_entry *he);};
/* * Count visible entries in @root, descending only through visible, unfolded * parents. Match hists__filter_entries(), which drives generic browser * navigation, so the count cannot include rows the browser skips. */static u64c2c_function__nr_visible_rows(struct rb_root_cached *root, float min_pcnt){ struct rb_node *nd; u64 rows = 0;
for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
/* * The generic refresh folds filtered parents and therefore hides * their subtree. A percentage-rejected parent is merely skipped; * if it is unfolded, qualifying descendants are still rendered. */ if (he->filtered) continue;
if (hist_entry__get_percent_limit(he) >= min_pcnt) rows++; if (he->has_children && he->unfolded) rows += c2c_function__nr_visible_rows(&he->hroot_out, min_pcnt); } return rows;}
static voidc2c_function_browser__update_nr_entries(struct c2c_function_browser *browser){ u64 nr_entries;
nr_entries = c2c_function__nr_visible_rows(&browser->hb.hists->entries, browser->hb.min_pcnt); browser->hb.nr_non_filtered_entries = nr_entries; browser->hb.b.nr_entries = nr_entries;}
static unsigned int c2c_function_browser__refresh(struct ui_browser *ui_browser){ struct hist_browser *hist_browser = container_of(ui_browser, struct hist_browser, b); struct c2c_function_browser *browser;
browser = container_of(hist_browser, struct c2c_function_browser, hb); c2c_function_browser__update_nr_entries(browser); return browser->orig_refresh(ui_browser);}
static int c2c_function_browser__title(struct hist_browser *browser, char *bf, size_t size){ scnprintf(bf, size, "Shared Data Functions Table (%" PRIu64 " entries, sorted on Cycles %%)", browser->hists->nr_non_filtered_entries); return 0;}
static struct c2c_function_browser *c2c_function_browser__new(struct hists *hists, int (*browse_cacheline)(struct hist_entry *he)){ struct c2c_function_browser *browser;
if (!hists) return NULL;
browser = zalloc(sizeof(*browser)); if (!browser) return NULL;
hist_browser__init(&browser->hb, hists); browser->orig_refresh = browser->hb.b.refresh; browser->hb.b.refresh = c2c_function_browser__refresh; browser->browse_cacheline = browse_cacheline;
browser->hb.title = c2c_function_browser__title; browser->hb.c2c_filter = true; browser->hb.show_headers = true; /* Keep title line count consistent with forcing headers on. */ browser->hb.b.extra_title_lines = hists->hpp_list->nr_header_lines; browser->hb.min_pcnt = 0.0;
return browser;}
static void c2c_function_browser__delete(struct c2c_function_browser *browser){ free(browser);}
static intc2c_browser__browse_cacheline(struct c2c_function_browser *browser, struct hist_entry *he_selection){ struct hist_entry *he = c2c_function__find_cacheline(he_selection);
return he ? browser->browse_cacheline(he) : -1;}
int perf_c2c__browse_function_view(struct c2c_function_view_args *args){ struct c2c_function_browser *browser; struct hists *hists; bool saved_use_callchain = symbol_conf.use_callchain; int key, ret; static const char help[] = " d Display details for the selected level-3 cacheline\n" " e/+ Expand/collapse the selected entry\n" " TAB/ESC/q/^C Return to the cacheline view\n";
if (!args || !args->cl_hists || !args->browse_cacheline) return -EINVAL;
/* * Function view does not display callchains; cacheline detail temporarily * restores them. */ symbol_conf.use_callchain = false;
ret = c2c_function__build(args->cl_hists, args->cl_sort, args->symbol_full, &hists); if (ret) { if (ret == -EOPNOTSUPP) ui__warning("The function view requires iaddr in --coalesce.\n"); else ui__error("Failed to build function view hierarchy (ret=%d)\n", ret); goto out; }
browser = c2c_function_browser__new(hists, args->browse_cacheline); if (!browser) { ret = -ENOMEM; goto out_reset; }
/* Reset abort key so we can receive Ctrl-C as a key. */ SLang_reset_tty(); SLang_init_tty(0, 0, 0); SLtty_set_suspend_state(true);
while (1) { c2c_function_browser__update_nr_entries(browser); key = hist_browser__run(&browser->hb, "? - help", true, 0);
switch (key) { case 'q': case K_TAB: case K_ESC: case CTRL('c'): goto browser_done; case 'd': /* Cacheline detail honors the user's callchain setting. */ symbol_conf.use_callchain = saved_use_callchain; c2c_browser__browse_cacheline(browser, browser->hb.he_selection); /* * Preserve any toggle made in the detail view, then * re-disable callchain for the function view. */ saved_use_callchain = symbol_conf.use_callchain; symbol_conf.use_callchain = false; break; case '?': ui_browser__help_window(&browser->hb.b, help); break; default: break; } }
browser_done: c2c_function_browser__delete(browser);out_reset: c2c_function__reset();out: symbol_conf.use_callchain = saved_use_callchain; return ret;}