|
| 1 | +perf-dlfilter(1) |
| 2 | +================ |
| 3 | + |
| 4 | +NAME |
| 5 | +---- |
| 6 | +perf-dlfilter - Filter sample events using a dynamically loaded shared |
| 7 | +object file |
| 8 | + |
| 9 | +SYNOPSIS |
| 10 | +-------- |
| 11 | +[verse] |
| 12 | +'perf script' [--dlfilter file.so ] |
| 13 | + |
| 14 | +DESCRIPTION |
| 15 | +----------- |
| 16 | + |
| 17 | +This option is used to process data through a custom filter provided by a |
| 18 | +dynamically loaded shared object file. |
| 19 | + |
| 20 | +If 'file.so' does not contain "/", then it will be found either in the current |
| 21 | +directory, or perf tools exec path which is ~/libexec/perf-core/dlfilters for |
| 22 | +a local build and install (refer perf --exec-path), or the dynamic linker |
| 23 | +paths. |
| 24 | + |
| 25 | +API |
| 26 | +--- |
| 27 | + |
| 28 | +The API for filtering consists of the following: |
| 29 | + |
| 30 | +[source,c] |
| 31 | +---- |
| 32 | +#include <perf/perf_dlfilter.h> |
| 33 | + |
| 34 | +const struct perf_dlfilter_fns perf_dlfilter_fns; |
| 35 | + |
| 36 | +int start(void **data, void *ctx); |
| 37 | +int stop(void *data, void *ctx); |
| 38 | +int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx); |
| 39 | +---- |
| 40 | + |
| 41 | +If implemented, 'start' will be called at the beginning, before any |
| 42 | +calls to 'filter_event' . Return 0 to indicate success, |
| 43 | +or return a negative error code. '*data' can be assigned for use by other |
| 44 | +functions. 'ctx' is needed for calls to perf_dlfilter_fns, but most |
| 45 | +perf_dlfilter_fns are not valid when called from 'start'. |
| 46 | + |
| 47 | +If implemented, 'stop' will be called at the end, after any calls to |
| 48 | +'filter_event'. Return 0 to indicate success, or |
| 49 | +return a negative error code. 'data' is set by 'start'. 'ctx' is needed |
| 50 | +for calls to perf_dlfilter_fns, but most perf_dlfilter_fns are not valid |
| 51 | +when called from 'stop'. |
| 52 | + |
| 53 | +If implemented, 'filter_event' will be called for each sample event. |
| 54 | +Return 0 to keep the sample event, 1 to filter it out, or return a negative |
| 55 | +error code. 'data' is set by 'start'. 'ctx' is needed for calls to |
| 56 | +'perf_dlfilter_fns'. |
| 57 | + |
| 58 | +The perf_dlfilter_sample structure |
| 59 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 60 | + |
| 61 | +'filter_event' is passed a perf_dlfilter_sample |
| 62 | +structure, which contains the following fields: |
| 63 | +[source,c] |
| 64 | +---- |
| 65 | +/* |
| 66 | + * perf sample event information (as per perf script and <linux/perf_event.h>) |
| 67 | + */ |
| 68 | +struct perf_dlfilter_sample { |
| 69 | + __u32 size; /* Size of this structure (for compatibility checking) */ |
| 70 | + __u16 ins_lat; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */ |
| 71 | + __u16 p_stage_cyc; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */ |
| 72 | + __u64 ip; |
| 73 | + __s32 pid; |
| 74 | + __s32 tid; |
| 75 | + __u64 time; |
| 76 | + __u64 addr; |
| 77 | + __u64 id; |
| 78 | + __u64 stream_id; |
| 79 | + __u64 period; |
| 80 | + __u64 weight; /* Refer PERF_SAMPLE_WEIGHT_TYPE in <linux/perf_event.h> */ |
| 81 | + __u64 transaction; /* Refer PERF_SAMPLE_TRANSACTION in <linux/perf_event.h> */ |
| 82 | + __u64 insn_cnt; /* For instructions-per-cycle (IPC) */ |
| 83 | + __u64 cyc_cnt; /* For instructions-per-cycle (IPC) */ |
| 84 | + __s32 cpu; |
| 85 | + __u32 flags; /* Refer PERF_DLFILTER_FLAG_* above */ |
| 86 | + __u64 data_src; /* Refer PERF_SAMPLE_DATA_SRC in <linux/perf_event.h> */ |
| 87 | + __u64 phys_addr; /* Refer PERF_SAMPLE_PHYS_ADDR in <linux/perf_event.h> */ |
| 88 | + __u64 data_page_size; /* Refer PERF_SAMPLE_DATA_PAGE_SIZE in <linux/perf_event.h> */ |
| 89 | + __u64 code_page_size; /* Refer PERF_SAMPLE_CODE_PAGE_SIZE in <linux/perf_event.h> */ |
| 90 | + __u64 cgroup; /* Refer PERF_SAMPLE_CGROUP in <linux/perf_event.h> */ |
| 91 | + __u8 cpumode; /* Refer CPUMODE_MASK etc in <linux/perf_event.h> */ |
| 92 | + __u8 addr_correlates_sym; /* True => resolve_addr() can be called */ |
| 93 | + __u16 misc; /* Refer perf_event_header in <linux/perf_event.h> */ |
| 94 | + __u32 raw_size; /* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */ |
| 95 | + const void *raw_data; /* Refer PERF_SAMPLE_RAW in <linux/perf_event.h> */ |
| 96 | + __u64 brstack_nr; /* Number of brstack entries */ |
| 97 | + const struct perf_branch_entry *brstack; /* Refer <linux/perf_event.h> */ |
| 98 | + __u64 raw_callchain_nr; /* Number of raw_callchain entries */ |
| 99 | + const __u64 *raw_callchain; /* Refer <linux/perf_event.h> */ |
| 100 | + const char *event; |
| 101 | +}; |
| 102 | +---- |
| 103 | + |
| 104 | +The perf_dlfilter_fns structure |
| 105 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 106 | + |
| 107 | +The 'perf_dlfilter_fns' structure is populated with function pointers when the |
| 108 | +file is loaded. The functions can be called by 'filter_event'. |
| 109 | + |
| 110 | +[source,c] |
| 111 | +---- |
| 112 | +struct perf_dlfilter_fns { |
| 113 | + const struct perf_dlfilter_al *(*resolve_ip)(void *ctx); |
| 114 | + const struct perf_dlfilter_al *(*resolve_addr)(void *ctx); |
| 115 | + void *(*reserved[126])(void *); |
| 116 | +}; |
| 117 | +---- |
| 118 | + |
| 119 | +'resolve_ip' returns information about ip. |
| 120 | + |
| 121 | +'resolve_addr' returns information about addr (if addr_correlates_sym). |
| 122 | + |
| 123 | +The perf_dlfilter_al structure |
| 124 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 125 | + |
| 126 | +The 'perf_dlfilter_al' structure contains information about an address. |
| 127 | + |
| 128 | +[source,c] |
| 129 | +---- |
| 130 | +/* |
| 131 | + * Address location (as per perf script) |
| 132 | + */ |
| 133 | +struct perf_dlfilter_al { |
| 134 | + __u32 size; /* Size of this structure (for compatibility checking) */ |
| 135 | + __u32 symoff; |
| 136 | + const char *sym; |
| 137 | + __u64 addr; /* Mapped address (from dso) */ |
| 138 | + __u64 sym_start; |
| 139 | + __u64 sym_end; |
| 140 | + const char *dso; |
| 141 | + __u8 sym_binding; /* STB_LOCAL, STB_GLOBAL or STB_WEAK, refer <elf.h> */ |
| 142 | + __u8 is_64_bit; /* Only valid if dso is not NULL */ |
| 143 | + __u8 is_kernel_ip; /* True if in kernel space */ |
| 144 | + __u32 buildid_size; |
| 145 | + __u8 *buildid; |
| 146 | + /* Below members are only populated by resolve_ip() */ |
| 147 | + __u8 filtered; /* true if this sample event will be filtered out */ |
| 148 | + const char *comm; |
| 149 | +}; |
| 150 | +---- |
| 151 | + |
| 152 | +perf_dlfilter_sample flags |
| 153 | +~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 154 | + |
| 155 | +The 'flags' member of 'perf_dlfilter_sample' corresponds with the flags field |
| 156 | +of perf script. The bits of the flags are as follows: |
| 157 | + |
| 158 | +[source,c] |
| 159 | +---- |
| 160 | +/* Definitions for perf_dlfilter_sample flags */ |
| 161 | +enum { |
| 162 | + PERF_DLFILTER_FLAG_BRANCH = 1ULL << 0, |
| 163 | + PERF_DLFILTER_FLAG_CALL = 1ULL << 1, |
| 164 | + PERF_DLFILTER_FLAG_RETURN = 1ULL << 2, |
| 165 | + PERF_DLFILTER_FLAG_CONDITIONAL = 1ULL << 3, |
| 166 | + PERF_DLFILTER_FLAG_SYSCALLRET = 1ULL << 4, |
| 167 | + PERF_DLFILTER_FLAG_ASYNC = 1ULL << 5, |
| 168 | + PERF_DLFILTER_FLAG_INTERRUPT = 1ULL << 6, |
| 169 | + PERF_DLFILTER_FLAG_TX_ABORT = 1ULL << 7, |
| 170 | + PERF_DLFILTER_FLAG_TRACE_BEGIN = 1ULL << 8, |
| 171 | + PERF_DLFILTER_FLAG_TRACE_END = 1ULL << 9, |
| 172 | + PERF_DLFILTER_FLAG_IN_TX = 1ULL << 10, |
| 173 | + PERF_DLFILTER_FLAG_VMENTRY = 1ULL << 11, |
| 174 | + PERF_DLFILTER_FLAG_VMEXIT = 1ULL << 12, |
| 175 | +}; |
| 176 | +---- |
| 177 | + |
| 178 | +EXAMPLE |
| 179 | +------- |
| 180 | + |
| 181 | +Filter out everything except branches from "foo" to "bar": |
| 182 | + |
| 183 | +[source,c] |
| 184 | +---- |
| 185 | +#include <perf/perf_dlfilter.h> |
| 186 | +#include <string.h> |
| 187 | + |
| 188 | +const struct perf_dlfilter_fns perf_dlfilter_fns; |
| 189 | + |
| 190 | +int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx) |
| 191 | +{ |
| 192 | + const struct perf_dlfilter_al *al; |
| 193 | + const struct perf_dlfilter_al *addr_al; |
| 194 | + |
| 195 | + if (!sample->ip || !sample->addr_correlates_sym) |
| 196 | + return 1; |
| 197 | + |
| 198 | + al = perf_dlfilter_fns.resolve_ip(ctx); |
| 199 | + if (!al || !al->sym || strcmp(al->sym, "foo")) |
| 200 | + return 1; |
| 201 | + |
| 202 | + addr_al = perf_dlfilter_fns.resolve_addr(ctx); |
| 203 | + if (!addr_al || !addr_al->sym || strcmp(addr_al->sym, "bar")) |
| 204 | + return 1; |
| 205 | + |
| 206 | + return 0; |
| 207 | +} |
| 208 | +---- |
| 209 | + |
| 210 | +To build the shared object, assuming perf has been installed for the local user |
| 211 | +i.e. perf_dlfilter.h is in ~/include/perf : |
| 212 | + |
| 213 | + gcc -c -I ~/include -fpic dlfilter-example.c |
| 214 | + gcc -shared -o dlfilter-example.so dlfilter-example.o |
| 215 | + |
| 216 | +To use the filter with perf script: |
| 217 | + |
| 218 | + perf script --dlfilter dlfilter-example.so |
| 219 | + |
| 220 | +SEE ALSO |
| 221 | +-------- |
| 222 | +linkperf:perf-script[1] |
0 commit comments