projects/linux·blob master · refs

209 lines · 5.6 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * C2C function browser - TUI front end for function-level sharing analysis
4 */
5
6#include <errno.h>
7#include <inttypes.h>
8#include <stdlib.h>
9#include <sys/ttydefaults.h>
10#include <linux/rbtree.h>
11#include <linux/zalloc.h>
12
13#include "../browser.h"
14#include "../keysyms.h"
15#include "../libslang.h"
16#include "../ui.h"
17#include "../../util/c2c.h"
18#include "../../util/debug.h"
19#include "../../util/hist.h"
20#include "../../util/symbol.h"
21#include "hists.h"
22
23struct c2c_function_browser {
24 struct hist_browser hb;
25 unsigned int (*orig_refresh)(struct ui_browser *browser);
26 int (*browse_cacheline)(struct hist_entry *he);
27};
28
29/*
30 * Count visible entries in @root, descending only through visible, unfolded
31 * parents. Match hists__filter_entries(), which drives generic browser
32 * navigation, so the count cannot include rows the browser skips.
33 */
34static u64
35c2c_function__nr_visible_rows(struct rb_root_cached *root, float min_pcnt)
36{
37 struct rb_node *nd;
38 u64 rows = 0;
39
40 for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
41 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
42
43 /*
44 * The generic refresh folds filtered parents and therefore hides
45 * their subtree. A percentage-rejected parent is merely skipped;
46 * if it is unfolded, qualifying descendants are still rendered.
47 */
48 if (he->filtered)
49 continue;
50
51 if (hist_entry__get_percent_limit(he) >= min_pcnt)
52 rows++;
53 if (he->has_children && he->unfolded)
54 rows += c2c_function__nr_visible_rows(&he->hroot_out,
55 min_pcnt);
56 }
57 return rows;
58}
59
60static void
61c2c_function_browser__update_nr_entries(struct c2c_function_browser *browser)
62{
63 u64 nr_entries;
64
65 nr_entries = c2c_function__nr_visible_rows(&browser->hb.hists->entries,
66 browser->hb.min_pcnt);
67 browser->hb.nr_non_filtered_entries = nr_entries;
68 browser->hb.b.nr_entries = nr_entries;
69}
70
71static unsigned int c2c_function_browser__refresh(struct ui_browser *ui_browser)
72{
73 struct hist_browser *hist_browser = container_of(ui_browser, struct hist_browser, b);
74 struct c2c_function_browser *browser;
75
76 browser = container_of(hist_browser, struct c2c_function_browser, hb);
77 c2c_function_browser__update_nr_entries(browser);
78 return browser->orig_refresh(ui_browser);
79}
80
81static int c2c_function_browser__title(struct hist_browser *browser,
82 char *bf, size_t size)
83{
84 scnprintf(bf, size,
85 "Shared Data Functions Table (%" PRIu64 " entries, sorted on Cycles %%)",
86 browser->hists->nr_non_filtered_entries);
87 return 0;
88}
89
90static struct c2c_function_browser *
91c2c_function_browser__new(struct hists *hists,
92 int (*browse_cacheline)(struct hist_entry *he))
93{
94 struct c2c_function_browser *browser;
95
96 if (!hists)
97 return NULL;
98
99 browser = zalloc(sizeof(*browser));
100 if (!browser)
101 return NULL;
102
103 hist_browser__init(&browser->hb, hists);
104 browser->orig_refresh = browser->hb.b.refresh;
105 browser->hb.b.refresh = c2c_function_browser__refresh;
106 browser->browse_cacheline = browse_cacheline;
107
108 browser->hb.title = c2c_function_browser__title;
109 browser->hb.c2c_filter = true;
110 browser->hb.show_headers = true;
111 /* Keep title line count consistent with forcing headers on. */
112 browser->hb.b.extra_title_lines = hists->hpp_list->nr_header_lines;
113 browser->hb.min_pcnt = 0.0;
114
115 return browser;
116}
117
118static void c2c_function_browser__delete(struct c2c_function_browser *browser)
119{
120 free(browser);
121}
122
123static int
124c2c_browser__browse_cacheline(struct c2c_function_browser *browser,
125 struct hist_entry *he_selection)
126{
127 struct hist_entry *he = c2c_function__find_cacheline(he_selection);
128
129 return he ? browser->browse_cacheline(he) : -1;
130}
131
132int perf_c2c__browse_function_view(struct c2c_function_view_args *args)
133{
134 struct c2c_function_browser *browser;
135 struct hists *hists;
136 bool saved_use_callchain = symbol_conf.use_callchain;
137 int key, ret;
138 static const char help[] =
139 " d Display details for the selected level-3 cacheline\n"
140 " e/+ Expand/collapse the selected entry\n"
141 " TAB/ESC/q/^C Return to the cacheline view\n";
142
143 if (!args || !args->cl_hists || !args->browse_cacheline)
144 return -EINVAL;
145
146 /*
147 * Function view does not display callchains; cacheline detail temporarily
148 * restores them.
149 */
150 symbol_conf.use_callchain = false;
151
152 ret = c2c_function__build(args->cl_hists, args->cl_sort,
153 args->symbol_full, &hists);
154 if (ret) {
155 if (ret == -EOPNOTSUPP)
156 ui__warning("The function view requires iaddr in --coalesce.\n");
157 else
158 ui__error("Failed to build function view hierarchy (ret=%d)\n", ret);
159 goto out;
160 }
161
162 browser = c2c_function_browser__new(hists, args->browse_cacheline);
163 if (!browser) {
164 ret = -ENOMEM;
165 goto out_reset;
166 }
167
168 /* Reset abort key so we can receive Ctrl-C as a key. */
169 SLang_reset_tty();
170 SLang_init_tty(0, 0, 0);
171 SLtty_set_suspend_state(true);
172
173 while (1) {
174 c2c_function_browser__update_nr_entries(browser);
175 key = hist_browser__run(&browser->hb, "? - help", true, 0);
176
177 switch (key) {
178 case 'q':
179 case K_TAB:
180 case K_ESC:
181 case CTRL('c'):
182 goto browser_done;
183 case 'd':
184 /* Cacheline detail honors the user's callchain setting. */
185 symbol_conf.use_callchain = saved_use_callchain;
186 c2c_browser__browse_cacheline(browser, browser->hb.he_selection);
187 /*
188 * Preserve any toggle made in the detail view, then
189 * re-disable callchain for the function view.
190 */
191 saved_use_callchain = symbol_conf.use_callchain;
192 symbol_conf.use_callchain = false;
193 break;
194 case '?':
195 ui_browser__help_window(&browser->hb.b, help);
196 break;
197 default:
198 break;
199 }
200 }
201
202browser_done:
203 c2c_function_browser__delete(browser);
204out_reset:
205 c2c_function__reset();
206out:
207 symbol_conf.use_callchain = saved_use_callchain;
208 return ret;
209}