LIBPERF-COUNTING(7)
π LIBPERF-COUNTING β the counting interface, explained by your resident Unix bestie
okay so this is the libperf manual, page libperf-counting(7) β literally the counting interface, and it's giving tutorial energy today. buckle up, bestie, we're measuring perf events and we're gonna slay it β¨
πΈ NAME πΈ
libperf-counting β the counting interface. that's it, that's the vibe π
π DESCRIPTION π
the counting interface hands you an API to measure specific perf events and get their count. no cap.
the test below tries to explain counting on the counting.c example. heads up though β it is by no means a complete guide to counting, it just shows off the basic libperf API for counting. lowkey iconic of it.
counting.c ships with the libperf package and you can compile and run it like this:
$ 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 thePERF_COUNT_SW_CPU_CLOCKevent, which is available only for root. sorry bestie,sudoor nothing π₯
counting.c 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
π¦ step one: init the library π¦
the first thing you need to do before using libperf is to call the init function:
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 set up the library and set the function for debug output from the library. so thoughtful of it π«Ά
the libperf_print callback will receive any message with its debug level, defined as:
enum libperf_print_level {
LIBPERF_ERR,
LIBPERF_WARN,
LIBPERF_INFO,
LIBPERF_DEBUG,
LIBPERF_DEBUG2,
LIBPERF_DEBUG3,
};
π§ step two: define your events π§
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:
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. timing details + count = the full picture, iykyk π
π step three: threads map π
next step is to prepare the threads map.
in this case we will monitor the current process, so we create a threads map with a single pid (0):
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);
π step four: the event list π
now we create libperf's event list, which will serve as the holder for the events we want:
45 evlist = perf_evlist__new();
46 if (!evlist) {
47 fprintf(stderr, "failed to create evlist\n");
48 goto out_threads;
49 }
β step five: make the events, add the events β
we create libperf's events for the attributes we defined earlier and add them to the list:
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);
π step six: configure + open π
configure the event list with the thread map and open the events:
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 }
π step seven: do the workload π
both events are created as disabled (note the disabled = 1 assignment up above), so we need to enable the whole list explicitly β both events, bestie, not just one.
from this moment the events are counting and we can do our workload. main character energy fr fr π
when we are done we disable the events list.
75 perf_evlist__enable(evlist);
76
77 while (count--);
78
79 perf_evlist__disable(evlist);
π₯ step eight: read the counts π₯
now we need to get the counts from the events. the following code iterates through the events list and reads the counts:
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 }
π«Ά step nine: and finally, cleanup π«Ά
we close the whole events list (both events) and remove it together with the threads map:
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 }
ate. no crumbs. β¨
π REPORTING BUGS π
report bugs to <linux-perf-users@vger.kernel.org[1]>. they're nice, i promise. π
π 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 πΈ
π NOTES π
linux-perf-users@vger.kernel.orgβmailto:linux-perf-users@vger.kernel.org
and that's the whole page, bestie π§ this little beauty is from libperf, dated 11/01/2026, and it's filed under LIBPERF-COUNTING(7). go forth and count. ππβ¨
π¦ where this page comes from
- fedora 43: libperf-devel 7.2.15-100.fc43 Β· ((GPL-2.0-only WITH Linux-syscall-note) OR CDDL-1.0) AND ((GPL-2.0-only WITH Linux-syscall-note) OR Linux-OpenIB) AND 0BSD AND Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND BSD-3-Clause-Clear AND CC0-1.0 AND GFDL-1.1-no-invariants-or-later AND GPL-1.0-or-later AND (GPL-1.0-or-later WITH Linux-syscall-note) AND GPL-2.0-only AND (GPL-2.0-only OR CDDL-1.0) AND (GPL-2.0-only OR GFDL-1.2-no-invariants-only) AND (GPL-2.0-only OR GFDL-1.2-no-invariants-or-later) AND (GPL-2.0-only WITH Linux-syscall-note) AND GPL-2.0-or-later AND (GPL-2.0-or-later OR CC-BY-4.0) AND (GPL-2.0-or-later WITH GCC-exception-2.0) AND (GPL-2.0-or-later WITH Linux-syscall-note) AND ISC AND LGPL-2.0-or-later AND (LGPL-2.0-or-later WITH Linux-syscall-note) AND LGPL-2.1-only AND (LGPL-2.1-only WITH Linux-syscall-note) AND LGPL-2.1-or-later AND (LGPL-2.1-or-later WITH Linux-syscall-note) AND (Linux-OpenIB OR GPL-2.0-only) AND (Linux-OpenIB OR GPL-2.0-only OR BSD-2-Clause) AND Linux-man-pages-copyleft AND MIT AND (MPL-1.1 OR GPL-2.0-only) AND (X11 OR GPL-2.0-only) AND (X11 OR GPL-2.0-or-later) AND Zlib AND (copyleft-next-0.3.1 OR GPL-2.0-or-later)
- fedora 44: libperf-devel 7.2.15-200.fc44 Β· ((GPL-2.0-only WITH Linux-syscall-note) OR CDDL-1.0) AND ((GPL-2.0-only WITH Linux-syscall-note) OR Linux-OpenIB) AND 0BSD AND Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND BSD-3-Clause-Clear AND CC0-1.0 AND GFDL-1.1-no-invariants-or-later AND GPL-1.0-or-later AND (GPL-1.0-or-later WITH Linux-syscall-note) AND GPL-2.0-only AND (GPL-2.0-only OR CDDL-1.0) AND (GPL-2.0-only OR GFDL-1.2-no-invariants-only) AND (GPL-2.0-only OR GFDL-1.2-no-invariants-or-later) AND (GPL-2.0-only WITH Linux-syscall-note) AND GPL-2.0-or-later AND (GPL-2.0-or-later OR CC-BY-4.0) AND (GPL-2.0-or-later WITH GCC-exception-2.0) AND (GPL-2.0-or-later WITH Linux-syscall-note) AND ISC AND LGPL-2.0-or-later AND (LGPL-2.0-or-later WITH Linux-syscall-note) AND LGPL-2.1-only AND (LGPL-2.1-only WITH Linux-syscall-note) AND LGPL-2.1-or-later AND (LGPL-2.1-or-later WITH Linux-syscall-note) AND (Linux-OpenIB OR GPL-2.0-only) AND (Linux-OpenIB OR GPL-2.0-only OR BSD-2-Clause) AND Linux-man-pages-copyleft AND MIT AND (MPL-1.1 OR GPL-2.0-only) AND (X11 OR GPL-2.0-only) AND (X11 OR GPL-2.0-or-later) AND Zlib AND (copyleft-next-0.3.1 OR GPL-2.0-or-later)
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms