Commit | Line | Data |
---|---|---|
ea251d51 | 1 | #include <math.h> |
2c5d4b4a | 2 | #include <linux/compiler.h> |
ea251d51 NK |
3 | |
4 | #include "../util/hist.h" | |
5 | #include "../util/util.h" | |
6 | #include "../util/sort.h" | |
4fb71074 | 7 | #include "../util/evsel.h" |
ea251d51 NK |
8 | |
9 | /* hist period print (hpp) functions */ | |
ea251d51 | 10 | |
4fb71074 | 11 | typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); |
ea251d51 | 12 | |
0c5268bf JO |
13 | static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, |
14 | u64 (*get_field)(struct hist_entry *), | |
15 | const char *fmt, hpp_snprint_fn print_fn, | |
16 | bool fmt_percent) | |
ea251d51 | 17 | { |
4fb71074 | 18 | int ret; |
b5ff71c3 | 19 | struct hists *hists = he->hists; |
759ff497 | 20 | struct perf_evsel *evsel = hists_to_evsel(hists); |
ea251d51 | 21 | |
0c5268bf JO |
22 | if (fmt_percent) { |
23 | double percent = 0.0; | |
9ffad987 | 24 | |
0c5268bf JO |
25 | if (hists->stats.total_period) |
26 | percent = 100.0 * get_field(he) / | |
27 | hists->stats.total_period; | |
28 | ||
29 | ret = print_fn(hpp->buf, hpp->size, fmt, percent); | |
30 | } else | |
31 | ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); | |
5b9e2146 | 32 | |
759ff497 | 33 | if (perf_evsel__is_group_event(evsel)) { |
5b9e2146 | 34 | int prev_idx, idx_delta; |
5b9e2146 NK |
35 | struct hist_entry *pair; |
36 | int nr_members = evsel->nr_members; | |
37 | ||
5b9e2146 NK |
38 | prev_idx = perf_evsel__group_idx(evsel); |
39 | ||
40 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { | |
41 | u64 period = get_field(pair); | |
42 | u64 total = pair->hists->stats.total_period; | |
43 | ||
44 | if (!total) | |
45 | continue; | |
46 | ||
47 | evsel = hists_to_evsel(pair->hists); | |
48 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; | |
49 | ||
50 | while (idx_delta--) { | |
51 | /* | |
52 | * zero-fill group members in the middle which | |
53 | * have no sample | |
54 | */ | |
55 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | |
0c5268bf | 56 | fmt, 0); |
5b9e2146 NK |
57 | } |
58 | ||
0c5268bf JO |
59 | if (fmt_percent) |
60 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | |
61 | fmt, 100.0 * period / total); | |
62 | else | |
63 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | |
64 | fmt, period); | |
5b9e2146 NK |
65 | |
66 | prev_idx = perf_evsel__group_idx(evsel); | |
67 | } | |
68 | ||
69 | idx_delta = nr_members - prev_idx - 1; | |
70 | ||
71 | while (idx_delta--) { | |
72 | /* | |
73 | * zero-fill group members at last which have no sample | |
74 | */ | |
75 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | |
0c5268bf | 76 | fmt, 0); |
5b9e2146 NK |
77 | } |
78 | } | |
4fb71074 | 79 | return ret; |
ea251d51 NK |
80 | } |
81 | ||
4fb71074 | 82 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ |
2c5d4b4a JO |
83 | static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
84 | struct perf_hpp *hpp) \ | |
4fb71074 NK |
85 | { \ |
86 | int len = _min_width; \ | |
87 | \ | |
5b9e2146 NK |
88 | if (symbol_conf.event_group) { \ |
89 | struct perf_evsel *evsel = hpp->ptr; \ | |
90 | \ | |
91 | len = max(len, evsel->nr_members * _unit_width); \ | |
92 | } \ | |
4fb71074 | 93 | return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ |
ea251d51 NK |
94 | } |
95 | ||
4fb71074 | 96 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ |
2c5d4b4a JO |
97 | static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
98 | struct perf_hpp *hpp __maybe_unused) \ | |
4fb71074 NK |
99 | { \ |
100 | int len = _min_width; \ | |
101 | \ | |
5b9e2146 NK |
102 | if (symbol_conf.event_group) { \ |
103 | struct perf_evsel *evsel = hpp->ptr; \ | |
104 | \ | |
105 | len = max(len, evsel->nr_members * _unit_width); \ | |
106 | } \ | |
4fb71074 | 107 | return len; \ |
ea251d51 NK |
108 | } |
109 | ||
4fb71074 NK |
110 | #define __HPP_COLOR_PERCENT_FN(_type, _field) \ |
111 | static u64 he_get_##_field(struct hist_entry *he) \ | |
112 | { \ | |
113 | return he->stat._field; \ | |
114 | } \ | |
115 | \ | |
2c5d4b4a JO |
116 | static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
117 | struct perf_hpp *hpp, struct hist_entry *he) \ | |
4fb71074 | 118 | { \ |
0c5268bf | 119 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ |
53805eca | 120 | percent_color_snprintf, true); \ |
ea251d51 NK |
121 | } |
122 | ||
4fb71074 | 123 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ |
2c5d4b4a JO |
124 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ |
125 | struct perf_hpp *hpp, struct hist_entry *he) \ | |
4fb71074 NK |
126 | { \ |
127 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | |
0c5268bf JO |
128 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ |
129 | scnprintf, true); \ | |
ea251d51 NK |
130 | } |
131 | ||
4fb71074 NK |
132 | #define __HPP_ENTRY_RAW_FN(_type, _field) \ |
133 | static u64 he_get_raw_##_field(struct hist_entry *he) \ | |
134 | { \ | |
135 | return he->stat._field; \ | |
136 | } \ | |
137 | \ | |
2c5d4b4a JO |
138 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ |
139 | struct perf_hpp *hpp, struct hist_entry *he) \ | |
4fb71074 NK |
140 | { \ |
141 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ | |
0c5268bf | 142 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ |
ea251d51 NK |
143 | } |
144 | ||
4fb71074 NK |
145 | #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ |
146 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | |
147 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | |
148 | __HPP_COLOR_PERCENT_FN(_type, _field) \ | |
149 | __HPP_ENTRY_PERCENT_FN(_type, _field) | |
ea251d51 | 150 | |
4fb71074 NK |
151 | #define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ |
152 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | |
153 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | |
154 | __HPP_ENTRY_RAW_FN(_type, _field) | |
ea251d51 | 155 | |
b5ff71c3 | 156 | |
4fb71074 NK |
157 | HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) |
158 | HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) | |
159 | HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) | |
160 | HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) | |
161 | HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) | |
ea251d51 | 162 | |
4fb71074 NK |
163 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) |
164 | HPP_RAW_FNS(period, "Period", period, 12, 12) | |
9ffad987 | 165 | |
1240005e JO |
166 | #define HPP__COLOR_PRINT_FNS(_name) \ |
167 | { \ | |
168 | .header = hpp__header_ ## _name, \ | |
169 | .width = hpp__width_ ## _name, \ | |
170 | .color = hpp__color_ ## _name, \ | |
171 | .entry = hpp__entry_ ## _name \ | |
172 | } | |
ea251d51 | 173 | |
1240005e JO |
174 | #define HPP__PRINT_FNS(_name) \ |
175 | { \ | |
176 | .header = hpp__header_ ## _name, \ | |
177 | .width = hpp__width_ ## _name, \ | |
178 | .entry = hpp__entry_ ## _name \ | |
179 | } | |
ea251d51 NK |
180 | |
181 | struct perf_hpp_fmt perf_hpp__format[] = { | |
1240005e JO |
182 | HPP__COLOR_PRINT_FNS(overhead), |
183 | HPP__COLOR_PRINT_FNS(overhead_sys), | |
184 | HPP__COLOR_PRINT_FNS(overhead_us), | |
185 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), | |
186 | HPP__COLOR_PRINT_FNS(overhead_guest_us), | |
187 | HPP__PRINT_FNS(samples), | |
345dc0b4 | 188 | HPP__PRINT_FNS(period) |
ea251d51 NK |
189 | }; |
190 | ||
1240005e JO |
191 | LIST_HEAD(perf_hpp__list); |
192 | ||
4fb71074 | 193 | |
ea251d51 NK |
194 | #undef HPP__COLOR_PRINT_FNS |
195 | #undef HPP__PRINT_FNS | |
196 | ||
4fb71074 NK |
197 | #undef HPP_PERCENT_FNS |
198 | #undef HPP_RAW_FNS | |
199 | ||
200 | #undef __HPP_HEADER_FN | |
201 | #undef __HPP_WIDTH_FN | |
202 | #undef __HPP_COLOR_PERCENT_FN | |
203 | #undef __HPP_ENTRY_PERCENT_FN | |
204 | #undef __HPP_ENTRY_RAW_FN | |
205 | ||
206 | ||
1d77822e | 207 | void perf_hpp__init(void) |
ea251d51 | 208 | { |
2b8bfa6b JO |
209 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); |
210 | ||
ea251d51 | 211 | if (symbol_conf.show_cpu_utilization) { |
1240005e JO |
212 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); |
213 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); | |
ea251d51 NK |
214 | |
215 | if (perf_guest) { | |
1240005e JO |
216 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS); |
217 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US); | |
ea251d51 NK |
218 | } |
219 | } | |
220 | ||
221 | if (symbol_conf.show_nr_samples) | |
1240005e | 222 | perf_hpp__column_enable(PERF_HPP__SAMPLES); |
ea251d51 NK |
223 | |
224 | if (symbol_conf.show_total_period) | |
1240005e | 225 | perf_hpp__column_enable(PERF_HPP__PERIOD); |
1d77822e | 226 | } |
ea251d51 | 227 | |
1240005e JO |
228 | void perf_hpp__column_register(struct perf_hpp_fmt *format) |
229 | { | |
230 | list_add_tail(&format->list, &perf_hpp__list); | |
231 | } | |
232 | ||
233 | void perf_hpp__column_enable(unsigned col) | |
1d77822e JO |
234 | { |
235 | BUG_ON(col >= PERF_HPP__MAX_INDEX); | |
1240005e | 236 | perf_hpp__column_register(&perf_hpp__format[col]); |
ea251d51 NK |
237 | } |
238 | ||
ea251d51 NK |
239 | int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, |
240 | struct hists *hists) | |
241 | { | |
242 | const char *sep = symbol_conf.field_sep; | |
243 | struct sort_entry *se; | |
244 | int ret = 0; | |
245 | ||
246 | list_for_each_entry(se, &hist_entry__sort_list, list) { | |
247 | if (se->elide) | |
248 | continue; | |
249 | ||
250 | ret += scnprintf(s + ret, size - ret, "%s", sep ?: " "); | |
251 | ret += se->se_snprintf(he, s + ret, size - ret, | |
252 | hists__col_len(hists, se->se_width_idx)); | |
253 | } | |
254 | ||
255 | return ret; | |
256 | } | |
7e62ef44 NK |
257 | |
258 | /* | |
259 | * See hists__fprintf to match the column widths | |
260 | */ | |
261 | unsigned int hists__sort_list_width(struct hists *hists) | |
262 | { | |
1240005e | 263 | struct perf_hpp_fmt *fmt; |
7e62ef44 | 264 | struct sort_entry *se; |
1240005e | 265 | int i = 0, ret = 0; |
5b9e2146 NK |
266 | struct perf_hpp dummy_hpp = { |
267 | .ptr = hists_to_evsel(hists), | |
268 | }; | |
7e62ef44 | 269 | |
1240005e | 270 | perf_hpp__for_each_format(fmt) { |
7e62ef44 NK |
271 | if (i) |
272 | ret += 2; | |
273 | ||
2c5d4b4a | 274 | ret += fmt->width(fmt, &dummy_hpp); |
7e62ef44 NK |
275 | } |
276 | ||
277 | list_for_each_entry(se, &hist_entry__sort_list, list) | |
278 | if (!se->elide) | |
279 | ret += 2 + hists__col_len(hists, se->se_width_idx); | |
280 | ||
281 | if (verbose) /* Addr + origin */ | |
282 | ret += 3 + BITS_PER_LONG / 4; | |
283 | ||
284 | return ret; | |
285 | } |