0001 libperf-counting(7)
0002 ===================
0003
0004 NAME
0005 ----
0006 libperf-counting - counting interface
0007
0008 DESCRIPTION
0009 -----------
0010 The counting interface provides API to measure and get count for specific perf events.
0011
0012 The following test tries to explain count on `counting.c` example.
0013
0014 It is by no means complete guide to counting, but shows libperf basic API for counting.
0015
0016 The `counting.c` comes with libperf package and can be compiled and run like:
0017
0018 [source,bash]
0019 --
0020 $ gcc -o counting counting.c -lperf
0021 $ sudo ./counting
0022 count 176792, enabled 176944, run 176944
0023 count 176242, enabled 176242, run 176242
0024 --
0025
0026 It requires root access, because of the `PERF_COUNT_SW_CPU_CLOCK` event,
0027 which is available only for root.
0028
0029 The `counting.c` example monitors two events on the current process and displays
0030 their count, in a nutshell it:
0031
0032 * creates events
0033 * adds them to the event list
0034 * opens and enables events through the event list
0035 * does some workload
0036 * disables events
0037 * reads and displays event counts
0038 * destroys the event list
0039
0040 The first thing you need to do before using libperf is to call init function:
0041
0042 [source,c]
0043 --
0044 8 static int libperf_print(enum libperf_print_level level,
0045 9 const char *fmt, va_list ap)
0046 10 {
0047 11 return vfprintf(stderr, fmt, ap);
0048 12 }
0049
0050 14 int main(int argc, char **argv)
0051 15 {
0052 ...
0053 35 libperf_init(libperf_print);
0054 --
0055
0056 It will setup the library and sets function for debug output from library.
0057
0058 The `libperf_print` callback will receive any message with its debug level,
0059 defined as:
0060
0061 [source,c]
0062 --
0063 enum libperf_print_level {
0064 LIBPERF_ERR,
0065 LIBPERF_WARN,
0066 LIBPERF_INFO,
0067 LIBPERF_DEBUG,
0068 LIBPERF_DEBUG2,
0069 LIBPERF_DEBUG3,
0070 };
0071 --
0072
0073 Once the setup is complete we start by defining specific events using the `struct perf_event_attr`.
0074
0075 We create software events for cpu and task:
0076
0077 [source,c]
0078 --
0079 20 struct perf_event_attr attr1 = {
0080 21 .type = PERF_TYPE_SOFTWARE,
0081 22 .config = PERF_COUNT_SW_CPU_CLOCK,
0082 23 .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING,
0083 24 .disabled = 1,
0084 25 };
0085 26 struct perf_event_attr attr2 = {
0086 27 .type = PERF_TYPE_SOFTWARE,
0087 28 .config = PERF_COUNT_SW_TASK_CLOCK,
0088 29 .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING,
0089 30 .disabled = 1,
0090 31 };
0091 --
0092
0093 The `read_format` setup tells perf to include timing details together with each count.
0094
0095 Next step is to prepare threads map.
0096
0097 In this case we will monitor current process, so we create threads map with single pid (0):
0098
0099 [source,c]
0100 --
0101 37 threads = perf_thread_map__new_dummy();
0102 38 if (!threads) {
0103 39 fprintf(stderr, "failed to create threads\n");
0104 40 return -1;
0105 41 }
0106 42
0107 43 perf_thread_map__set_pid(threads, 0, 0);
0108 --
0109
0110 Now we create libperf's event list, which will serve as holder for the events we want:
0111
0112 [source,c]
0113 --
0114 45 evlist = perf_evlist__new();
0115 46 if (!evlist) {
0116 47 fprintf(stderr, "failed to create evlist\n");
0117 48 goto out_threads;
0118 49 }
0119 --
0120
0121 We create libperf's events for the attributes we defined earlier and add them to the list:
0122
0123 [source,c]
0124 --
0125 51 evsel = perf_evsel__new(&attr1);
0126 52 if (!evsel) {
0127 53 fprintf(stderr, "failed to create evsel1\n");
0128 54 goto out_evlist;
0129 55 }
0130 56
0131 57 perf_evlist__add(evlist, evsel);
0132 58
0133 59 evsel = perf_evsel__new(&attr2);
0134 60 if (!evsel) {
0135 61 fprintf(stderr, "failed to create evsel2\n");
0136 62 goto out_evlist;
0137 63 }
0138 64
0139 65 perf_evlist__add(evlist, evsel);
0140 --
0141
0142 Configure event list with the thread map and open events:
0143
0144 [source,c]
0145 --
0146 67 perf_evlist__set_maps(evlist, NULL, threads);
0147 68
0148 69 err = perf_evlist__open(evlist);
0149 70 if (err) {
0150 71 fprintf(stderr, "failed to open evsel\n");
0151 72 goto out_evlist;
0152 73 }
0153 --
0154
0155 Both events are created as disabled (note the `disabled = 1` assignment above),
0156 so we need to enable the whole list explicitly (both events).
0157
0158 From this moment events are counting and we can do our workload.
0159
0160 When we are done we disable the events list.
0161
0162 [source,c]
0163 --
0164 75 perf_evlist__enable(evlist);
0165 76
0166 77 while (count--);
0167 78
0168 79 perf_evlist__disable(evlist);
0169 --
0170
0171 Now we need to get the counts from events, following code iterates through the
0172 events list and read counts:
0173
0174 [source,c]
0175 --
0176 81 perf_evlist__for_each_evsel(evlist, evsel) {
0177 82 perf_evsel__read(evsel, 0, 0, &counts);
0178 83 fprintf(stdout, "count %llu, enabled %llu, run %llu\n",
0179 84 counts.val, counts.ena, counts.run);
0180 85 }
0181 --
0182
0183 And finally cleanup.
0184
0185 We close the whole events list (both events) and remove it together with the threads map:
0186
0187 [source,c]
0188 --
0189 87 perf_evlist__close(evlist);
0190 88
0191 89 out_evlist:
0192 90 perf_evlist__delete(evlist);
0193 91 out_threads:
0194 92 perf_thread_map__put(threads);
0195 93 return err;
0196 94 }
0197 --
0198
0199 REPORTING BUGS
0200 --------------
0201 Report bugs to <linux-perf-users@vger.kernel.org>.
0202
0203 LICENSE
0204 -------
0205 libperf is Free Software licensed under the GNU LGPL 2.1
0206
0207 RESOURCES
0208 ---------
0209 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
0210
0211 SEE ALSO
0212 --------
0213 libperf(3), libperf-sampling(7)