forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
5.5 KiB
213 lines
5.5 KiB
libperf-counting(7) |
|
=================== |
|
|
|
NAME |
|
---- |
|
libperf-counting - counting interface |
|
|
|
DESCRIPTION |
|
----------- |
|
The counting interface provides API to measure and get count for specific perf events. |
|
|
|
The following test tries to explain count on `counting.c` example. |
|
|
|
It is by no means complete guide to counting, but shows libperf basic API for counting. |
|
|
|
The `counting.c` comes with libperf package and can be compiled and run like: |
|
|
|
[source,bash] |
|
-- |
|
$ gcc -o counting counting.c -lperf |
|
$ sudo ./counting |
|
count 176792, enabled 176944, run 176944 |
|
count 176242, enabled 176242, run 176242 |
|
-- |
|
|
|
It requires root access, because of the `PERF_COUNT_SW_CPU_CLOCK` event, |
|
which is available only for root. |
|
|
|
The `counting.c` example monitors two events on the current process and displays |
|
their count, in a nutshell it: |
|
|
|
* creates events |
|
* adds them to the event list |
|
* opens and enables events through the event list |
|
* does some workload |
|
* disables events |
|
* reads and displays event counts |
|
* destroys the event list |
|
|
|
The first thing you need to do before using libperf is to call init function: |
|
|
|
[source,c] |
|
-- |
|
8 static int libperf_print(enum libperf_print_level level, |
|
9 const char *fmt, va_list ap) |
|
10 { |
|
11 return vfprintf(stderr, fmt, ap); |
|
12 } |
|
|
|
14 int main(int argc, char **argv) |
|
15 { |
|
... |
|
35 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 specific events using the `struct perf_event_attr`. |
|
|
|
We create software events for cpu and task: |
|
|
|
[source,c] |
|
-- |
|
20 struct perf_event_attr attr1 = { |
|
21 .type = PERF_TYPE_SOFTWARE, |
|
22 .config = PERF_COUNT_SW_CPU_CLOCK, |
|
23 .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING, |
|
24 .disabled = 1, |
|
25 }; |
|
26 struct perf_event_attr attr2 = { |
|
27 .type = PERF_TYPE_SOFTWARE, |
|
28 .config = PERF_COUNT_SW_TASK_CLOCK, |
|
29 .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING, |
|
30 .disabled = 1, |
|
31 }; |
|
-- |
|
|
|
The `read_format` setup tells perf to include timing details together with each count. |
|
|
|
Next step is to prepare threads map. |
|
|
|
In this case we will monitor current process, so we create threads map with single pid (0): |
|
|
|
[source,c] |
|
-- |
|
37 threads = perf_thread_map__new_dummy(); |
|
38 if (!threads) { |
|
39 fprintf(stderr, "failed to create threads\n"); |
|
40 return -1; |
|
41 } |
|
42 |
|
43 perf_thread_map__set_pid(threads, 0, 0); |
|
-- |
|
|
|
Now we create libperf's event list, which will serve as holder for the events we want: |
|
|
|
[source,c] |
|
-- |
|
45 evlist = perf_evlist__new(); |
|
46 if (!evlist) { |
|
47 fprintf(stderr, "failed to create evlist\n"); |
|
48 goto out_threads; |
|
49 } |
|
-- |
|
|
|
We create libperf's events for the attributes we defined earlier and add them to the list: |
|
|
|
[source,c] |
|
-- |
|
51 evsel = perf_evsel__new(&attr1); |
|
52 if (!evsel) { |
|
53 fprintf(stderr, "failed to create evsel1\n"); |
|
54 goto out_evlist; |
|
55 } |
|
56 |
|
57 perf_evlist__add(evlist, evsel); |
|
58 |
|
59 evsel = perf_evsel__new(&attr2); |
|
60 if (!evsel) { |
|
61 fprintf(stderr, "failed to create evsel2\n"); |
|
62 goto out_evlist; |
|
63 } |
|
64 |
|
65 perf_evlist__add(evlist, evsel); |
|
-- |
|
|
|
Configure event list with the thread map and open events: |
|
|
|
[source,c] |
|
-- |
|
67 perf_evlist__set_maps(evlist, NULL, threads); |
|
68 |
|
69 err = perf_evlist__open(evlist); |
|
70 if (err) { |
|
71 fprintf(stderr, "failed to open evsel\n"); |
|
72 goto out_evlist; |
|
73 } |
|
-- |
|
|
|
Both events are created as disabled (note the `disabled = 1` assignment above), |
|
so we need to enable the whole list explicitly (both events). |
|
|
|
From this moment events are counting and we can do our workload. |
|
|
|
When we are done we disable the events list. |
|
|
|
[source,c] |
|
-- |
|
75 perf_evlist__enable(evlist); |
|
76 |
|
77 while (count--); |
|
78 |
|
79 perf_evlist__disable(evlist); |
|
-- |
|
|
|
Now we need to get the counts from events, following code iterates through the |
|
events list and read counts: |
|
|
|
[source,c] |
|
-- |
|
81 perf_evlist__for_each_evsel(evlist, evsel) { |
|
82 perf_evsel__read(evsel, 0, 0, &counts); |
|
83 fprintf(stdout, "count %llu, enabled %llu, run %llu\n", |
|
84 counts.val, counts.ena, counts.run); |
|
85 } |
|
-- |
|
|
|
And finally cleanup. |
|
|
|
We close the whole events list (both events) and remove it together with the threads map: |
|
|
|
[source,c] |
|
-- |
|
87 perf_evlist__close(evlist); |
|
88 |
|
89 out_evlist: |
|
90 perf_evlist__delete(evlist); |
|
91 out_threads: |
|
92 perf_thread_map__put(threads); |
|
93 return err; |
|
94 } |
|
-- |
|
|
|
REPORTING BUGS |
|
-------------- |
|
Report bugs to <[email protected]>. |
|
|
|
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-sampling(7)
|
|
|