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: Jiri 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: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
3ce311afb5
commit
81de3bf37a
|
@ -1,7 +1,156 @@
|
|||
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 $@+ $@
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
## 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=*
|
||||
plus=+
|
||||
caret=^
|
||||
startsb=[
|
||||
endsb=]
|
||||
tilde=~
|
||||
|
||||
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[]
|
||||
.ft C
|
||||
endif::doctype-manpage[]
|
||||
|
|
||||
ifdef::doctype-manpage[]
|
||||
.ft
|
||||
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[]
|
|
@ -0,0 +1,119 @@
|
|||
#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;
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
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)
|
|
@ -0,0 +1,243 @@
|
|||
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)
|
|
@ -0,0 +1,246 @@
|
|||
libperf(3)
|
||||
==========
|
||||
|
||||
NAME
|
||||
----
|
||||
libperf - Linux kernel perf event library
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*Generic API:*
|
||||
|
||||
[source,c]
|
||||
--
|
||||
#include <perf/core.h>
|
||||
|
||||
enum libperf_print_level {
|
||||
LIBPERF_ERR,
|
||||
LIBPERF_WARN,
|
||||
LIBPERF_INFO,
|
||||
LIBPERF_DEBUG,
|
||||
LIBPERF_DEBUG2,
|
||||
LIBPERF_DEBUG3,
|
||||
};
|
||||
|
||||
typedef int (*libperf_print_fn_t)(enum libperf_print_level level,
|
||||
const char *, va_list ap);
|
||||
|
||||
void libperf_init(libperf_print_fn_t fn);
|
||||
--
|
||||
|
||||
*API to handle cpu maps:*
|
||||
|
||||
[source,c]
|
||||
--
|
||||
#include <perf/cpumap.h>
|
||||
|
||||
struct perf_cpu_map;
|
||||
|
||||
struct perf_cpu_map *perf_cpu_map__dummy_new(void);
|
||||
struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
|
||||
struct perf_cpu_map *perf_cpu_map__read(FILE *file);
|
||||
struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
|
||||
struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
|
||||
struct perf_cpu_map *other);
|
||||
void perf_cpu_map__put(struct perf_cpu_map *map);
|
||||
int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
|
||||
int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
|
||||
bool perf_cpu_map__empty(const struct perf_cpu_map *map);
|
||||
int perf_cpu_map__max(struct perf_cpu_map *map);
|
||||
|
||||
#define perf_cpu_map__for_each_cpu(cpu, idx, cpus)
|
||||
--
|
||||
|
||||
*API to handle thread maps:*
|
||||
|
||||
[source,c]
|
||||
--
|
||||
#include <perf/threadmap.h>
|
||||
|
||||
struct perf_thread_map;
|
||||
|
||||
struct perf_thread_map *perf_thread_map__new_dummy(void);
|
||||
|
||||
void perf_thread_map__set_pid(struct perf_thread_map *map, int thread, pid_t pid);
|
||||
char *perf_thread_map__comm(struct perf_thread_map *map, int thread);
|
||||
int perf_thread_map__nr(struct perf_thread_map *threads);
|
||||
pid_t perf_thread_map__pid(struct perf_thread_map *map, int thread);
|
||||
|
||||
struct perf_thread_map *perf_thread_map__get(struct perf_thread_map *map);
|
||||
void perf_thread_map__put(struct perf_thread_map *map);
|
||||
--
|
||||
|
||||
*API to handle event lists:*
|
||||
|
||||
[source,c]
|
||||
--
|
||||
#include <perf/evlist.h>
|
||||
|
||||
struct perf_evlist;
|
||||
|
||||
void perf_evlist__add(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel);
|
||||
void perf_evlist__remove(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel);
|
||||
struct perf_evlist *perf_evlist__new(void);
|
||||
void perf_evlist__delete(struct perf_evlist *evlist);
|
||||
struct perf_evsel* perf_evlist__next(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel);
|
||||
int perf_evlist__open(struct perf_evlist *evlist);
|
||||
void perf_evlist__close(struct perf_evlist *evlist);
|
||||
void perf_evlist__enable(struct perf_evlist *evlist);
|
||||
void perf_evlist__disable(struct perf_evlist *evlist);
|
||||
|
||||
#define perf_evlist__for_each_evsel(evlist, pos)
|
||||
|
||||
void perf_evlist__set_maps(struct perf_evlist *evlist,
|
||||
struct perf_cpu_map *cpus,
|
||||
struct perf_thread_map *threads);
|
||||
int perf_evlist__poll(struct perf_evlist *evlist, int timeout);
|
||||
int perf_evlist__filter_pollfd(struct perf_evlist *evlist,
|
||||
short revents_and_mask);
|
||||
|
||||
int perf_evlist__mmap(struct perf_evlist *evlist, int pages);
|
||||
void perf_evlist__munmap(struct perf_evlist *evlist);
|
||||
|
||||
struct perf_mmap *perf_evlist__next_mmap(struct perf_evlist *evlist,
|
||||
struct perf_mmap *map,
|
||||
bool overwrite);
|
||||
|
||||
#define perf_evlist__for_each_mmap(evlist, pos, overwrite)
|
||||
--
|
||||
|
||||
*API to handle events:*
|
||||
|
||||
[source,c]
|
||||
--
|
||||
#include <perf/evsel.h>*
|
||||
|
||||
struct perf_evsel;
|
||||
|
||||
struct perf_counts_values {
|
||||
union {
|
||||
struct {
|
||||
uint64_t val;
|
||||
uint64_t ena;
|
||||
uint64_t run;
|
||||
};
|
||||
uint64_t values[3];
|
||||
};
|
||||
};
|
||||
|
||||
struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr);
|
||||
void perf_evsel__delete(struct perf_evsel *evsel);
|
||||
int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
|
||||
struct perf_thread_map *threads);
|
||||
void perf_evsel__close(struct perf_evsel *evsel);
|
||||
void perf_evsel__close_cpu(struct perf_evsel *evsel, int cpu);
|
||||
int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
|
||||
struct perf_counts_values *count);
|
||||
int perf_evsel__enable(struct perf_evsel *evsel);
|
||||
int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu);
|
||||
int perf_evsel__disable(struct perf_evsel *evsel);
|
||||
int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu);
|
||||
struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
|
||||
struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel);
|
||||
struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel);
|
||||
--
|
||||
|
||||
*API to handle maps (perf ring buffers):*
|
||||
|
||||
[source,c]
|
||||
--
|
||||
#include <perf/mmap.h>
|
||||
|
||||
struct perf_mmap;
|
||||
|
||||
void perf_mmap__consume(struct perf_mmap *map);
|
||||
int perf_mmap__read_init(struct perf_mmap *map);
|
||||
void perf_mmap__read_done(struct perf_mmap *map);
|
||||
union perf_event *perf_mmap__read_event(struct perf_mmap *map);
|
||||
--
|
||||
|
||||
*Structures to access perf API events:*
|
||||
|
||||
[source,c]
|
||||
--
|
||||
#include <perf/event.h>
|
||||
|
||||
struct perf_record_mmap;
|
||||
struct perf_record_mmap2;
|
||||
struct perf_record_comm;
|
||||
struct perf_record_namespaces;
|
||||
struct perf_record_fork;
|
||||
struct perf_record_lost;
|
||||
struct perf_record_lost_samples;
|
||||
struct perf_record_read;
|
||||
struct perf_record_throttle;
|
||||
struct perf_record_ksymbol;
|
||||
struct perf_record_bpf_event;
|
||||
struct perf_record_sample;
|
||||
struct perf_record_switch;
|
||||
struct perf_record_header_attr;
|
||||
struct perf_record_record_cpu_map;
|
||||
struct perf_record_cpu_map_data;
|
||||
struct perf_record_cpu_map;
|
||||
struct perf_record_event_update_cpus;
|
||||
struct perf_record_event_update_scale;
|
||||
struct perf_record_event_update;
|
||||
struct perf_trace_event_type;
|
||||
struct perf_record_header_event_type;
|
||||
struct perf_record_header_tracing_data;
|
||||
struct perf_record_header_build_id;
|
||||
struct perf_record_id_index;
|
||||
struct perf_record_auxtrace_info;
|
||||
struct perf_record_auxtrace;
|
||||
struct perf_record_auxtrace_error;
|
||||
struct perf_record_aux;
|
||||
struct perf_record_itrace_start;
|
||||
struct perf_record_thread_map_entry;
|
||||
struct perf_record_thread_map;
|
||||
struct perf_record_stat_config_entry;
|
||||
struct perf_record_stat_config;
|
||||
struct perf_record_stat;
|
||||
struct perf_record_stat_round;
|
||||
struct perf_record_time_conv;
|
||||
struct perf_record_header_feature;
|
||||
struct perf_record_compressed;
|
||||
--
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The libperf library provides an API to access the linux kernel perf
|
||||
events subsystem.
|
||||
|
||||
Following objects are key to the libperf interface:
|
||||
|
||||
[horizontal]
|
||||
|
||||
struct perf_cpu_map:: Provides a cpu list abstraction.
|
||||
|
||||
struct perf_thread_map:: Provides a thread list abstraction.
|
||||
|
||||
struct perf_evsel:: Provides an abstraction for single a perf event.
|
||||
|
||||
struct perf_evlist:: Gathers several struct perf_evsel object and performs functions on all of them.
|
||||
|
||||
struct perf_mmap:: Provides an abstraction for accessing perf ring buffer.
|
||||
|
||||
The exported API functions bind these objects together.
|
||||
|
||||
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-sampling(7), libperf-counting(7)
|
|
@ -1,100 +0,0 @@
|
|||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
libperf
|
||||
|
||||
The libperf library provides an API to access the linux kernel perf
|
||||
events subsystem. It provides the following high level objects:
|
||||
|
||||
- struct perf_cpu_map
|
||||
- struct perf_thread_map
|
||||
- struct perf_evlist
|
||||
- struct perf_evsel
|
||||
|
||||
reference
|
||||
=========
|
||||
Function reference by header files:
|
||||
|
||||
perf/core.h
|
||||
-----------
|
||||
.. code-block:: c
|
||||
|
||||
typedef int (\*libperf_print_fn_t)(enum libperf_print_level level,
|
||||
const char \*, va_list ap);
|
||||
|
||||
void libperf_set_print(libperf_print_fn_t fn);
|
||||
|
||||
perf/cpumap.h
|
||||
-------------
|
||||
.. code-block:: c
|
||||
|
||||
struct perf_cpu_map \*perf_cpu_map__dummy_new(void);
|
||||
struct perf_cpu_map \*perf_cpu_map__new(const char \*cpu_list);
|
||||
struct perf_cpu_map \*perf_cpu_map__read(FILE \*file);
|
||||
struct perf_cpu_map \*perf_cpu_map__get(struct perf_cpu_map \*map);
|
||||
void perf_cpu_map__put(struct perf_cpu_map \*map);
|
||||
int perf_cpu_map__cpu(const struct perf_cpu_map \*cpus, int idx);
|
||||
int perf_cpu_map__nr(const struct perf_cpu_map \*cpus);
|
||||
perf_cpu_map__for_each_cpu(cpu, idx, cpus)
|
||||
|
||||
perf/threadmap.h
|
||||
----------------
|
||||
.. code-block:: c
|
||||
|
||||
struct perf_thread_map \*perf_thread_map__new_dummy(void);
|
||||
void perf_thread_map__set_pid(struct perf_thread_map \*map, int thread, pid_t pid);
|
||||
char \*perf_thread_map__comm(struct perf_thread_map \*map, int thread);
|
||||
struct perf_thread_map \*perf_thread_map__get(struct perf_thread_map \*map);
|
||||
void perf_thread_map__put(struct perf_thread_map \*map);
|
||||
|
||||
perf/evlist.h
|
||||
-------------
|
||||
.. code-block::
|
||||
|
||||
void perf_evlist__init(struct perf_evlist \*evlist);
|
||||
void perf_evlist__add(struct perf_evlist \*evlist,
|
||||
struct perf_evsel \*evsel);
|
||||
void perf_evlist__remove(struct perf_evlist \*evlist,
|
||||
struct perf_evsel \*evsel);
|
||||
struct perf_evlist \*perf_evlist__new(void);
|
||||
void perf_evlist__delete(struct perf_evlist \*evlist);
|
||||
struct perf_evsel\* perf_evlist__next(struct perf_evlist \*evlist,
|
||||
struct perf_evsel \*evsel);
|
||||
int perf_evlist__open(struct perf_evlist \*evlist);
|
||||
void perf_evlist__close(struct perf_evlist \*evlist);
|
||||
void perf_evlist__enable(struct perf_evlist \*evlist);
|
||||
void perf_evlist__disable(struct perf_evlist \*evlist);
|
||||
perf_evlist__for_each_evsel(evlist, pos)
|
||||
void perf_evlist__set_maps(struct perf_evlist \*evlist,
|
||||
struct perf_cpu_map \*cpus,
|
||||
struct perf_thread_map \*threads);
|
||||
|
||||
perf/evsel.h
|
||||
------------
|
||||
.. code-block:: c
|
||||
|
||||
struct perf_counts_values {
|
||||
union {
|
||||
struct {
|
||||
uint64_t val;
|
||||
uint64_t ena;
|
||||
uint64_t run;
|
||||
};
|
||||
uint64_t values[3];
|
||||
};
|
||||
};
|
||||
|
||||
void perf_evsel__init(struct perf_evsel \*evsel,
|
||||
struct perf_event_attr \*attr);
|
||||
struct perf_evsel \*perf_evsel__new(struct perf_event_attr \*attr);
|
||||
void perf_evsel__delete(struct perf_evsel \*evsel);
|
||||
int perf_evsel__open(struct perf_evsel \*evsel, struct perf_cpu_map \*cpus,
|
||||
struct perf_thread_map \*threads);
|
||||
void perf_evsel__close(struct perf_evsel \*evsel);
|
||||
int perf_evsel__read(struct perf_evsel \*evsel, int cpu, int thread,
|
||||
struct perf_counts_values \*count);
|
||||
int perf_evsel__enable(struct perf_evsel \*evsel);
|
||||
int perf_evsel__disable(struct perf_evsel \*evsel);
|
||||
int perf_evsel__apply_filter(struct perf_evsel \*evsel, const char \*filter);
|
||||
struct perf_cpu_map \*perf_evsel__cpus(struct perf_evsel \*evsel);
|
||||
struct perf_thread_map \*perf_evsel__threads(struct perf_evsel \*evsel);
|
||||
struct perf_event_attr \*perf_evsel__attr(struct perf_evsel \*evsel);
|
|
@ -0,0 +1,14 @@
|
|||
<!-- manpage-1.72.xsl:
|
||||
special settings for manpages rendered from asciidoc+docbook
|
||||
handles peculiarities in docbook-xsl 1.72.0 -->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<xsl:import href="manpage-base.xsl"/>
|
||||
|
||||
<!-- these are the special values for the roff control characters
|
||||
needed for docbook-xsl 1.72.0 -->
|
||||
<xsl:param name="git.docbook.backslash">▓</xsl:param>
|
||||
<xsl:param name="git.docbook.dot" >⌂</xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,35 @@
|
|||
<!-- manpage-base.xsl:
|
||||
special formatting for manpages rendered from asciidoc+docbook -->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<!-- these params silence some output from xmlto -->
|
||||
<xsl:param name="man.output.quietly" select="1"/>
|
||||
<xsl:param name="refentry.meta.get.quietly" select="1"/>
|
||||
|
||||
<!-- convert asciidoc callouts to man page format;
|
||||
git.docbook.backslash and git.docbook.dot params
|
||||
must be supplied by another XSL file or other means -->
|
||||
<xsl:template match="co">
|
||||
<xsl:value-of select="concat(
|
||||
$git.docbook.backslash,'fB(',
|
||||
substring-after(@id,'-'),')',
|
||||
$git.docbook.backslash,'fR')"/>
|
||||
</xsl:template>
|
||||
<xsl:template match="calloutlist">
|
||||
<xsl:value-of select="$git.docbook.dot"/>
|
||||
<xsl:text>sp </xsl:text>
|
||||
<xsl:apply-templates/>
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:template>
|
||||
<xsl:template match="callout">
|
||||
<xsl:value-of select="concat(
|
||||
$git.docbook.backslash,'fB',
|
||||
substring-after(@arearefs,'-'),
|
||||
'. ',$git.docbook.backslash,'fR')"/>
|
||||
<xsl:apply-templates/>
|
||||
<xsl:value-of select="$git.docbook.dot"/>
|
||||
<xsl:text>br </xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,17 @@
|
|||
<!-- manpage-bold-literal.xsl:
|
||||
special formatting for manpages rendered from asciidoc+docbook -->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<!-- render literal text as bold (instead of plain or monospace);
|
||||
this makes literal text easier to distinguish in manpages
|
||||
viewed on a tty -->
|
||||
<xsl:template match="literal">
|
||||
<xsl:value-of select="$git.docbook.backslash"/>
|
||||
<xsl:text>fB</xsl:text>
|
||||
<xsl:apply-templates/>
|
||||
<xsl:value-of select="$git.docbook.backslash"/>
|
||||
<xsl:text>fR</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,13 @@
|
|||
<!-- manpage-normal.xsl:
|
||||
special settings for manpages rendered from asciidoc+docbook
|
||||
handles anything we want to keep away from docbook-xsl 1.72.0 -->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<xsl:import href="manpage-base.xsl"/>
|
||||
|
||||
<!-- these are the normal values for the roff control characters -->
|
||||
<xsl:param name="git.docbook.backslash">\</xsl:param>
|
||||
<xsl:param name="git.docbook.dot" >.</xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,21 @@
|
|||
<!-- manpage-suppress-sp.xsl:
|
||||
special settings for manpages rendered from asciidoc+docbook
|
||||
handles erroneous, inline .sp in manpage output of some
|
||||
versions of docbook-xsl -->
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0">
|
||||
|
||||
<!-- attempt to work around spurious .sp at the tail of the line
|
||||
that some versions of docbook stylesheets seem to add -->
|
||||
<xsl:template match="simpara">
|
||||
<xsl:variable name="content">
|
||||
<xsl:apply-templates/>
|
||||
</xsl:variable>
|
||||
<xsl:value-of select="normalize-space($content)"/>
|
||||
<xsl:if test="not(ancestor::authorblurb) and
|
||||
not(ancestor::personblurb)">
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -1,123 +0,0 @@
|
|||
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||
|
||||
libperf tutorial
|
||||
================
|
||||
|
||||
Compile and install libperf from kernel sources
|
||||
===============================================
|
||||
.. code-block:: bash
|
||||
|
||||
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
||||
cd linux/tools/perf/lib
|
||||
make
|
||||
sudo make install prefix=/usr
|
||||
|
||||
Libperf object
|
||||
==============
|
||||
The libperf library provides several high level objects:
|
||||
|
||||
struct perf_cpu_map
|
||||
Provides a cpu list abstraction.
|
||||
|
||||
struct perf_thread_map
|
||||
Provides a thread list abstraction.
|
||||
|
||||
struct perf_evsel
|
||||
Provides an abstraction for single a perf event.
|
||||
|
||||
struct perf_evlist
|
||||
Gathers several struct perf_evsel object and performs functions on all of them.
|
||||
|
||||
The exported API binds these objects together,
|
||||
for full reference see the libperf.7 man page.
|
||||
|
||||
Examples
|
||||
========
|
||||
Examples aim to explain libperf functionality on simple use cases.
|
||||
They are based in on a checked out linux kernel git tree:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd tools/perf/lib/Documentation/tutorial/
|
||||
$ ls -d ex-*
|
||||
ex-1-compile ex-2-evsel-stat ex-3-evlist-stat
|
||||
|
||||
ex-1-compile example
|
||||
====================
|
||||
This example shows the basic usage of *struct perf_cpu_map*,
|
||||
how to create it and display its cpus:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd ex-1-compile/
|
||||
$ make
|
||||
gcc -o test test.c -lperf
|
||||
$ ./test
|
||||
0 1 2 3 4 5 6 7
|
||||
|
||||
|
||||
The full code listing is here:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
1 #include <perf/cpumap.h>
|
||||
2
|
||||
3 int main(int argc, char **Argv)
|
||||
4 {
|
||||
5 struct perf_cpu_map *cpus;
|
||||
6 int cpu, tmp;
|
||||
7
|
||||
8 cpus = perf_cpu_map__new(NULL);
|
||||
9
|
||||
10 perf_cpu_map__for_each_cpu(cpu, tmp, cpus)
|
||||
11 fprintf(stdout, "%d ", cpu);
|
||||
12
|
||||
13 fprintf(stdout, "\n");
|
||||
14
|
||||
15 perf_cpu_map__put(cpus);
|
||||
16 return 0;
|
||||
17 }
|
||||
|
||||
|
||||
First you need to include the proper header to have *struct perf_cpumap*
|
||||
declaration and functions:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
1 #include <perf/cpumap.h>
|
||||
|
||||
|
||||
The *struct perf_cpumap* object is created by *perf_cpu_map__new* call.
|
||||
The *NULL* argument asks it to populate the object with the current online CPUs list:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
8 cpus = perf_cpu_map__new(NULL);
|
||||
|
||||
This is paired with a *perf_cpu_map__put*, that drops its reference at the end, possibly deleting it.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
15 perf_cpu_map__put(cpus);
|
||||
|
||||
The iteration through the *struct perf_cpumap* CPUs is done using the *perf_cpu_map__for_each_cpu*
|
||||
macro which requires 3 arguments:
|
||||
|
||||
- cpu - the cpu numer
|
||||
- tmp - iteration helper variable
|
||||
- cpus - the *struct perf_cpumap* object
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
10 perf_cpu_map__for_each_cpu(cpu, tmp, cpus)
|
||||
11 fprintf(stdout, "%d ", cpu);
|
||||
|
||||
ex-2-evsel-stat example
|
||||
=======================
|
||||
|
||||
TBD
|
||||
|
||||
ex-3-evlist-stat example
|
||||
========================
|
||||
|
||||
TBD
|
|
@ -181,7 +181,10 @@ install_pkgconfig: $(LIBPERF_PC)
|
|||
$(call QUIET_INSTALL, $(LIBPERF_PC)) \
|
||||
$(call do_install,$(LIBPERF_PC),$(libdir_SQ)/pkgconfig,644)
|
||||
|
||||
install: install_lib install_headers install_pkgconfig
|
||||
install_doc:
|
||||
$(Q)$(MAKE) -C Documentation install-man install-html install-examples
|
||||
|
||||
install: install_lib install_headers install_pkgconfig install_doc
|
||||
|
||||
FORCE:
|
||||
|
||||
|
|
Loading…
Reference in New Issue