214 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 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)
 |