| 1 | libperf-sampling(7) |
| 2 | =================== |
| 3 | |
| 4 | NAME |
| 5 | ---- |
| 6 | libperf-sampling - sampling interface |
| 7 | |
| 8 | |
| 9 | DESCRIPTION |
| 10 | ----------- |
| 11 | The sampling interface provides API to measure and get count for specific perf events. |
| 12 | |
| 13 | The following test tries to explain count on `sampling.c` example. |
| 14 | |
| 15 | It is by no means complete guide to sampling, but shows libperf basic API for sampling. |
| 16 | |
| 17 | The `sampling.c` comes with libperf package and can be compiled and run like: |
| 18 | |
| 19 | [source,bash] |
| 20 | -- |
| 21 | $ gcc -o sampling sampling.c -lperf |
| 22 | $ sudo ./sampling |
| 23 | cpu 0, pid 0, tid 0, ip ffffffffad06c4e6, period 1 |
| 24 | cpu 0, pid 4465, tid 4469, ip ffffffffad118748, period 18322959 |
| 25 | cpu 0, pid 0, tid 0, ip ffffffffad115722, period 33544846 |
| 26 | cpu 0, pid 4465, tid 4470, ip 7f84fe0cdad6, period 23687474 |
| 27 | cpu 0, pid 0, tid 0, ip ffffffffad9e0349, period 34255790 |
| 28 | cpu 0, pid 4465, tid 4469, ip ffffffffad136581, period 38664069 |
| 29 | cpu 0, pid 0, tid 0, ip ffffffffad9e55e2, period 21922384 |
| 30 | cpu 0, pid 4465, tid 4470, ip 7f84fe0ebebf, period 17655175 |
| 31 | ... |
| 32 | -- |
| 33 | |
| 34 | It requires root access, because it uses hardware cycles event. |
| 35 | |
| 36 | The `sampling.c` example profiles/samples all CPUs with hardware cycles, in a |
| 37 | nutshell it: |
| 38 | |
| 39 | - creates events |
| 40 | - adds them to the event list |
| 41 | - opens and enables events through the event list |
| 42 | - sleeps for 3 seconds |
| 43 | - disables events |
| 44 | - reads and displays recorded samples |
| 45 | - destroys the event list |
| 46 | |
| 47 | The first thing you need to do before using libperf is to call init function: |
| 48 | |
| 49 | [source,c] |
| 50 | -- |
| 51 | 12 static int libperf_print(enum libperf_print_level level, |
| 52 | 13 const char *fmt, va_list ap) |
| 53 | 14 { |
| 54 | 15 return vfprintf(stderr, fmt, ap); |
| 55 | 16 } |
| 56 | |
| 57 | 23 int main(int argc, char **argv) |
| 58 | 24 { |
| 59 | ... |
| 60 | 40 libperf_init(libperf_print); |
| 61 | -- |
| 62 | |
| 63 | It will setup the library and sets function for debug output from library. |
| 64 | |
| 65 | The `libperf_print` callback will receive any message with its debug level, |
| 66 | defined as: |
| 67 | |
| 68 | [source,c] |
| 69 | -- |
| 70 | enum libperf_print_level { |
| 71 | LIBPERF_ERR, |
| 72 | LIBPERF_WARN, |
| 73 | LIBPERF_INFO, |
| 74 | LIBPERF_DEBUG, |
| 75 | LIBPERF_DEBUG2, |
| 76 | LIBPERF_DEBUG3, |
| 77 | }; |
| 78 | -- |
| 79 | |
| 80 | Once the setup is complete we start by defining cycles event using the `struct perf_event_attr`: |
| 81 | |
| 82 | [source,c] |
| 83 | -- |
| 84 | 29 struct perf_event_attr attr = { |
| 85 | 30 .type = PERF_TYPE_HARDWARE, |
| 86 | 31 .config = PERF_COUNT_HW_CPU_CYCLES, |
| 87 | 32 .disabled = 1, |
| 88 | 33 .freq = 1, |
| 89 | 34 .sample_freq = 10, |
| 90 | 35 .sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_CPU|PERF_SAMPLE_PERIOD, |
| 91 | 36 }; |
| 92 | -- |
| 93 | |
| 94 | Next step is to prepare CPUs map. |
| 95 | |
| 96 | In this case we will monitor all the available CPUs: |
| 97 | |
| 98 | [source,c] |
| 99 | -- |
| 100 | 42 cpus = perf_cpu_map__new_online_cpus(); |
| 101 | 43 if (!cpus) { |
| 102 | 44 fprintf(stderr, "failed to create cpus\n"); |
| 103 | 45 return -1; |
| 104 | 46 } |
| 105 | -- |
| 106 | |
| 107 | Now we create libperf's event list, which will serve as holder for the cycles event: |
| 108 | |
| 109 | [source,c] |
| 110 | -- |
| 111 | 48 evlist = perf_evlist__new(); |
| 112 | 49 if (!evlist) { |
| 113 | 50 fprintf(stderr, "failed to create evlist\n"); |
| 114 | 51 goto out_cpus; |
| 115 | 52 } |
| 116 | -- |
| 117 | |
| 118 | We create libperf's event for the cycles attribute we defined earlier and add it to the list: |
| 119 | |
| 120 | [source,c] |
| 121 | -- |
| 122 | 54 evsel = perf_evsel__new(&attr); |
| 123 | 55 if (!evsel) { |
| 124 | 56 fprintf(stderr, "failed to create cycles\n"); |
| 125 | 57 goto out_cpus; |
| 126 | 58 } |
| 127 | 59 |
| 128 | 60 perf_evlist__add(evlist, evsel); |
| 129 | -- |
| 130 | |
| 131 | Configure event list with the cpus map and open event: |
| 132 | |
| 133 | [source,c] |
| 134 | -- |
| 135 | 62 perf_evlist__set_maps(evlist, cpus, NULL); |
| 136 | 63 |
| 137 | 64 err = perf_evlist__open(evlist); |
| 138 | 65 if (err) { |
| 139 | 66 fprintf(stderr, "failed to open evlist\n"); |
| 140 | 67 goto out_evlist; |
| 141 | 68 } |
| 142 | -- |
| 143 | |
| 144 | Once the events list is open, we can create memory maps AKA perf ring buffers: |
| 145 | |
| 146 | [source,c] |
| 147 | -- |
| 148 | 70 err = perf_evlist__mmap(evlist, 4); |
| 149 | 71 if (err) { |
| 150 | 72 fprintf(stderr, "failed to mmap evlist\n"); |
| 151 | 73 goto out_evlist; |
| 152 | 74 } |
| 153 | -- |
| 154 | |
| 155 | The event is created as disabled (note the `disabled = 1` assignment above), |
| 156 | so we need to enable the events list explicitly. |
| 157 | |
| 158 | From this moment the cycles event is sampling. |
| 159 | |
| 160 | We will sleep for 3 seconds while the ring buffers get data from all CPUs, then we disable the events list. |
| 161 | |
| 162 | [source,c] |
| 163 | -- |
| 164 | 76 perf_evlist__enable(evlist); |
| 165 | 77 sleep(3); |
| 166 | 78 perf_evlist__disable(evlist); |
| 167 | -- |
| 168 | |
| 169 | Following code walks through the ring buffers and reads stored events/samples: |
| 170 | |
| 171 | [source,c] |
| 172 | -- |
| 173 | 80 perf_evlist__for_each_mmap(evlist, map, false) { |
| 174 | 81 if (perf_mmap__read_init(map) < 0) |
| 175 | 82 continue; |
| 176 | 83 |
| 177 | 84 while ((event = perf_mmap__read_event(map)) != NULL) { |
| 178 | |
| 179 | /* process event */ |
| 180 | |
| 181 | 108 perf_mmap__consume(map); |
| 182 | 109 } |
| 183 | 110 perf_mmap__read_done(map); |
| 184 | 111 } |
| 185 | |
| 186 | -- |
| 187 | |
| 188 | Each sample needs to get parsed: |
| 189 | |
| 190 | [source,c] |
| 191 | -- |
| 192 | 85 int cpu, pid, tid; |
| 193 | 86 __u64 ip, period, *array; |
| 194 | 87 union u64_swap u; |
| 195 | 88 |
| 196 | 89 array = event->sample.array; |
| 197 | 90 |
| 198 | 91 ip = *array; |
| 199 | 92 array++; |
| 200 | 93 |
| 201 | 94 u.val64 = *array; |
| 202 | 95 pid = u.val32[0]; |
| 203 | 96 tid = u.val32[1]; |
| 204 | 97 array++; |
| 205 | 98 |
| 206 | 99 u.val64 = *array; |
| 207 | 100 cpu = u.val32[0]; |
| 208 | 101 array++; |
| 209 | 102 |
| 210 | 103 period = *array; |
| 211 | 104 |
| 212 | 105 fprintf(stdout, "cpu %3d, pid %6d, tid %6d, ip %20llx, period %20llu\n", |
| 213 | 106 cpu, pid, tid, ip, period); |
| 214 | -- |
| 215 | |
| 216 | And finally cleanup. |
| 217 | |
| 218 | We close the whole events list (both events) and remove it together with the threads map: |
| 219 | |
| 220 | [source,c] |
| 221 | -- |
| 222 | 113 out_evlist: |
| 223 | 114 perf_evlist__delete(evlist); |
| 224 | 115 out_cpus: |
| 225 | 116 perf_cpu_map__put(cpus); |
| 226 | 117 return err; |
| 227 | 118 } |
| 228 | -- |
| 229 | |
| 230 | REPORTING BUGS |
| 231 | -------------- |
| 232 | Report bugs to <[email protected]>. |
| 233 | |
| 234 | LICENSE |
| 235 | ------- |
| 236 | libperf is Free Software licensed under the GNU LGPL 2.1 |
| 237 | |
| 238 | RESOURCES |
| 239 | --------- |
| 240 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git |
| 241 | |
| 242 | SEE ALSO |
| 243 | -------- |
| 244 | libperf(3), libperf-counting(7) |