1 // SPDX-License-Identifier: GPL-2.0
3 * Test v2 API for perf --dlfilter shared object
4 * Copyright (c) 2023, Intel Corporation.
12 * Copy v2 API instead of including current API
14 #include <linux/perf_event.h>
15 #include <linux/types.h>
18 * The following macro can be used to determine if this header defines
19 * perf_dlfilter_sample machine_pid and vcpu.
21 #define PERF_DLFILTER_HAS_MACHINE_PID
23 /* Definitions for perf_dlfilter_sample flags */
25 PERF_DLFILTER_FLAG_BRANCH
= 1ULL << 0,
26 PERF_DLFILTER_FLAG_CALL
= 1ULL << 1,
27 PERF_DLFILTER_FLAG_RETURN
= 1ULL << 2,
28 PERF_DLFILTER_FLAG_CONDITIONAL
= 1ULL << 3,
29 PERF_DLFILTER_FLAG_SYSCALLRET
= 1ULL << 4,
30 PERF_DLFILTER_FLAG_ASYNC
= 1ULL << 5,
31 PERF_DLFILTER_FLAG_INTERRUPT
= 1ULL << 6,
32 PERF_DLFILTER_FLAG_TX_ABORT
= 1ULL << 7,
33 PERF_DLFILTER_FLAG_TRACE_BEGIN
= 1ULL << 8,
34 PERF_DLFILTER_FLAG_TRACE_END
= 1ULL << 9,
35 PERF_DLFILTER_FLAG_IN_TX
= 1ULL << 10,
36 PERF_DLFILTER_FLAG_VMENTRY
= 1ULL << 11,
37 PERF_DLFILTER_FLAG_VMEXIT
= 1ULL << 12,
41 * perf sample event information (as per perf script and <linux/perf_event.h>)
43 struct perf_dlfilter_sample
{
44 __u32 size
; /* Size of this structure (for compatibility checking) */
45 __u16 ins_lat
; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
46 __u16 p_stage_cyc
; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
55 __u64 weight
; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
56 __u64 transaction
; /* Refer PERF_SAMPLE_TRANSACTION in <linux/perf_event.h> */
57 __u64 insn_cnt
; /* For instructions-per-cycle (IPC) */
58 __u64 cyc_cnt
; /* For instructions-per-cycle (IPC) */
60 __u32 flags
; /* Refer PERF_DLFILTER_FLAG_* above */
61 __u64 data_src
; /* Refer PERF_SAMPLE_DATA_SRC in <linux/perf_event.h> */
62 __u64 phys_addr
; /* Refer PERF_SAMPLE_PHYS_ADDR in <linux/perf_event.h> */
63 __u64 data_page_size
; /* Refer PERF_SAMPLE_DATA_PAGE_SIZE in <linux/perf_event.h> */
64 __u64 code_page_size
; /* Refer PERF_SAMPLE_CODE_PAGE_SIZE in <linux/perf_event.h> */
65 __u64 cgroup
; /* Refer PERF_SAMPLE_CGROUP in <linux/perf_event.h> */
66 __u8 cpumode
; /* Refer CPUMODE_MASK etc in <linux/perf_event.h> */
67 __u8 addr_correlates_sym
; /* True => resolve_addr() can be called */
68 __u16 misc
; /* Refer perf_event_header in <linux/perf_event.h> */
69 __u32 raw_size
; /* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
70 const void *raw_data
; /* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
71 __u64 brstack_nr
; /* Number of brstack entries */
72 const struct perf_branch_entry
*brstack
; /* Refer <linux/perf_event.h> */
73 __u64 raw_callchain_nr
; /* Number of raw_callchain entries */
74 const __u64
*raw_callchain
; /* Refer <linux/perf_event.h> */
81 * Address location (as per perf script)
83 struct perf_dlfilter_al
{
84 __u32 size
; /* Size of this structure (for compatibility checking) */
87 __u64 addr
; /* Mapped address (from dso) */
91 __u8 sym_binding
; /* STB_LOCAL, STB_GLOBAL or STB_WEAK, refer <elf.h> */
92 __u8 is_64_bit
; /* Only valid if dso is not NULL */
93 __u8 is_kernel_ip
; /* True if in kernel space */
96 /* Below members are only populated by resolve_ip() */
97 __u8 filtered
; /* True if this sample event will be filtered out */
99 void *priv
; /* Private data (v2 API) */
102 struct perf_dlfilter_fns
{
103 /* Return information about ip */
104 const struct perf_dlfilter_al
*(*resolve_ip
)(void *ctx
);
105 /* Return information about addr (if addr_correlates_sym) */
106 const struct perf_dlfilter_al
*(*resolve_addr
)(void *ctx
);
107 /* Return arguments from --dlarg option */
108 char **(*args
)(void *ctx
, int *dlargc
);
110 * Return information about address (al->size must be set before
111 * calling). Returns 0 on success, -1 otherwise. Call al_cleanup()
112 * when 'al' data is no longer needed.
114 __s32 (*resolve_address
)(void *ctx
, __u64 address
, struct perf_dlfilter_al
*al
);
115 /* Return instruction bytes and length */
116 const __u8
*(*insn
)(void *ctx
, __u32
*length
);
117 /* Return source file name and line number */
118 const char *(*srcline
)(void *ctx
, __u32
*line_number
);
119 /* Return perf_event_attr, refer <linux/perf_event.h> */
120 struct perf_event_attr
*(*attr
)(void *ctx
);
121 /* Read object code, return numbers of bytes read */
122 __s32 (*object_code
)(void *ctx
, __u64 ip
, void *buf
, __u32 len
);
124 * If present (i.e. must check al_cleanup != NULL), call after
125 * resolve_address() to free any associated resources. (v2 API)
127 void (*al_cleanup
)(void *ctx
, struct perf_dlfilter_al
*al
);
129 void *(*reserved
[119])(void *);
132 struct perf_dlfilter_fns perf_dlfilter_fns
;
136 #define pr_debug(fmt, ...) do { \
138 fprintf(stderr, fmt, ##__VA_ARGS__); \
141 static int test_fail(const char *msg
)
143 pr_debug("%s\n", msg
);
147 #define CHECK(x) do { \
149 return test_fail("Check '" #x "' failed\n"); \
156 int early_filter_cnt
;
160 static struct filter_data
*filt_dat
;
162 int start(void **data
, void *ctx
)
166 struct filter_data
*d
;
171 CHECK(!filt_dat
&& !called
);
174 d
= calloc(1, sizeof(*d
));
176 test_fail("Failed to allocate memory");
180 dlargv
= perf_dlfilter_fns
.args(ctx
, &dlargc
);
183 CHECK(!strcmp(dlargv
[0], "first"));
184 verbose
= strtol(dlargv
[1], NULL
, 0);
185 d
->ip
= strtoull(dlargv
[2], NULL
, 0);
186 d
->addr
= strtoull(dlargv
[3], NULL
, 0);
187 d
->do_early
= strtol(dlargv
[4], NULL
, 0);
188 CHECK(!strcmp(dlargv
[5], "last"));
190 pr_debug("%s API\n", __func__
);
195 #define CHECK_SAMPLE(x) do { \
196 if (sample->x != expected.x) \
197 return test_fail("'" #x "' not expected value\n"); \
200 static int check_sample(struct filter_data
*d
, const struct perf_dlfilter_sample
*sample
)
202 struct perf_dlfilter_sample expected
= {
212 .cpumode
= PERF_RECORD_MISC_USER
,
213 .addr_correlates_sym
= 1,
214 .misc
= PERF_RECORD_MISC_USER
,
217 CHECK(sample
->size
>= sizeof(struct perf_dlfilter_sample
));
225 CHECK_SAMPLE(stream_id
);
226 CHECK_SAMPLE(period
);
228 CHECK_SAMPLE(cpumode
);
229 CHECK_SAMPLE(addr_correlates_sym
);
232 CHECK(!sample
->raw_data
);
233 CHECK_SAMPLE(brstack_nr
);
234 CHECK(!sample
->brstack
);
235 CHECK_SAMPLE(raw_callchain_nr
);
236 CHECK(!sample
->raw_callchain
);
238 #define EVENT_NAME "branches"
239 CHECK(!strncmp(sample
->event
, EVENT_NAME
, strlen(EVENT_NAME
)));
244 static int check_al(void *ctx
)
246 const struct perf_dlfilter_al
*al
;
248 al
= perf_dlfilter_fns
.resolve_ip(ctx
);
250 return test_fail("resolve_ip() failed");
252 CHECK(al
->sym
&& !strcmp("foo", al
->sym
));
258 static int check_addr_al(void *ctx
)
260 const struct perf_dlfilter_al
*addr_al
;
262 addr_al
= perf_dlfilter_fns
.resolve_addr(ctx
);
264 return test_fail("resolve_addr() failed");
266 CHECK(addr_al
->sym
&& !strcmp("bar", addr_al
->sym
));
267 CHECK(!addr_al
->symoff
);
272 static int check_address_al(void *ctx
, const struct perf_dlfilter_sample
*sample
)
274 struct perf_dlfilter_al address_al
;
275 const struct perf_dlfilter_al
*al
;
277 al
= perf_dlfilter_fns
.resolve_ip(ctx
);
279 return test_fail("resolve_ip() failed");
281 address_al
.size
= sizeof(address_al
);
282 if (perf_dlfilter_fns
.resolve_address(ctx
, sample
->ip
, &address_al
))
283 return test_fail("resolve_address() failed");
285 CHECK(address_al
.sym
&& al
->sym
);
286 CHECK(!strcmp(address_al
.sym
, al
->sym
));
287 CHECK(address_al
.addr
== al
->addr
);
288 CHECK(address_al
.sym_start
== al
->sym_start
);
289 CHECK(address_al
.sym_end
== al
->sym_end
);
290 CHECK(address_al
.dso
&& al
->dso
);
291 CHECK(!strcmp(address_al
.dso
, al
->dso
));
293 /* al_cleanup() is v2 API so may not be present */
294 if (perf_dlfilter_fns
.al_cleanup
)
295 perf_dlfilter_fns
.al_cleanup(ctx
, &address_al
);
300 static int check_attr(void *ctx
)
302 struct perf_event_attr
*attr
= perf_dlfilter_fns
.attr(ctx
);
305 CHECK(attr
->type
== PERF_TYPE_HARDWARE
);
306 CHECK(attr
->config
== PERF_COUNT_HW_BRANCH_INSTRUCTIONS
);
311 static int check_object_code(void *ctx
, const struct perf_dlfilter_sample
*sample
)
315 CHECK(perf_dlfilter_fns
.object_code(ctx
, sample
->ip
, buf
, sizeof(buf
)) > 0);
320 static int do_checks(void *data
, const struct perf_dlfilter_sample
*sample
, void *ctx
, bool early
)
322 struct filter_data
*d
= data
;
324 CHECK(data
&& filt_dat
== data
);
327 CHECK(!d
->early_filter_cnt
);
328 d
->early_filter_cnt
+= 1;
330 CHECK(!d
->filter_cnt
);
331 CHECK(d
->early_filter_cnt
);
332 CHECK(d
->do_early
!= 2);
336 if (check_sample(data
, sample
))
342 if (early
&& !d
->do_early
)
345 if (check_al(ctx
) || check_addr_al(ctx
) || check_address_al(ctx
, sample
) ||
346 check_object_code(ctx
, sample
))
350 return d
->do_early
== 2;
355 int filter_event_early(void *data
, const struct perf_dlfilter_sample
*sample
, void *ctx
)
357 pr_debug("%s API\n", __func__
);
359 return do_checks(data
, sample
, ctx
, true);
362 int filter_event(void *data
, const struct perf_dlfilter_sample
*sample
, void *ctx
)
364 pr_debug("%s API\n", __func__
);
366 return do_checks(data
, sample
, ctx
, false);
369 int stop(void *data
, void *ctx
)
373 pr_debug("%s API\n", __func__
);
375 CHECK(data
&& filt_dat
== data
&& !called
);
383 const char *filter_description(const char **long_description
)
385 *long_description
= "Filter used by the 'dlfilter C API' perf test";
386 return "dlfilter to test v2 C API";