| 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 <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-sampling(7) |