0001 perf-dlfilter(1)
0002 ================
0003
0004 NAME
0005 ----
0006 perf-dlfilter - Filter sample events using a dynamically loaded shared
0007 object file
0008
0009 SYNOPSIS
0010 --------
0011 [verse]
0012 'perf script' [--dlfilter file.so ] [ --dlarg arg ]...
0013
0014 DESCRIPTION
0015 -----------
0016
0017 This option is used to process data through a custom filter provided by a
0018 dynamically loaded shared object file. Arguments can be passed using --dlarg
0019 and retrieved using perf_dlfilter_fns.args().
0020
0021 If 'file.so' does not contain "/", then it will be found either in the current
0022 directory, or perf tools exec path which is ~/libexec/perf-core/dlfilters for
0023 a local build and install (refer perf --exec-path), or the dynamic linker
0024 paths.
0025
0026 API
0027 ---
0028
0029 The API for filtering consists of the following:
0030
0031 [source,c]
0032 ----
0033 #include <perf/perf_dlfilter.h>
0034
0035 struct perf_dlfilter_fns perf_dlfilter_fns;
0036
0037 int start(void **data, void *ctx);
0038 int stop(void *data, void *ctx);
0039 int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
0040 int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx);
0041 const char *filter_description(const char **long_description);
0042 ----
0043
0044 If implemented, 'start' will be called at the beginning, before any
0045 calls to 'filter_event' or 'filter_event_early'. Return 0 to indicate success,
0046 or return a negative error code. '*data' can be assigned for use by other
0047 functions. 'ctx' is needed for calls to perf_dlfilter_fns, but most
0048 perf_dlfilter_fns are not valid when called from 'start'.
0049
0050 If implemented, 'stop' will be called at the end, after any calls to
0051 'filter_event' or 'filter_event_early'. Return 0 to indicate success, or
0052 return a negative error code. 'data' is set by 'start'. 'ctx' is needed
0053 for calls to perf_dlfilter_fns, but most perf_dlfilter_fns are not valid
0054 when called from 'stop'.
0055
0056 If implemented, 'filter_event' will be called for each sample event.
0057 Return 0 to keep the sample event, 1 to filter it out, or return a negative
0058 error code. 'data' is set by 'start'. 'ctx' is needed for calls to
0059 'perf_dlfilter_fns'.
0060
0061 'filter_event_early' is the same as 'filter_event' except it is called before
0062 internal filtering.
0063
0064 If implemented, 'filter_description' should return a one-line description
0065 of the filter, and optionally a longer description.
0066
0067 The perf_dlfilter_sample structure
0068 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0069
0070 'filter_event' and 'filter_event_early' are passed a perf_dlfilter_sample
0071 structure, which contains the following fields:
0072 [source,c]
0073 ----
0074 /*
0075 * perf sample event information (as per perf script and <linux/perf_event.h>)
0076 */
0077 struct perf_dlfilter_sample {
0078 __u32 size; /* Size of this structure (for compatibility checking) */
0079 __u16 ins_lat; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
0080 __u16 p_stage_cyc; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
0081 __u64 ip;
0082 __s32 pid;
0083 __s32 tid;
0084 __u64 time;
0085 __u64 addr;
0086 __u64 id;
0087 __u64 stream_id;
0088 __u64 period;
0089 __u64 weight; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */
0090 __u64 transaction; /* Refer PERF_SAMPLE_TRANSACTION in <linux/perf_event.h> */
0091 __u64 insn_cnt; /* For instructions-per-cycle (IPC) */
0092 __u64 cyc_cnt; /* For instructions-per-cycle (IPC) */
0093 __s32 cpu;
0094 __u32 flags; /* Refer PERF_DLFILTER_FLAG_* above */
0095 __u64 data_src; /* Refer PERF_SAMPLE_DATA_SRC in <linux/perf_event.h> */
0096 __u64 phys_addr; /* Refer PERF_SAMPLE_PHYS_ADDR in <linux/perf_event.h> */
0097 __u64 data_page_size; /* Refer PERF_SAMPLE_DATA_PAGE_SIZE in <linux/perf_event.h> */
0098 __u64 code_page_size; /* Refer PERF_SAMPLE_CODE_PAGE_SIZE in <linux/perf_event.h> */
0099 __u64 cgroup; /* Refer PERF_SAMPLE_CGROUP in <linux/perf_event.h> */
0100 __u8 cpumode; /* Refer CPUMODE_MASK etc in <linux/perf_event.h> */
0101 __u8 addr_correlates_sym; /* True => resolve_addr() can be called */
0102 __u16 misc; /* Refer perf_event_header in <linux/perf_event.h> */
0103 __u32 raw_size; /* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
0104 const void *raw_data; /* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */
0105 __u64 brstack_nr; /* Number of brstack entries */
0106 const struct perf_branch_entry *brstack; /* Refer <linux/perf_event.h> */
0107 __u64 raw_callchain_nr; /* Number of raw_callchain entries */
0108 const __u64 *raw_callchain; /* Refer <linux/perf_event.h> */
0109 const char *event;
0110 __s32 machine_pid;
0111 __s32 vcpu;
0112 };
0113 ----
0114
0115 Note: 'machine_pid' and 'vcpu' are not original members, but were added together later.
0116 'size' can be used to determine their presence at run time.
0117 PERF_DLFILTER_HAS_MACHINE_PID will be defined if they are present at compile time.
0118 For example:
0119 [source,c]
0120 ----
0121 #include <perf/perf_dlfilter.h>
0122 #include <stddef.h>
0123 #include <stdbool.h>
0124
0125 static inline bool have_machine_pid(const struct perf_dlfilter_sample *sample)
0126 {
0127 #ifdef PERF_DLFILTER_HAS_MACHINE_PID
0128 return sample->size >= offsetof(struct perf_dlfilter_sample, vcpu) + sizeof(sample->vcpu);
0129 #else
0130 return false;
0131 #endif
0132 }
0133 ----
0134
0135 The perf_dlfilter_fns structure
0136 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0137
0138 The 'perf_dlfilter_fns' structure is populated with function pointers when the
0139 file is loaded. The functions can be called by 'filter_event' or
0140 'filter_event_early'.
0141
0142 [source,c]
0143 ----
0144 struct perf_dlfilter_fns {
0145 const struct perf_dlfilter_al *(*resolve_ip)(void *ctx);
0146 const struct perf_dlfilter_al *(*resolve_addr)(void *ctx);
0147 char **(*args)(void *ctx, int *dlargc);
0148 __s32 (*resolve_address)(void *ctx, __u64 address, struct perf_dlfilter_al *al);
0149 const __u8 *(*insn)(void *ctx, __u32 *length);
0150 const char *(*srcline)(void *ctx, __u32 *line_number);
0151 struct perf_event_attr *(*attr)(void *ctx);
0152 __s32 (*object_code)(void *ctx, __u64 ip, void *buf, __u32 len);
0153 void *(*reserved[120])(void *);
0154 };
0155 ----
0156
0157 'resolve_ip' returns information about ip.
0158
0159 'resolve_addr' returns information about addr (if addr_correlates_sym).
0160
0161 'args' returns arguments from --dlarg options.
0162
0163 'resolve_address' provides information about 'address'. al->size must be set
0164 before calling. Returns 0 on success, -1 otherwise.
0165
0166 'insn' returns instruction bytes and length.
0167
0168 'srcline' return source file name and line number.
0169
0170 'attr' returns perf_event_attr, refer <linux/perf_event.h>.
0171
0172 'object_code' reads object code and returns the number of bytes read.
0173
0174 The perf_dlfilter_al structure
0175 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0176
0177 The 'perf_dlfilter_al' structure contains information about an address.
0178
0179 [source,c]
0180 ----
0181 /*
0182 * Address location (as per perf script)
0183 */
0184 struct perf_dlfilter_al {
0185 __u32 size; /* Size of this structure (for compatibility checking) */
0186 __u32 symoff;
0187 const char *sym;
0188 __u64 addr; /* Mapped address (from dso) */
0189 __u64 sym_start;
0190 __u64 sym_end;
0191 const char *dso;
0192 __u8 sym_binding; /* STB_LOCAL, STB_GLOBAL or STB_WEAK, refer <elf.h> */
0193 __u8 is_64_bit; /* Only valid if dso is not NULL */
0194 __u8 is_kernel_ip; /* True if in kernel space */
0195 __u32 buildid_size;
0196 __u8 *buildid;
0197 /* Below members are only populated by resolve_ip() */
0198 __u8 filtered; /* true if this sample event will be filtered out */
0199 const char *comm;
0200 };
0201 ----
0202
0203 perf_dlfilter_sample flags
0204 ~~~~~~~~~~~~~~~~~~~~~~~~~~
0205
0206 The 'flags' member of 'perf_dlfilter_sample' corresponds with the flags field
0207 of perf script. The bits of the flags are as follows:
0208
0209 [source,c]
0210 ----
0211 /* Definitions for perf_dlfilter_sample flags */
0212 enum {
0213 PERF_DLFILTER_FLAG_BRANCH = 1ULL << 0,
0214 PERF_DLFILTER_FLAG_CALL = 1ULL << 1,
0215 PERF_DLFILTER_FLAG_RETURN = 1ULL << 2,
0216 PERF_DLFILTER_FLAG_CONDITIONAL = 1ULL << 3,
0217 PERF_DLFILTER_FLAG_SYSCALLRET = 1ULL << 4,
0218 PERF_DLFILTER_FLAG_ASYNC = 1ULL << 5,
0219 PERF_DLFILTER_FLAG_INTERRUPT = 1ULL << 6,
0220 PERF_DLFILTER_FLAG_TX_ABORT = 1ULL << 7,
0221 PERF_DLFILTER_FLAG_TRACE_BEGIN = 1ULL << 8,
0222 PERF_DLFILTER_FLAG_TRACE_END = 1ULL << 9,
0223 PERF_DLFILTER_FLAG_IN_TX = 1ULL << 10,
0224 PERF_DLFILTER_FLAG_VMENTRY = 1ULL << 11,
0225 PERF_DLFILTER_FLAG_VMEXIT = 1ULL << 12,
0226 };
0227 ----
0228
0229 EXAMPLE
0230 -------
0231
0232 Filter out everything except branches from "foo" to "bar":
0233
0234 [source,c]
0235 ----
0236 #include <perf/perf_dlfilter.h>
0237 #include <string.h>
0238
0239 struct perf_dlfilter_fns perf_dlfilter_fns;
0240
0241 int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx)
0242 {
0243 const struct perf_dlfilter_al *al;
0244 const struct perf_dlfilter_al *addr_al;
0245
0246 if (!sample->ip || !sample->addr_correlates_sym)
0247 return 1;
0248
0249 al = perf_dlfilter_fns.resolve_ip(ctx);
0250 if (!al || !al->sym || strcmp(al->sym, "foo"))
0251 return 1;
0252
0253 addr_al = perf_dlfilter_fns.resolve_addr(ctx);
0254 if (!addr_al || !addr_al->sym || strcmp(addr_al->sym, "bar"))
0255 return 1;
0256
0257 return 0;
0258 }
0259 ----
0260
0261 To build the shared object, assuming perf has been installed for the local user
0262 i.e. perf_dlfilter.h is in ~/include/perf :
0263
0264 gcc -c -I ~/include -fpic dlfilter-example.c
0265 gcc -shared -o dlfilter-example.so dlfilter-example.o
0266
0267 To use the filter with perf script:
0268
0269 perf script --dlfilter dlfilter-example.so
0270
0271 NOTES
0272 -----
0273
0274 The dlfilter .so file will be dependent on shared libraries. If those change,
0275 it may be necessary to rebuild the .so. Also there may be unexpected results
0276 if the .so uses different versions of the shared libraries that perf uses.
0277 Versions can be checked using the ldd command.
0278
0279 SEE ALSO
0280 --------
0281 linkperf:perf-script[1]