Commit 81de3bf3 authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo
Browse files

libperf: Add man pages



Change the man page generation to asciidoc, because it's easier to use
and has been more commonly used in related projects. Remove the current
rst pages.

Add 3 man pages to have a base for more additions:

  libperf.3          - overall description
  libperf-counting.7 - counting basics explained on simple example
  libperf-sampling.7 - sampling basics explained on simple example

The plan is to add more man pages to cover the basic API.

The build generates html and man pages:

  $ cd tools/lib/perf/Documentation
  $ make
    ASCIIDOC libperf.xml
    XMLTO    libperf.3
    ASCIIDOC libperf-counting.xml
    XMLTO    libperf-counting.7
    ASCIIDOC libperf-sampling.xml
    XMLTO    libperf-sampling.7
    ASCIIDOC libperf.html
    ASCIIDOC libperf-counting.html
    ASCIIDOC libperf-sampling.html

Add the following install targets:

   install-man      - man pages
   install-html     - html version of man pages
   install-examples - examples mentioned in the man pages

Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lore.kernel.org/lkml/20191206210612.8676-3-jolsa@kernel.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 3ce311af
Loading
Loading
Loading
Loading
+154 −5
Original line number Diff line number Diff line
all:
	rst2man man/libperf.rst > man/libperf.7
	rst2pdf tutorial/tutorial.rst
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
# Most of this file is copied from tools/perf/Documentation/Makefile

include ../../../scripts/Makefile.include
include ../../../scripts/utilities.mak

MAN3_TXT  = libperf.txt
MAN7_TXT  = libperf-counting.txt libperf-sampling.txt
MAN_EX    = examples/*.c

MAN_TXT   = $(MAN3_TXT) $(MAN7_TXT)

_MAN_XML  = $(patsubst %.txt,%.xml,$(MAN_TXT))
_MAN_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
_MAN_3    = $(patsubst %.txt,%.3,$(MAN3_TXT))
_MAN_7    = $(patsubst %.txt,%.7,$(MAN7_TXT))

MAN_XML   = $(addprefix $(OUTPUT),$(_MAN_XML))
MAN_HTML  = $(addprefix $(OUTPUT),$(_MAN_HTML))
MAN_3     = $(addprefix $(OUTPUT),$(_MAN_3))
MAN_7     = $(addprefix $(OUTPUT),$(_MAN_7))
MAN_X     = $(MAN_3) $(MAN_7)

# Make the path relative to DESTDIR, not prefix
ifndef DESTDIR
  prefix ?=$(HOME)
endif

mandir  ?= $(prefix)/share/man
man3dir  = $(mandir)/man3
man7dir  = $(mandir)/man7

docdir  ?= $(prefix)/share/doc/libperf
htmldir  = $(docdir)/html
exdir    = $(docdir)/examples

ASCIIDOC        = asciidoc
ASCIIDOC_EXTRA  = --unsafe -f asciidoc.conf
ASCIIDOC_HTML   = xhtml11
MANPAGE_XSL     = manpage-normal.xsl
XMLTO_EXTRA     =
XMLTO           =xmlto

INSTALL ?= install
RM      ?= rm -f

# For asciidoc ...
#	-7.1.2,	no extra settings are needed.
#	8.0-,	set ASCIIDOC8.
#

# For docbook-xsl ...
#	-1.68.1,	set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0)
#	1.69.0,		no extra settings are needed?
#	1.69.1-1.71.0,	set DOCBOOK_SUPPRESS_SP?
#	1.71.1,		no extra settings are needed?
#	1.72.0,		set DOCBOOK_XSL_172.
#	1.73.0-,	set ASCIIDOC_NO_ROFF

# If you had been using DOCBOOK_XSL_172 in an attempt to get rid
# of 'the ".ft C" problem' in your generated manpages, and you
# instead ended up with weird characters around callouts, try
# using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8).

ifdef ASCIIDOC8
  ASCIIDOC_EXTRA += -a asciidoc7compatible
endif
ifdef DOCBOOK_XSL_172
  ASCIIDOC_EXTRA += -a libperf-asciidoc-no-roff
  MANPAGE_XSL = manpage-1.72.xsl
else
  ifdef ASCIIDOC_NO_ROFF
    # docbook-xsl after 1.72 needs the regular XSL, but will not
    # pass-thru raw roff codes from asciidoc.conf, so turn them off.
    ASCIIDOC_EXTRA += -a libperf-asciidoc-no-roff
  endif
endif
ifdef MAN_BOLD_LITERAL
  XMLTO_EXTRA += -m manpage-bold-literal.xsl
endif
ifdef DOCBOOK_SUPPRESS_SP
  XMLTO_EXTRA += -m manpage-suppress-sp.xsl
endif

DESTDIR ?=
DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'

export DESTDIR DESTDIR_SQ

# Please note that there is a minor bug in asciidoc.
# The version after 6.0.3 _will_ include the patch found here:
#   http://marc.theaimsgroup.com/?l=libtraceevent&m=111558757202243&w=2
#
# Until that version is released you may have to apply the patch
# yourself - yes, all 6 characters of it!

QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR1  =

ifneq ($(findstring $(MAKEFLAGS),w),w)
  PRINT_DIR = --no-print-directory
else # "make -w"
  NO_SUBDIR = :
endif

ifneq ($(findstring $(MAKEFLAGS),s),s)
  ifneq ($(V),1)
    QUIET_ASCIIDOC = @echo '  ASCIIDOC '$@;
    QUIET_XMLTO    = @echo '  XMLTO    '$@;
  endif
endif

all: $(MAN_X) $(MAN_HTML)

$(MAN_HTML) $(MAN_X): asciidoc.conf

install-man: all
	$(call QUIET_INSTALL, man) \
		$(INSTALL) -d -m 755 $(DESTDIR)$(man3dir); \
		$(INSTALL) -m 644 $(MAN_3) $(DESTDIR)$(man3dir); \
		$(INSTALL) -d -m 755 $(DESTDIR)$(man7dir); \
		$(INSTALL) -m 644 $(MAN_7) $(DESTDIR)$(man7dir);

install-html:
	$(call QUIET_INSTALL, html) \
		$(INSTALL) -d -m 755 $(DESTDIR)$(htmldir); \
		$(INSTALL) -m 644 $(MAN_HTML) $(DESTDIR)$(htmldir); \

install-examples:
	$(call QUIET_INSTALL, examples) \
		$(INSTALL) -d -m 755 $(DESTDIR)$(exdir); \
		$(INSTALL) -m 644 $(MAN_EX) $(DESTDIR)$(exdir); \

CLEAN_FILES =					\
	$(MAN_XML) $(addsuffix +,$(MAN_XML))	\
	$(MAN_HTML) $(addsuffix +,$(MAN_HTML))	\
	$(MAN_X)

clean:
	rm -f man/libperf.7
	rm -f tutorial/tutorial.pdf
	$(call QUIET_CLEAN, Documentation) $(RM) $(CLEAN_FILES)

$(MAN_3): $(OUTPUT)%.3: %.xml
	$(QUIET_XMLTO)$(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<

$(MAN_7): $(OUTPUT)%.7: %.xml
	$(QUIET_XMLTO)$(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<

$(MAN_XML): $(OUTPUT)%.xml: %.txt
	$(QUIET_ASCIIDOC)$(ASCIIDOC) -b docbook -d manpage \
		$(ASCIIDOC_EXTRA) -alibperf_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \
	mv $@+ $@

$(MAN_HTML): $(OUTPUT)%.html: %.txt
	$(QUIET_ASCIIDOC)$(ASCIIDOC) -b $(ASCIIDOC_HTML) -d manpage \
	$(ASCIIDOC_EXTRA) -aperf_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \
	mv $@+ $@
+120 −0
Original line number Diff line number Diff line
## linktep: macro
#
# Usage: linktep:command[manpage-section]
#
# Note, {0} is the manpage section, while {target} is the command.
#
# Show TEP link as: <command>(<section>); if section is defined, else just show
# the command.

[macros]
(?su)[\\]?(?P<name>linktep):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=

[attributes]
asterisk=&#42;
plus=&#43;
caret=&#94;
startsb=&#91;
endsb=&#93;
tilde=&#126;

ifdef::backend-docbook[]
[linktep-inlinemacro]
{0%{target}}
{0#<citerefentry>}
{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
{0#</citerefentry>}
endif::backend-docbook[]

ifdef::backend-docbook[]
ifndef::tep-asciidoc-no-roff[]
# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
# v1.72 breaks with this because it replaces dots not in roff requests.
[listingblock]
<example><title>{title}</title>
<literallayout>
ifdef::doctype-manpage[]
&#10;.ft C&#10;
endif::doctype-manpage[]
|
ifdef::doctype-manpage[]
&#10;.ft&#10;
endif::doctype-manpage[]
</literallayout>
{title#}</example>
endif::tep-asciidoc-no-roff[]

ifdef::tep-asciidoc-no-roff[]
ifdef::doctype-manpage[]
# The following two small workarounds insert a simple paragraph after screen
[listingblock]
<example><title>{title}</title>
<literallayout>
|
</literallayout><simpara></simpara>
{title#}</example>

[verseblock]
<formalpara{id? id="{id}"}><title>{title}</title><para>
{title%}<literallayout{id? id="{id}"}>
{title#}<literallayout>
|
</literallayout>
{title#}</para></formalpara>
{title%}<simpara></simpara>
endif::doctype-manpage[]
endif::tep-asciidoc-no-roff[]
endif::backend-docbook[]

ifdef::doctype-manpage[]
ifdef::backend-docbook[]
[header]
template::[header-declarations]
<refentry>
<refmeta>
<refentrytitle>{mantitle}</refentrytitle>
<manvolnum>{manvolnum}</manvolnum>
<refmiscinfo class="source">libperf</refmiscinfo>
<refmiscinfo class="version">{libperf_version}</refmiscinfo>
<refmiscinfo class="manual">libperf Manual</refmiscinfo>
</refmeta>
<refnamediv>
  <refname>{manname1}</refname>
  <refname>{manname2}</refname>
  <refname>{manname3}</refname>
  <refname>{manname4}</refname>
  <refname>{manname5}</refname>
  <refname>{manname6}</refname>
  <refname>{manname7}</refname>
  <refname>{manname8}</refname>
  <refname>{manname9}</refname>
  <refname>{manname10}</refname>
  <refname>{manname11}</refname>
  <refname>{manname12}</refname>
  <refname>{manname13}</refname>
  <refname>{manname14}</refname>
  <refname>{manname15}</refname>
  <refname>{manname16}</refname>
  <refname>{manname17}</refname>
  <refname>{manname18}</refname>
  <refname>{manname19}</refname>
  <refname>{manname20}</refname>
  <refname>{manname21}</refname>
  <refname>{manname22}</refname>
  <refname>{manname23}</refname>
  <refname>{manname24}</refname>
  <refname>{manname25}</refname>
  <refname>{manname26}</refname>
  <refname>{manname27}</refname>
  <refname>{manname28}</refname>
  <refname>{manname29}</refname>
  <refname>{manname30}</refname>
  <refpurpose>{manpurpose}</refpurpose>
</refnamediv>
endif::backend-docbook[]
endif::doctype-manpage[]

ifdef::backend-xhtml11[]
[linktep-inlinemacro]
<a href="{target}.html">{target}{0?({0})}</a>
endif::backend-xhtml11[]
+119 −0
Original line number Diff line number Diff line
#include <linux/perf_event.h>
#include <perf/evlist.h>
#include <perf/evsel.h>
#include <perf/cpumap.h>
#include <perf/threadmap.h>
#include <perf/mmap.h>
#include <perf/core.h>
#include <perf/event.h>
#include <stdio.h>
#include <unistd.h>

static int libperf_print(enum libperf_print_level level,
                         const char *fmt, va_list ap)
{
	return vfprintf(stderr, fmt, ap);
}

union u64_swap {
	__u64 val64;
	__u32 val32[2];
};

int main(int argc, char **argv)
{
	struct perf_evlist *evlist;
	struct perf_evsel *evsel;
	struct perf_mmap *map;
	struct perf_cpu_map *cpus;
	struct perf_event_attr attr = {
		.type        = PERF_TYPE_HARDWARE,
		.config      = PERF_COUNT_HW_CPU_CYCLES,
		.disabled    = 1,
		.freq        = 1,
		.sample_freq = 10,
		.sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_CPU|PERF_SAMPLE_PERIOD,
	};
	int err = -1;
	union perf_event *event;

	libperf_init(libperf_print);

	cpus = perf_cpu_map__new(NULL);
	if (!cpus) {
		fprintf(stderr, "failed to create cpus\n");
		return -1;
	}

	evlist = perf_evlist__new();
	if (!evlist) {
		fprintf(stderr, "failed to create evlist\n");
		goto out_cpus;
	}

	evsel = perf_evsel__new(&attr);
	if (!evsel) {
		fprintf(stderr, "failed to create cycles\n");
		goto out_cpus;
	}

	perf_evlist__add(evlist, evsel);

	perf_evlist__set_maps(evlist, cpus, NULL);

	err = perf_evlist__open(evlist);
	if (err) {
		fprintf(stderr, "failed to open evlist\n");
		goto out_evlist;
	}

	err = perf_evlist__mmap(evlist, 4);
	if (err) {
		fprintf(stderr, "failed to mmap evlist\n");
		goto out_evlist;
	}

	perf_evlist__enable(evlist);
	sleep(3);
	perf_evlist__disable(evlist);

	perf_evlist__for_each_mmap(evlist, map, false) {
		if (perf_mmap__read_init(map) < 0)
			continue;

		while ((event = perf_mmap__read_event(map)) != NULL) {
			int cpu, pid, tid;
			__u64 ip, period, *array;
			union u64_swap u;

			array = event->sample.array;

			ip = *array;
			array++;

			u.val64 = *array;
			pid = u.val32[0];
			tid = u.val32[1];
			array++;

			u.val64 = *array;
			cpu = u.val32[0];
			array++;

			period = *array;

			fprintf(stdout, "cpu %3d, pid %6d, tid %6d, ip %20llx, period %20llu\n",
				cpu, pid, tid, ip, period);

			perf_mmap__consume(map);
		}

		perf_mmap__read_done(map);
	}

out_evlist:
	perf_evlist__delete(evlist);
out_cpus:
	perf_cpu_map__put(cpus);
	return err;
}
+211 −0
Original line number Diff line number Diff line
libperf-counting(7)
===================

NAME
----
libperf-counting - counting interface

DESCRIPTION
-----------
The counting interface provides API to meassure 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 libbperf 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 nutshel 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 explicitely (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 throught 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 finaly 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)
+243 −0
Original line number Diff line number Diff line
libperf-sampling(7)
===================

NAME
----
libperf-sampling - sampling interface


DESCRIPTION
-----------
The sampling interface provides API to meassure and get count for specific perf events.

The following test tries to explain count on `sampling.c` example.

It is by no means complete guide to sampling, but shows libperf basic API for sampling.

The `sampling.c` comes with libbperf package and can be compiled and run like:

[source,bash]
--
$ gcc -o sampling sampling.c -lperf
$ sudo ./sampling
cpu   0, pid      0, tid      0, ip     ffffffffad06c4e6, period                    1
cpu   0, pid   4465, tid   4469, ip     ffffffffad118748, period             18322959
cpu   0, pid      0, tid      0, ip     ffffffffad115722, period             33544846
cpu   0, pid   4465, tid   4470, ip         7f84fe0cdad6, period             23687474
cpu   0, pid      0, tid      0, ip     ffffffffad9e0349, period             34255790
cpu   0, pid   4465, tid   4469, ip     ffffffffad136581, period             38664069
cpu   0, pid      0, tid      0, ip     ffffffffad9e55e2, period             21922384
cpu   0, pid   4465, tid   4470, ip         7f84fe0ebebf, period             17655175
...
--

It requires root access, because it uses hardware cycles event.

The `sampling.c` example profiles/samples all CPUs with hardware cycles, in a nutshel it:

- creates events
- adds them to the event list
- opens and enables events through the event list
- sleeps for 3 seconds
- disables events
- reads and displays recorded samples
- destroys the event list

The first thing you need to do before using libperf is to call init function:

[source,c]
--
 12 static int libperf_print(enum libperf_print_level level,
 13                          const char *fmt, va_list ap)
 14 {
 15         return vfprintf(stderr, fmt, ap);
 16 }

 23 int main(int argc, char **argv)
 24 {
 ...
 40         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 cycles event using the `struct perf_event_attr`:

[source,c]
--
 29         struct perf_event_attr attr = {
 30                 .type        = PERF_TYPE_HARDWARE,
 31                 .config      = PERF_COUNT_HW_CPU_CYCLES,
 32                 .disabled    = 1,
 33                 .freq        = 1,
 34                 .sample_freq = 10,
 35                 .sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_CPU|PERF_SAMPLE_PERIOD,
 36         };
--

Next step is to prepare cpus map.

In this case we will monitor all the available CPUs:

[source,c]
--
 42         cpus = perf_cpu_map__new(NULL);
 43         if (!cpus) {
 44                 fprintf(stderr, "failed to create cpus\n");
 45                 return -1;
 46         }
--

Now we create libperf's event list, which will serve as holder for the cycles event:

[source,c]
--
 48         evlist = perf_evlist__new();
 49         if (!evlist) {
 50                 fprintf(stderr, "failed to create evlist\n");
 51                 goto out_cpus;
 52         }
--

We create libperf's event for the cycles attribute we defined earlier and add it to the list:

[source,c]
--
 54         evsel = perf_evsel__new(&attr);
 55         if (!evsel) {
 56                 fprintf(stderr, "failed to create cycles\n");
 57                 goto out_cpus;
 58         }
 59
 60         perf_evlist__add(evlist, evsel);
--

Configure event list with the cpus map and open event:

[source,c]
--
 62         perf_evlist__set_maps(evlist, cpus, NULL);
 63
 64         err = perf_evlist__open(evlist);
 65         if (err) {
 66                 fprintf(stderr, "failed to open evlist\n");
 67                 goto out_evlist;
 68         }
--

Once the events list is open, we can create memory maps AKA perf ring buffers:

[source,c]
--
 70         err = perf_evlist__mmap(evlist, 4);
 71         if (err) {
 72                 fprintf(stderr, "failed to mmap evlist\n");
 73                 goto out_evlist;
 74         }
--

The event is created as disabled (note the `disabled = 1` assignment above),
so we need to enable the events list explicitely.

From this moment the cycles event is sampling.

We will sleep for 3 seconds while the ring buffers get data from all CPUs, then we disable the events list.

[source,c]
--
 76         perf_evlist__enable(evlist);
 77         sleep(3);
 78         perf_evlist__disable(evlist);
--

Following code walks through the ring buffers and reads stored events/samples:

[source,c]
--
 80         perf_evlist__for_each_mmap(evlist, map, false) {
 81                 if (perf_mmap__read_init(map) < 0)
 82                         continue;
 83
 84                 while ((event = perf_mmap__read_event(map)) != NULL) {

                            /* process event */

108                         perf_mmap__consume(map);
109                 }
110                 perf_mmap__read_done(map);
111         }

--

Each sample needs to get parsed:

[source,c]
--
 85                         int cpu, pid, tid;
 86                         __u64 ip, period, *array;
 87                         union u64_swap u;
 88
 89                         array = event->sample.array;
 90
 91                         ip = *array;
 92                         array++;
 93
 94                         u.val64 = *array;
 95                         pid = u.val32[0];
 96                         tid = u.val32[1];
 97                         array++;
 98
 99                         u.val64 = *array;
100                         cpu = u.val32[0];
101                         array++;
102
103                         period = *array;
104
105                         fprintf(stdout, "cpu %3d, pid %6d, tid %6d, ip %20llx, period %20llu\n",
106                                 cpu, pid, tid, ip, period);
--

And finaly cleanup.

We close the whole events list (both events) and remove it together with the threads map:

[source,c]
--
113 out_evlist:
114         perf_evlist__delete(evlist);
115 out_cpus:
116         perf_cpu_map__put(cpus);
117         return err;
118 }
--

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-counting(7)
Loading