245 lines
6.5 KiB
Plaintext
245 lines
6.5 KiB
Plaintext
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)
|