1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <inttypes.h> |
3 | #include <stdio.h> |
4 | #include <stdlib.h> |
5 | #include <stdbool.h> |
6 | #include <linux/kernel.h> |
7 | #include <linux/types.h> |
8 | #include <linux/perf_event.h> |
9 | #include "util/evsel_fprintf.h" |
10 | #include "trace-event.h" |
11 | |
12 | struct bit_names { |
13 | int bit; |
14 | const char *name; |
15 | }; |
16 | |
17 | static void __p_bits(char *buf, size_t size, u64 value, struct bit_names *bits) |
18 | { |
19 | bool first_bit = true; |
20 | int i = 0; |
21 | |
22 | do { |
23 | if (value & bits[i].bit) { |
24 | buf += scnprintf(buf, size, fmt: "%s%s" , first_bit ? "" : "|" , bits[i].name); |
25 | first_bit = false; |
26 | } |
27 | } while (bits[++i].name != NULL); |
28 | } |
29 | |
30 | static void __p_sample_type(char *buf, size_t size, u64 value) |
31 | { |
32 | #define bit_name(n) { PERF_SAMPLE_##n, #n } |
33 | struct bit_names bits[] = { |
34 | bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR), |
35 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), |
36 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), |
37 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), |
38 | bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC), |
39 | bit_name(WEIGHT), bit_name(PHYS_ADDR), bit_name(AUX), |
40 | bit_name(CGROUP), bit_name(DATA_PAGE_SIZE), bit_name(CODE_PAGE_SIZE), |
41 | bit_name(WEIGHT_STRUCT), |
42 | { .name = NULL, } |
43 | }; |
44 | #undef bit_name |
45 | __p_bits(buf, size, value, bits); |
46 | } |
47 | |
48 | static void __p_branch_sample_type(char *buf, size_t size, u64 value) |
49 | { |
50 | #define bit_name(n) { PERF_SAMPLE_BRANCH_##n, #n } |
51 | struct bit_names bits[] = { |
52 | bit_name(USER), bit_name(KERNEL), bit_name(HV), bit_name(ANY), |
53 | bit_name(ANY_CALL), bit_name(ANY_RETURN), bit_name(IND_CALL), |
54 | bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX), |
55 | bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP), |
56 | bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES), |
57 | bit_name(TYPE_SAVE), bit_name(HW_INDEX), bit_name(PRIV_SAVE), |
58 | bit_name(COUNTERS), |
59 | { .name = NULL, } |
60 | }; |
61 | #undef bit_name |
62 | __p_bits(buf, size, value, bits); |
63 | } |
64 | |
65 | static void __p_read_format(char *buf, size_t size, u64 value) |
66 | { |
67 | #define bit_name(n) { PERF_FORMAT_##n, #n } |
68 | struct bit_names bits[] = { |
69 | bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING), |
70 | bit_name(ID), bit_name(GROUP), bit_name(LOST), |
71 | { .name = NULL, } |
72 | }; |
73 | #undef bit_name |
74 | __p_bits(buf, size, value, bits); |
75 | } |
76 | |
77 | #define ENUM_ID_TO_STR_CASE(x) case x: return (#x); |
78 | static const char *stringify_perf_type_id(u64 value) |
79 | { |
80 | switch (value) { |
81 | ENUM_ID_TO_STR_CASE(PERF_TYPE_HARDWARE) |
82 | ENUM_ID_TO_STR_CASE(PERF_TYPE_SOFTWARE) |
83 | ENUM_ID_TO_STR_CASE(PERF_TYPE_TRACEPOINT) |
84 | ENUM_ID_TO_STR_CASE(PERF_TYPE_HW_CACHE) |
85 | ENUM_ID_TO_STR_CASE(PERF_TYPE_RAW) |
86 | ENUM_ID_TO_STR_CASE(PERF_TYPE_BREAKPOINT) |
87 | default: |
88 | return NULL; |
89 | } |
90 | } |
91 | |
92 | static const char *stringify_perf_hw_id(u64 value) |
93 | { |
94 | switch (value) { |
95 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CPU_CYCLES) |
96 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_INSTRUCTIONS) |
97 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_REFERENCES) |
98 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_MISSES) |
99 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_BRANCH_INSTRUCTIONS) |
100 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_BRANCH_MISSES) |
101 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_BUS_CYCLES) |
102 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_STALLED_CYCLES_FRONTEND) |
103 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_STALLED_CYCLES_BACKEND) |
104 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_REF_CPU_CYCLES) |
105 | default: |
106 | return NULL; |
107 | } |
108 | } |
109 | |
110 | static const char *stringify_perf_hw_cache_id(u64 value) |
111 | { |
112 | switch (value) { |
113 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_L1D) |
114 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_L1I) |
115 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_LL) |
116 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_DTLB) |
117 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_ITLB) |
118 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_BPU) |
119 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_NODE) |
120 | default: |
121 | return NULL; |
122 | } |
123 | } |
124 | |
125 | static const char *stringify_perf_hw_cache_op_id(u64 value) |
126 | { |
127 | switch (value) { |
128 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_OP_READ) |
129 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_OP_WRITE) |
130 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_OP_PREFETCH) |
131 | default: |
132 | return NULL; |
133 | } |
134 | } |
135 | |
136 | static const char *stringify_perf_hw_cache_op_result_id(u64 value) |
137 | { |
138 | switch (value) { |
139 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_RESULT_ACCESS) |
140 | ENUM_ID_TO_STR_CASE(PERF_COUNT_HW_CACHE_RESULT_MISS) |
141 | default: |
142 | return NULL; |
143 | } |
144 | } |
145 | |
146 | static const char *stringify_perf_sw_id(u64 value) |
147 | { |
148 | switch (value) { |
149 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_CPU_CLOCK) |
150 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_TASK_CLOCK) |
151 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_PAGE_FAULTS) |
152 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_CONTEXT_SWITCHES) |
153 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_CPU_MIGRATIONS) |
154 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_PAGE_FAULTS_MIN) |
155 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_PAGE_FAULTS_MAJ) |
156 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_ALIGNMENT_FAULTS) |
157 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_EMULATION_FAULTS) |
158 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_DUMMY) |
159 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_BPF_OUTPUT) |
160 | ENUM_ID_TO_STR_CASE(PERF_COUNT_SW_CGROUP_SWITCHES) |
161 | default: |
162 | return NULL; |
163 | } |
164 | } |
165 | #undef ENUM_ID_TO_STR_CASE |
166 | |
167 | #define PRINT_ID(_s, _f) \ |
168 | do { \ |
169 | const char *__s = _s; \ |
170 | if (__s == NULL) \ |
171 | snprintf(buf, size, _f, value); \ |
172 | else \ |
173 | snprintf(buf, size, _f" (%s)", value, __s); \ |
174 | } while (0) |
175 | #define print_id_unsigned(_s) PRINT_ID(_s, "%"PRIu64) |
176 | #define print_id_hex(_s) PRINT_ID(_s, "%#"PRIx64) |
177 | |
178 | static void __p_type_id(char *buf, size_t size, u64 value) |
179 | { |
180 | print_id_unsigned(stringify_perf_type_id(value)); |
181 | } |
182 | |
183 | static void __p_config_hw_id(char *buf, size_t size, u64 value) |
184 | { |
185 | print_id_hex(stringify_perf_hw_id(value)); |
186 | } |
187 | |
188 | static void __p_config_sw_id(char *buf, size_t size, u64 value) |
189 | { |
190 | print_id_hex(stringify_perf_sw_id(value)); |
191 | } |
192 | |
193 | static void __p_config_hw_cache_id(char *buf, size_t size, u64 value) |
194 | { |
195 | const char *hw_cache_str = stringify_perf_hw_cache_id(value: value & 0xff); |
196 | const char *hw_cache_op_str = |
197 | stringify_perf_hw_cache_op_id(value: (value & 0xff00) >> 8); |
198 | const char *hw_cache_op_result_str = |
199 | stringify_perf_hw_cache_op_result_id(value: (value & 0xff0000) >> 16); |
200 | |
201 | if (hw_cache_str == NULL || hw_cache_op_str == NULL || |
202 | hw_cache_op_result_str == NULL) { |
203 | snprintf(buf, size, "%#" PRIx64, value); |
204 | } else { |
205 | snprintf(buf, size, "%#" PRIx64" (%s | %s | %s)" , value, |
206 | hw_cache_op_result_str, hw_cache_op_str, hw_cache_str); |
207 | } |
208 | } |
209 | |
210 | #ifdef HAVE_LIBTRACEEVENT |
211 | static void __p_config_tracepoint_id(char *buf, size_t size, u64 value) |
212 | { |
213 | char *str = tracepoint_id_to_name(value); |
214 | |
215 | print_id_hex(str); |
216 | free(str); |
217 | } |
218 | #endif |
219 | |
220 | static void __p_config_id(char *buf, size_t size, u32 type, u64 value) |
221 | { |
222 | switch (type) { |
223 | case PERF_TYPE_HARDWARE: |
224 | return __p_config_hw_id(buf, size, value); |
225 | case PERF_TYPE_SOFTWARE: |
226 | return __p_config_sw_id(buf, size, value); |
227 | case PERF_TYPE_HW_CACHE: |
228 | return __p_config_hw_cache_id(buf, size, value); |
229 | case PERF_TYPE_TRACEPOINT: |
230 | #ifdef HAVE_LIBTRACEEVENT |
231 | return __p_config_tracepoint_id(buf, size, value); |
232 | #endif |
233 | case PERF_TYPE_RAW: |
234 | case PERF_TYPE_BREAKPOINT: |
235 | default: |
236 | snprintf(buf, size, "%#" PRIx64, value); |
237 | return; |
238 | } |
239 | } |
240 | |
241 | #define BUF_SIZE 1024 |
242 | |
243 | #define p_hex(val) snprintf(buf, BUF_SIZE, "%#"PRIx64, (uint64_t)(val)) |
244 | #define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) |
245 | #define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) |
246 | #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) |
247 | #define p_branch_sample_type(val) __p_branch_sample_type(buf, BUF_SIZE, val) |
248 | #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) |
249 | #define p_type_id(val) __p_type_id(buf, BUF_SIZE, val) |
250 | #define p_config_id(val) __p_config_id(buf, BUF_SIZE, attr->type, val) |
251 | |
252 | #define PRINT_ATTRn(_n, _f, _p, _a) \ |
253 | do { \ |
254 | if (_a || attr->_f) { \ |
255 | _p(attr->_f); \ |
256 | ret += attr__fprintf(fp, _n, buf, priv);\ |
257 | } \ |
258 | } while (0) |
259 | |
260 | #define PRINT_ATTRf(_f, _p) PRINT_ATTRn(#_f, _f, _p, false) |
261 | |
262 | int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, |
263 | attr__fprintf_f attr__fprintf, void *priv) |
264 | { |
265 | char buf[BUF_SIZE]; |
266 | int ret = 0; |
267 | |
268 | PRINT_ATTRn("type" , type, p_type_id, true); |
269 | PRINT_ATTRf(size, p_unsigned); |
270 | PRINT_ATTRn("config" , config, p_config_id, true); |
271 | PRINT_ATTRn("{ sample_period, sample_freq }" , sample_period, p_unsigned, false); |
272 | PRINT_ATTRf(sample_type, p_sample_type); |
273 | PRINT_ATTRf(read_format, p_read_format); |
274 | |
275 | PRINT_ATTRf(disabled, p_unsigned); |
276 | PRINT_ATTRf(inherit, p_unsigned); |
277 | PRINT_ATTRf(pinned, p_unsigned); |
278 | PRINT_ATTRf(exclusive, p_unsigned); |
279 | PRINT_ATTRf(exclude_user, p_unsigned); |
280 | PRINT_ATTRf(exclude_kernel, p_unsigned); |
281 | PRINT_ATTRf(exclude_hv, p_unsigned); |
282 | PRINT_ATTRf(exclude_idle, p_unsigned); |
283 | PRINT_ATTRf(mmap, p_unsigned); |
284 | PRINT_ATTRf(comm, p_unsigned); |
285 | PRINT_ATTRf(freq, p_unsigned); |
286 | PRINT_ATTRf(inherit_stat, p_unsigned); |
287 | PRINT_ATTRf(enable_on_exec, p_unsigned); |
288 | PRINT_ATTRf(task, p_unsigned); |
289 | PRINT_ATTRf(watermark, p_unsigned); |
290 | PRINT_ATTRf(precise_ip, p_unsigned); |
291 | PRINT_ATTRf(mmap_data, p_unsigned); |
292 | PRINT_ATTRf(sample_id_all, p_unsigned); |
293 | PRINT_ATTRf(exclude_host, p_unsigned); |
294 | PRINT_ATTRf(exclude_guest, p_unsigned); |
295 | PRINT_ATTRf(exclude_callchain_kernel, p_unsigned); |
296 | PRINT_ATTRf(exclude_callchain_user, p_unsigned); |
297 | PRINT_ATTRf(mmap2, p_unsigned); |
298 | PRINT_ATTRf(comm_exec, p_unsigned); |
299 | PRINT_ATTRf(use_clockid, p_unsigned); |
300 | PRINT_ATTRf(context_switch, p_unsigned); |
301 | PRINT_ATTRf(write_backward, p_unsigned); |
302 | PRINT_ATTRf(namespaces, p_unsigned); |
303 | PRINT_ATTRf(ksymbol, p_unsigned); |
304 | PRINT_ATTRf(bpf_event, p_unsigned); |
305 | PRINT_ATTRf(aux_output, p_unsigned); |
306 | PRINT_ATTRf(cgroup, p_unsigned); |
307 | PRINT_ATTRf(text_poke, p_unsigned); |
308 | PRINT_ATTRf(build_id, p_unsigned); |
309 | PRINT_ATTRf(inherit_thread, p_unsigned); |
310 | PRINT_ATTRf(remove_on_exec, p_unsigned); |
311 | PRINT_ATTRf(sigtrap, p_unsigned); |
312 | |
313 | PRINT_ATTRn("{ wakeup_events, wakeup_watermark }" , wakeup_events, p_unsigned, false); |
314 | PRINT_ATTRf(bp_type, p_unsigned); |
315 | PRINT_ATTRn("{ bp_addr, config1 }" , bp_addr, p_hex, false); |
316 | PRINT_ATTRn("{ bp_len, config2 }" , bp_len, p_hex, false); |
317 | PRINT_ATTRf(branch_sample_type, p_branch_sample_type); |
318 | PRINT_ATTRf(sample_regs_user, p_hex); |
319 | PRINT_ATTRf(sample_stack_user, p_unsigned); |
320 | PRINT_ATTRf(clockid, p_signed); |
321 | PRINT_ATTRf(sample_regs_intr, p_hex); |
322 | PRINT_ATTRf(aux_watermark, p_unsigned); |
323 | PRINT_ATTRf(sample_max_stack, p_unsigned); |
324 | PRINT_ATTRf(aux_sample_size, p_unsigned); |
325 | PRINT_ATTRf(sig_data, p_unsigned); |
326 | |
327 | return ret; |
328 | } |
329 | |