libperf-sampling(7) 
 | 
=================== 
 | 
  
 | 
NAME 
 | 
---- 
 | 
libperf-sampling - sampling interface 
 | 
  
 | 
  
 | 
DESCRIPTION 
 | 
----------- 
 | 
The sampling interface provides API to measure and get count for specific perf events. 
 | 
  
 | 
The following test tries to explain count on `sampling.c` example. 
 | 
  
 | 
It is by no means complete guide to sampling, but shows libperf basic API for sampling. 
 | 
  
 | 
The `sampling.c` comes with libperf package and can be compiled and run like: 
 | 
  
 | 
[source,bash] 
 | 
-- 
 | 
$ gcc -o sampling sampling.c -lperf 
 | 
$ sudo ./sampling 
 | 
cpu   0, pid      0, tid      0, ip     ffffffffad06c4e6, period                    1 
 | 
cpu   0, pid   4465, tid   4469, ip     ffffffffad118748, period             18322959 
 | 
cpu   0, pid      0, tid      0, ip     ffffffffad115722, period             33544846 
 | 
cpu   0, pid   4465, tid   4470, ip         7f84fe0cdad6, period             23687474 
 | 
cpu   0, pid      0, tid      0, ip     ffffffffad9e0349, period             34255790 
 | 
cpu   0, pid   4465, tid   4469, ip     ffffffffad136581, period             38664069 
 | 
cpu   0, pid      0, tid      0, ip     ffffffffad9e55e2, period             21922384 
 | 
cpu   0, pid   4465, tid   4470, ip         7f84fe0ebebf, period             17655175 
 | 
... 
 | 
-- 
 | 
  
 | 
It requires root access, because it uses hardware cycles event. 
 | 
  
 | 
The `sampling.c` example profiles/samples all CPUs with hardware cycles, in a 
 | 
nutshell it: 
 | 
  
 | 
- creates events 
 | 
- adds them to the event list 
 | 
- opens and enables events through the event list 
 | 
- sleeps for 3 seconds 
 | 
- disables events 
 | 
- reads and displays recorded samples 
 | 
- destroys the event list 
 | 
  
 | 
The first thing you need to do before using libperf is to call init function: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 12 static int libperf_print(enum libperf_print_level level, 
 | 
 13                          const char *fmt, va_list ap) 
 | 
 14 { 
 | 
 15         return vfprintf(stderr, fmt, ap); 
 | 
 16 } 
 | 
  
 | 
 23 int main(int argc, char **argv) 
 | 
 24 { 
 | 
 ... 
 | 
 40         libperf_init(libperf_print); 
 | 
-- 
 | 
  
 | 
It will setup the library and sets function for debug output from library. 
 | 
  
 | 
The `libperf_print` callback will receive any message with its debug level, 
 | 
defined as: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
enum libperf_print_level { 
 | 
        LIBPERF_ERR, 
 | 
        LIBPERF_WARN, 
 | 
        LIBPERF_INFO, 
 | 
        LIBPERF_DEBUG, 
 | 
        LIBPERF_DEBUG2, 
 | 
        LIBPERF_DEBUG3, 
 | 
}; 
 | 
-- 
 | 
  
 | 
Once the setup is complete we start by defining cycles event using the `struct perf_event_attr`: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 29         struct perf_event_attr attr = { 
 | 
 30                 .type        = PERF_TYPE_HARDWARE, 
 | 
 31                 .config      = PERF_COUNT_HW_CPU_CYCLES, 
 | 
 32                 .disabled    = 1, 
 | 
 33                 .freq        = 1, 
 | 
 34                 .sample_freq = 10, 
 | 
 35                 .sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_CPU|PERF_SAMPLE_PERIOD, 
 | 
 36         }; 
 | 
-- 
 | 
  
 | 
Next step is to prepare CPUs map. 
 | 
  
 | 
In this case we will monitor all the available CPUs: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 42         cpus = perf_cpu_map__new(NULL); 
 | 
 43         if (!cpus) { 
 | 
 44                 fprintf(stderr, "failed to create cpus\n"); 
 | 
 45                 return -1; 
 | 
 46         } 
 | 
-- 
 | 
  
 | 
Now we create libperf's event list, which will serve as holder for the cycles event: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 48         evlist = perf_evlist__new(); 
 | 
 49         if (!evlist) { 
 | 
 50                 fprintf(stderr, "failed to create evlist\n"); 
 | 
 51                 goto out_cpus; 
 | 
 52         } 
 | 
-- 
 | 
  
 | 
We create libperf's event for the cycles attribute we defined earlier and add it to the list: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 54         evsel = perf_evsel__new(&attr); 
 | 
 55         if (!evsel) { 
 | 
 56                 fprintf(stderr, "failed to create cycles\n"); 
 | 
 57                 goto out_cpus; 
 | 
 58         } 
 | 
 59 
 | 
 60         perf_evlist__add(evlist, evsel); 
 | 
-- 
 | 
  
 | 
Configure event list with the cpus map and open event: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 62         perf_evlist__set_maps(evlist, cpus, NULL); 
 | 
 63 
 | 
 64         err = perf_evlist__open(evlist); 
 | 
 65         if (err) { 
 | 
 66                 fprintf(stderr, "failed to open evlist\n"); 
 | 
 67                 goto out_evlist; 
 | 
 68         } 
 | 
-- 
 | 
  
 | 
Once the events list is open, we can create memory maps AKA perf ring buffers: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 70         err = perf_evlist__mmap(evlist, 4); 
 | 
 71         if (err) { 
 | 
 72                 fprintf(stderr, "failed to mmap evlist\n"); 
 | 
 73                 goto out_evlist; 
 | 
 74         } 
 | 
-- 
 | 
  
 | 
The event is created as disabled (note the `disabled = 1` assignment above), 
 | 
so we need to enable the events list explicitly. 
 | 
  
 | 
From this moment the cycles event is sampling. 
 | 
  
 | 
We will sleep for 3 seconds while the ring buffers get data from all CPUs, then we disable the events list. 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 76         perf_evlist__enable(evlist); 
 | 
 77         sleep(3); 
 | 
 78         perf_evlist__disable(evlist); 
 | 
-- 
 | 
  
 | 
Following code walks through the ring buffers and reads stored events/samples: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 80         perf_evlist__for_each_mmap(evlist, map, false) { 
 | 
 81                 if (perf_mmap__read_init(map) < 0) 
 | 
 82                         continue; 
 | 
 83 
 | 
 84                 while ((event = perf_mmap__read_event(map)) != NULL) { 
 | 
  
 | 
                            /* process event */ 
 | 
  
 | 
108                         perf_mmap__consume(map); 
 | 
109                 } 
 | 
110                 perf_mmap__read_done(map); 
 | 
111         } 
 | 
  
 | 
-- 
 | 
  
 | 
Each sample needs to get parsed: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
 85                         int cpu, pid, tid; 
 | 
 86                         __u64 ip, period, *array; 
 | 
 87                         union u64_swap u; 
 | 
 88 
 | 
 89                         array = event->sample.array; 
 | 
 90 
 | 
 91                         ip = *array; 
 | 
 92                         array++; 
 | 
 93 
 | 
 94                         u.val64 = *array; 
 | 
 95                         pid = u.val32[0]; 
 | 
 96                         tid = u.val32[1]; 
 | 
 97                         array++; 
 | 
 98 
 | 
 99                         u.val64 = *array; 
 | 
100                         cpu = u.val32[0]; 
 | 
101                         array++; 
 | 
102 
 | 
103                         period = *array; 
 | 
104 
 | 
105                         fprintf(stdout, "cpu %3d, pid %6d, tid %6d, ip %20llx, period %20llu\n", 
 | 
106                                 cpu, pid, tid, ip, period); 
 | 
-- 
 | 
  
 | 
And finally cleanup. 
 | 
  
 | 
We close the whole events list (both events) and remove it together with the threads map: 
 | 
  
 | 
[source,c] 
 | 
-- 
 | 
113 out_evlist: 
 | 
114         perf_evlist__delete(evlist); 
 | 
115 out_cpus: 
 | 
116         perf_cpu_map__put(cpus); 
 | 
117         return err; 
 | 
118 } 
 | 
-- 
 | 
  
 | 
REPORTING BUGS 
 | 
-------------- 
 | 
Report bugs to <linux-perf-users@vger.kernel.org>. 
 | 
  
 | 
LICENSE 
 | 
------- 
 | 
libperf is Free Software licensed under the GNU LGPL 2.1 
 | 
  
 | 
RESOURCES 
 | 
--------- 
 | 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 
 | 
  
 | 
SEE ALSO 
 | 
-------- 
 | 
libperf(3), libperf-counting(7) 
 |