diff options
94 files changed, 5414 insertions, 214 deletions
diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index dabfcf7c3941..7a0e64ccd6ff 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h | |||
@@ -381,6 +381,7 @@ struct kvm_sync_regs { | |||
381 | #define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) | 381 | #define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) |
382 | #define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) | 382 | #define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) |
383 | #define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2) | 383 | #define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2) |
384 | #define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) | ||
384 | 385 | ||
385 | #define KVM_STATE_NESTED_GUEST_MODE 0x00000001 | 386 | #define KVM_STATE_NESTED_GUEST_MODE 0x00000001 |
386 | #define KVM_STATE_NESTED_RUN_PENDING 0x00000002 | 387 | #define KVM_STATE_NESTED_RUN_PENDING 0x00000002 |
diff --git a/tools/arch/x86/include/uapi/asm/perf_regs.h b/tools/arch/x86/include/uapi/asm/perf_regs.h index f3329cabce5c..ac67bbea10ca 100644 --- a/tools/arch/x86/include/uapi/asm/perf_regs.h +++ b/tools/arch/x86/include/uapi/asm/perf_regs.h | |||
@@ -27,8 +27,29 @@ enum perf_event_x86_regs { | |||
27 | PERF_REG_X86_R13, | 27 | PERF_REG_X86_R13, |
28 | PERF_REG_X86_R14, | 28 | PERF_REG_X86_R14, |
29 | PERF_REG_X86_R15, | 29 | PERF_REG_X86_R15, |
30 | 30 | /* These are the limits for the GPRs. */ | |
31 | PERF_REG_X86_32_MAX = PERF_REG_X86_GS + 1, | 31 | PERF_REG_X86_32_MAX = PERF_REG_X86_GS + 1, |
32 | PERF_REG_X86_64_MAX = PERF_REG_X86_R15 + 1, | 32 | PERF_REG_X86_64_MAX = PERF_REG_X86_R15 + 1, |
33 | |||
34 | /* These all need two bits set because they are 128bit */ | ||
35 | PERF_REG_X86_XMM0 = 32, | ||
36 | PERF_REG_X86_XMM1 = 34, | ||
37 | PERF_REG_X86_XMM2 = 36, | ||
38 | PERF_REG_X86_XMM3 = 38, | ||
39 | PERF_REG_X86_XMM4 = 40, | ||
40 | PERF_REG_X86_XMM5 = 42, | ||
41 | PERF_REG_X86_XMM6 = 44, | ||
42 | PERF_REG_X86_XMM7 = 46, | ||
43 | PERF_REG_X86_XMM8 = 48, | ||
44 | PERF_REG_X86_XMM9 = 50, | ||
45 | PERF_REG_X86_XMM10 = 52, | ||
46 | PERF_REG_X86_XMM11 = 54, | ||
47 | PERF_REG_X86_XMM12 = 56, | ||
48 | PERF_REG_X86_XMM13 = 58, | ||
49 | PERF_REG_X86_XMM14 = 60, | ||
50 | PERF_REG_X86_XMM15 = 62, | ||
51 | |||
52 | /* These include both GPRs and XMMX registers */ | ||
53 | PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2, | ||
33 | }; | 54 | }; |
34 | #endif /* _ASM_X86_PERF_REGS_H */ | 55 | #endif /* _ASM_X86_PERF_REGS_H */ |
diff --git a/tools/arch/x86/lib/memcpy_64.S b/tools/arch/x86/lib/memcpy_64.S index 3b24dc05251c..9d05572370ed 100644 --- a/tools/arch/x86/lib/memcpy_64.S +++ b/tools/arch/x86/lib/memcpy_64.S | |||
@@ -257,6 +257,7 @@ ENTRY(__memcpy_mcsafe) | |||
257 | /* Copy successful. Return zero */ | 257 | /* Copy successful. Return zero */ |
258 | .L_done_memcpy_trap: | 258 | .L_done_memcpy_trap: |
259 | xorl %eax, %eax | 259 | xorl %eax, %eax |
260 | .L_done: | ||
260 | ret | 261 | ret |
261 | ENDPROC(__memcpy_mcsafe) | 262 | ENDPROC(__memcpy_mcsafe) |
262 | EXPORT_SYMBOL_GPL(__memcpy_mcsafe) | 263 | EXPORT_SYMBOL_GPL(__memcpy_mcsafe) |
@@ -273,7 +274,7 @@ EXPORT_SYMBOL_GPL(__memcpy_mcsafe) | |||
273 | addl %edx, %ecx | 274 | addl %edx, %ecx |
274 | .E_trailing_bytes: | 275 | .E_trailing_bytes: |
275 | mov %ecx, %eax | 276 | mov %ecx, %eax |
276 | ret | 277 | jmp .L_done |
277 | 278 | ||
278 | /* | 279 | /* |
279 | * For write fault handling, given the destination is unaligned, | 280 | * For write fault handling, given the destination is unaligned, |
diff --git a/tools/lib/traceevent/Documentation/Makefile b/tools/lib/traceevent/Documentation/Makefile new file mode 100644 index 000000000000..aa72ab96c3c1 --- /dev/null +++ b/tools/lib/traceevent/Documentation/Makefile | |||
@@ -0,0 +1,207 @@ | |||
1 | include ../../../scripts/Makefile.include | ||
2 | include ../../../scripts/utilities.mak | ||
3 | |||
4 | # This Makefile and manpage XSL files were taken from tools/perf/Documentation | ||
5 | # and modified for libtraceevent. | ||
6 | |||
7 | MAN3_TXT= \ | ||
8 | $(wildcard libtraceevent-*.txt) \ | ||
9 | libtraceevent.txt | ||
10 | |||
11 | MAN_TXT = $(MAN3_TXT) | ||
12 | _MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT)) | ||
13 | _MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT)) | ||
14 | _DOC_MAN3=$(patsubst %.txt,%.3,$(MAN3_TXT)) | ||
15 | |||
16 | MAN_XML=$(addprefix $(OUTPUT),$(_MAN_XML)) | ||
17 | MAN_HTML=$(addprefix $(OUTPUT),$(_MAN_HTML)) | ||
18 | DOC_MAN3=$(addprefix $(OUTPUT),$(_DOC_MAN3)) | ||
19 | |||
20 | # Make the path relative to DESTDIR, not prefix | ||
21 | ifndef DESTDIR | ||
22 | prefix?=$(HOME) | ||
23 | endif | ||
24 | bindir?=$(prefix)/bin | ||
25 | htmldir?=$(prefix)/share/doc/libtraceevent-doc | ||
26 | pdfdir?=$(prefix)/share/doc/libtraceevent-doc | ||
27 | mandir?=$(prefix)/share/man | ||
28 | man3dir=$(mandir)/man3 | ||
29 | |||
30 | ASCIIDOC=asciidoc | ||
31 | ASCIIDOC_EXTRA = --unsafe -f asciidoc.conf | ||
32 | ASCIIDOC_HTML = xhtml11 | ||
33 | MANPAGE_XSL = manpage-normal.xsl | ||
34 | XMLTO_EXTRA = | ||
35 | INSTALL?=install | ||
36 | RM ?= rm -f | ||
37 | |||
38 | ifdef USE_ASCIIDOCTOR | ||
39 | ASCIIDOC = asciidoctor | ||
40 | ASCIIDOC_EXTRA = -a compat-mode | ||
41 | ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions | ||
42 | ASCIIDOC_EXTRA += -a mansource="libtraceevent" -a manmanual="libtraceevent Manual" | ||
43 | ASCIIDOC_HTML = xhtml5 | ||
44 | endif | ||
45 | |||
46 | XMLTO=xmlto | ||
47 | |||
48 | _tmp_tool_path := $(call get-executable,$(ASCIIDOC)) | ||
49 | ifeq ($(_tmp_tool_path),) | ||
50 | missing_tools = $(ASCIIDOC) | ||
51 | endif | ||
52 | |||
53 | ifndef USE_ASCIIDOCTOR | ||
54 | _tmp_tool_path := $(call get-executable,$(XMLTO)) | ||
55 | ifeq ($(_tmp_tool_path),) | ||
56 | missing_tools += $(XMLTO) | ||
57 | endif | ||
58 | endif | ||
59 | |||
60 | # | ||
61 | # For asciidoc ... | ||
62 | # -7.1.2, no extra settings are needed. | ||
63 | # 8.0-, set ASCIIDOC8. | ||
64 | # | ||
65 | |||
66 | # | ||
67 | # For docbook-xsl ... | ||
68 | # -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0) | ||
69 | # 1.69.0, no extra settings are needed? | ||
70 | # 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP? | ||
71 | # 1.71.1, no extra settings are needed? | ||
72 | # 1.72.0, set DOCBOOK_XSL_172. | ||
73 | # 1.73.0-, set ASCIIDOC_NO_ROFF | ||
74 | # | ||
75 | |||
76 | # | ||
77 | # If you had been using DOCBOOK_XSL_172 in an attempt to get rid | ||
78 | # of 'the ".ft C" problem' in your generated manpages, and you | ||
79 | # instead ended up with weird characters around callouts, try | ||
80 | # using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8). | ||
81 | # | ||
82 | |||
83 | ifdef ASCIIDOC8 | ||
84 | ASCIIDOC_EXTRA += -a asciidoc7compatible | ||
85 | endif | ||
86 | ifdef DOCBOOK_XSL_172 | ||
87 | ASCIIDOC_EXTRA += -a libtraceevent-asciidoc-no-roff | ||
88 | MANPAGE_XSL = manpage-1.72.xsl | ||
89 | else | ||
90 | ifdef ASCIIDOC_NO_ROFF | ||
91 | # docbook-xsl after 1.72 needs the regular XSL, but will not | ||
92 | # pass-thru raw roff codes from asciidoc.conf, so turn them off. | ||
93 | ASCIIDOC_EXTRA += -a libtraceevent-asciidoc-no-roff | ||
94 | endif | ||
95 | endif | ||
96 | ifdef MAN_BOLD_LITERAL | ||
97 | XMLTO_EXTRA += -m manpage-bold-literal.xsl | ||
98 | endif | ||
99 | ifdef DOCBOOK_SUPPRESS_SP | ||
100 | XMLTO_EXTRA += -m manpage-suppress-sp.xsl | ||
101 | endif | ||
102 | |||
103 | SHELL_PATH ?= $(SHELL) | ||
104 | # Shell quote; | ||
105 | SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) | ||
106 | |||
107 | DESTDIR ?= | ||
108 | DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' | ||
109 | |||
110 | export DESTDIR DESTDIR_SQ | ||
111 | |||
112 | # | ||
113 | # Please note that there is a minor bug in asciidoc. | ||
114 | # The version after 6.0.3 _will_ include the patch found here: | ||
115 | # http://marc.theaimsgroup.com/?l=libtraceevent&m=111558757202243&w=2 | ||
116 | # | ||
117 | # Until that version is released you may have to apply the patch | ||
118 | # yourself - yes, all 6 characters of it! | ||
119 | # | ||
120 | QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir | ||
121 | QUIET_SUBDIR1 = | ||
122 | |||
123 | ifneq ($(findstring $(MAKEFLAGS),w),w) | ||
124 | PRINT_DIR = --no-print-directory | ||
125 | else # "make -w" | ||
126 | NO_SUBDIR = : | ||
127 | endif | ||
128 | |||
129 | ifneq ($(findstring $(MAKEFLAGS),s),s) | ||
130 | ifneq ($(V),1) | ||
131 | QUIET_ASCIIDOC = @echo ' ASCIIDOC '$@; | ||
132 | QUIET_XMLTO = @echo ' XMLTO '$@; | ||
133 | QUIET_SUBDIR0 = +@subdir= | ||
134 | QUIET_SUBDIR1 = ;$(NO_SUBDIR) \ | ||
135 | echo ' SUBDIR ' $$subdir; \ | ||
136 | $(MAKE) $(PRINT_DIR) -C $$subdir | ||
137 | export V | ||
138 | endif | ||
139 | endif | ||
140 | |||
141 | all: html man | ||
142 | |||
143 | man: man3 | ||
144 | man3: $(DOC_MAN3) | ||
145 | |||
146 | html: $(MAN_HTML) | ||
147 | |||
148 | $(MAN_HTML) $(DOC_MAN3): asciidoc.conf | ||
149 | |||
150 | install: install-man | ||
151 | |||
152 | check-man-tools: | ||
153 | ifdef missing_tools | ||
154 | $(error "You need to install $(missing_tools) for man pages") | ||
155 | endif | ||
156 | |||
157 | do-install-man: man | ||
158 | $(call QUIET_INSTALL, Documentation-man) \ | ||
159 | $(INSTALL) -d -m 755 $(DESTDIR)$(man3dir); \ | ||
160 | $(INSTALL) -m 644 $(DOC_MAN3) $(DESTDIR)$(man3dir); | ||
161 | |||
162 | install-man: check-man-tools man do-install-man | ||
163 | |||
164 | uninstall: uninstall-man | ||
165 | |||
166 | uninstall-man: | ||
167 | $(call QUIET_UNINST, Documentation-man) \ | ||
168 | $(Q)$(RM) $(addprefix $(DESTDIR)$(man3dir)/,$(DOC_MAN3)) | ||
169 | |||
170 | |||
171 | ifdef missing_tools | ||
172 | DO_INSTALL_MAN = $(warning Please install $(missing_tools) to have the man pages installed) | ||
173 | else | ||
174 | DO_INSTALL_MAN = do-install-man | ||
175 | endif | ||
176 | |||
177 | CLEAN_FILES = \ | ||
178 | $(MAN_XML) $(addsuffix +,$(MAN_XML)) \ | ||
179 | $(MAN_HTML) $(addsuffix +,$(MAN_HTML)) \ | ||
180 | $(DOC_MAN3) *.3 | ||
181 | |||
182 | clean: | ||
183 | $(call QUIET_CLEAN, Documentation) $(RM) $(CLEAN_FILES) | ||
184 | |||
185 | ifdef USE_ASCIIDOCTOR | ||
186 | $(OUTPUT)%.3 : $(OUTPUT)%.txt | ||
187 | $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ | ||
188 | $(ASCIIDOC) -b manpage -d manpage \ | ||
189 | $(ASCIIDOC_EXTRA) -alibtraceevent_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \ | ||
190 | mv $@+ $@ | ||
191 | endif | ||
192 | |||
193 | $(OUTPUT)%.3 : $(OUTPUT)%.xml | ||
194 | $(QUIET_XMLTO)$(RM) $@ && \ | ||
195 | $(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< | ||
196 | |||
197 | $(OUTPUT)%.xml : %.txt | ||
198 | $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ | ||
199 | $(ASCIIDOC) -b docbook -d manpage \ | ||
200 | $(ASCIIDOC_EXTRA) -alibtraceevent_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \ | ||
201 | mv $@+ $@ | ||
202 | |||
203 | $(MAN_HTML): $(OUTPUT)%.html : %.txt | ||
204 | $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ | ||
205 | $(ASCIIDOC) -b $(ASCIIDOC_HTML) -d manpage \ | ||
206 | $(ASCIIDOC_EXTRA) -aperf_version=$(EVENT_PARSE_VERSION) -o $@+ $< && \ | ||
207 | mv $@+ $@ | ||
diff --git a/tools/lib/traceevent/Documentation/asciidoc.conf b/tools/lib/traceevent/Documentation/asciidoc.conf new file mode 100644 index 000000000000..07595717f06e --- /dev/null +++ b/tools/lib/traceevent/Documentation/asciidoc.conf | |||
@@ -0,0 +1,120 @@ | |||
1 | ## linktep: macro | ||
2 | # | ||
3 | # Usage: linktep:command[manpage-section] | ||
4 | # | ||
5 | # Note, {0} is the manpage section, while {target} is the command. | ||
6 | # | ||
7 | # Show TEP link as: <command>(<section>); if section is defined, else just show | ||
8 | # the command. | ||
9 | |||
10 | [macros] | ||
11 | (?su)[\\]?(?P<name>linktep):(?P<target>\S*?)\[(?P<attrlist>.*?)\]= | ||
12 | |||
13 | [attributes] | ||
14 | asterisk=* | ||
15 | plus=+ | ||
16 | caret=^ | ||
17 | startsb=[ | ||
18 | endsb=] | ||
19 | tilde=~ | ||
20 | |||
21 | ifdef::backend-docbook[] | ||
22 | [linktep-inlinemacro] | ||
23 | {0%{target}} | ||
24 | {0#<citerefentry>} | ||
25 | {0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>} | ||
26 | {0#</citerefentry>} | ||
27 | endif::backend-docbook[] | ||
28 | |||
29 | ifdef::backend-docbook[] | ||
30 | ifndef::tep-asciidoc-no-roff[] | ||
31 | # "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this. | ||
32 | # v1.72 breaks with this because it replaces dots not in roff requests. | ||
33 | [listingblock] | ||
34 | <example><title>{title}</title> | ||
35 | <literallayout> | ||
36 | ifdef::doctype-manpage[] | ||
37 | .ft C | ||
38 | endif::doctype-manpage[] | ||
39 | | | ||
40 | ifdef::doctype-manpage[] | ||
41 | .ft | ||
42 | endif::doctype-manpage[] | ||
43 | </literallayout> | ||
44 | {title#}</example> | ||
45 | endif::tep-asciidoc-no-roff[] | ||
46 | |||
47 | ifdef::tep-asciidoc-no-roff[] | ||
48 | ifdef::doctype-manpage[] | ||
49 | # The following two small workarounds insert a simple paragraph after screen | ||
50 | [listingblock] | ||
51 | <example><title>{title}</title> | ||
52 | <literallayout> | ||
53 | | | ||
54 | </literallayout><simpara></simpara> | ||
55 | {title#}</example> | ||
56 | |||
57 | [verseblock] | ||
58 | <formalpara{id? id="{id}"}><title>{title}</title><para> | ||
59 | {title%}<literallayout{id? id="{id}"}> | ||
60 | {title#}<literallayout> | ||
61 | | | ||
62 | </literallayout> | ||
63 | {title#}</para></formalpara> | ||
64 | {title%}<simpara></simpara> | ||
65 | endif::doctype-manpage[] | ||
66 | endif::tep-asciidoc-no-roff[] | ||
67 | endif::backend-docbook[] | ||
68 | |||
69 | ifdef::doctype-manpage[] | ||
70 | ifdef::backend-docbook[] | ||
71 | [header] | ||
72 | template::[header-declarations] | ||
73 | <refentry> | ||
74 | <refmeta> | ||
75 | <refentrytitle>{mantitle}</refentrytitle> | ||
76 | <manvolnum>{manvolnum}</manvolnum> | ||
77 | <refmiscinfo class="source">libtraceevent</refmiscinfo> | ||
78 | <refmiscinfo class="version">{libtraceevent_version}</refmiscinfo> | ||
79 | <refmiscinfo class="manual">libtraceevent Manual</refmiscinfo> | ||
80 | </refmeta> | ||
81 | <refnamediv> | ||
82 | <refname>{manname1}</refname> | ||
83 | <refname>{manname2}</refname> | ||
84 | <refname>{manname3}</refname> | ||
85 | <refname>{manname4}</refname> | ||
86 | <refname>{manname5}</refname> | ||
87 | <refname>{manname6}</refname> | ||
88 | <refname>{manname7}</refname> | ||
89 | <refname>{manname8}</refname> | ||
90 | <refname>{manname9}</refname> | ||
91 | <refname>{manname10}</refname> | ||
92 | <refname>{manname11}</refname> | ||
93 | <refname>{manname12}</refname> | ||
94 | <refname>{manname13}</refname> | ||
95 | <refname>{manname14}</refname> | ||
96 | <refname>{manname15}</refname> | ||
97 | <refname>{manname16}</refname> | ||
98 | <refname>{manname17}</refname> | ||
99 | <refname>{manname18}</refname> | ||
100 | <refname>{manname19}</refname> | ||
101 | <refname>{manname20}</refname> | ||
102 | <refname>{manname21}</refname> | ||
103 | <refname>{manname22}</refname> | ||
104 | <refname>{manname23}</refname> | ||
105 | <refname>{manname24}</refname> | ||
106 | <refname>{manname25}</refname> | ||
107 | <refname>{manname26}</refname> | ||
108 | <refname>{manname27}</refname> | ||
109 | <refname>{manname28}</refname> | ||
110 | <refname>{manname29}</refname> | ||
111 | <refname>{manname30}</refname> | ||
112 | <refpurpose>{manpurpose}</refpurpose> | ||
113 | </refnamediv> | ||
114 | endif::backend-docbook[] | ||
115 | endif::doctype-manpage[] | ||
116 | |||
117 | ifdef::backend-xhtml11[] | ||
118 | [linktep-inlinemacro] | ||
119 | <a href="{target}.html">{target}{0?({0})}</a> | ||
120 | endif::backend-xhtml11[] | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-commands.txt b/tools/lib/traceevent/Documentation/libtraceevent-commands.txt new file mode 100644 index 000000000000..bec552001f8e --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-commands.txt | |||
@@ -0,0 +1,153 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_register_comm, tep_override_comm, tep_pid_is_registered, | ||
7 | tep_data_comm_from_pid, tep_data_pid_from_comm, tep_cmdline_pid - | ||
8 | Manage pid to process name mappings. | ||
9 | |||
10 | SYNOPSIS | ||
11 | -------- | ||
12 | [verse] | ||
13 | -- | ||
14 | *#include <event-parse.h>* | ||
15 | |||
16 | int *tep_register_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, int _pid_); | ||
17 | int *tep_override_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, int _pid_); | ||
18 | bool *tep_is_pid_registered*(struct tep_handle pass:[*]_tep_, int _pid_); | ||
19 | const char pass:[*]*tep_data_comm_from_pid*(struct tep_handle pass:[*]_pevent_, int _pid_); | ||
20 | struct cmdline pass:[*]*tep_data_pid_from_comm*(struct tep_handle pass:[*]_pevent_, const char pass:[*]_comm_, struct cmdline pass:[*]_next_); | ||
21 | int *tep_cmdline_pid*(struct tep_handle pass:[*]_pevent_, struct cmdline pass:[*]_cmdline_); | ||
22 | -- | ||
23 | |||
24 | DESCRIPTION | ||
25 | ----------- | ||
26 | These functions can be used to handle the mapping between pid and process name. | ||
27 | The library builds a cache of these mappings, which is used to display the name | ||
28 | of the process, instead of its pid. This information can be retrieved from | ||
29 | tracefs/saved_cmdlines file. | ||
30 | |||
31 | The _tep_register_comm()_ function registers a _pid_ / process name mapping. | ||
32 | If a command with the same _pid_ is already registered, an error is returned. | ||
33 | The _pid_ argument is the process ID, the _comm_ argument is the process name, | ||
34 | _tep_ is the event context. The _comm_ is duplicated internally. | ||
35 | |||
36 | The _tep_override_comm()_ function registers a _pid_ / process name mapping. | ||
37 | If a process with the same pid is already registered, the process name string is | ||
38 | udapted with the new one. The _pid_ argument is the process ID, the _comm_ | ||
39 | argument is the process name, _tep_ is the event context. The _comm_ is | ||
40 | duplicated internally. | ||
41 | |||
42 | The _tep_is_pid_registered()_ function checks if a pid has a process name | ||
43 | mapping registered. The _pid_ argument is the process ID, _tep_ is the event | ||
44 | context. | ||
45 | |||
46 | The _tep_data_comm_from_pid()_ function returns the process name for a given | ||
47 | pid. The _pid_ argument is the process ID, _tep_ is the event context. | ||
48 | The returned string should not be freed, but will be freed when the _tep_ | ||
49 | handler is closed. | ||
50 | |||
51 | The _tep_data_pid_from_comm()_ function returns a pid for a given process name. | ||
52 | The _comm_ argument is the process name, _tep_ is the event context. | ||
53 | The argument _next_ is the cmdline structure to search for the next pid. | ||
54 | As there may be more than one pid for a given process, the result of this call | ||
55 | can be passed back into a recurring call in the _next_ parameter, to search for | ||
56 | the next pid. If _next_ is NULL, it will return the first pid associated with | ||
57 | the _comm_. The function performs a linear search, so it may be slow. | ||
58 | |||
59 | The _tep_cmdline_pid()_ function returns the pid associated with a given | ||
60 | _cmdline_. The _tep_ argument is the event context. | ||
61 | |||
62 | RETURN VALUE | ||
63 | ------------ | ||
64 | _tep_register_comm()_ function returns 0 on success. In case of an error -1 is | ||
65 | returned and errno is set to indicate the cause of the problem: ENOMEM, if there | ||
66 | is not enough memory to duplicate the _comm_ or EEXIST if a mapping for this | ||
67 | _pid_ is already registered. | ||
68 | |||
69 | _tep_override_comm()_ function returns 0 on success. In case of an error -1 is | ||
70 | returned and errno is set to indicate the cause of the problem: ENOMEM, if there | ||
71 | is not enough memory to duplicate the _comm_. | ||
72 | |||
73 | _tep_is_pid_registered()_ function returns true if the _pid_ has a process name | ||
74 | mapped to it, false otherwise. | ||
75 | |||
76 | _tep_data_comm_from_pid()_ function returns the process name as string, or the | ||
77 | string "<...>" if there is no mapping for the given pid. | ||
78 | |||
79 | _tep_data_pid_from_comm()_ function returns a pointer to a struct cmdline, that | ||
80 | holds a pid for a given process, or NULL if none is found. This result can be | ||
81 | passed back into a recurring call as the _next_ parameter of the function. | ||
82 | |||
83 | _tep_cmdline_pid()_ functions returns the pid for the give cmdline. If _cmdline_ | ||
84 | is NULL, then -1 is returned. | ||
85 | |||
86 | EXAMPLE | ||
87 | ------- | ||
88 | The following example registers pid for command "ls", in context of event _tep_ | ||
89 | and performs various searches for pid / process name mappings: | ||
90 | [source,c] | ||
91 | -- | ||
92 | #include <event-parse.h> | ||
93 | ... | ||
94 | int ret; | ||
95 | int ls_pid = 1021; | ||
96 | struct tep_handle *tep = tep_alloc(); | ||
97 | ... | ||
98 | ret = tep_register_comm(tep, "ls", ls_pid); | ||
99 | if (ret != 0 && errno == EEXIST) | ||
100 | ret = tep_override_comm(tep, "ls", ls_pid); | ||
101 | if (ret != 0) { | ||
102 | /* Failed to register pid / command mapping */ | ||
103 | } | ||
104 | ... | ||
105 | if (tep_is_pid_registered(tep, ls_pid) == 0) { | ||
106 | /* Command mapping for ls_pid is not registered */ | ||
107 | } | ||
108 | ... | ||
109 | const char *comm = tep_data_comm_from_pid(tep, ls_pid); | ||
110 | if (comm) { | ||
111 | /* Found process name for ls_pid */ | ||
112 | } | ||
113 | ... | ||
114 | int pid; | ||
115 | struct cmdline *cmd = tep_data_pid_from_comm(tep, "ls", NULL); | ||
116 | while (cmd) { | ||
117 | pid = tep_cmdline_pid(tep, cmd); | ||
118 | /* Found pid for process "ls" */ | ||
119 | cmd = tep_data_pid_from_comm(tep, "ls", cmd); | ||
120 | } | ||
121 | -- | ||
122 | FILES | ||
123 | ----- | ||
124 | [verse] | ||
125 | -- | ||
126 | *event-parse.h* | ||
127 | Header file to include in order to have access to the library APIs. | ||
128 | *-ltraceevent* | ||
129 | Linker switch to add when building a program that uses the library. | ||
130 | -- | ||
131 | |||
132 | SEE ALSO | ||
133 | -------- | ||
134 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
135 | |||
136 | AUTHOR | ||
137 | ------ | ||
138 | [verse] | ||
139 | -- | ||
140 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
141 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
142 | -- | ||
143 | REPORTING BUGS | ||
144 | -------------- | ||
145 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
146 | |||
147 | LICENSE | ||
148 | ------- | ||
149 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
150 | |||
151 | RESOURCES | ||
152 | --------- | ||
153 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-cpus.txt b/tools/lib/traceevent/Documentation/libtraceevent-cpus.txt new file mode 100644 index 000000000000..5ad70e43b752 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-cpus.txt | |||
@@ -0,0 +1,77 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_get_cpus, tep_set_cpus - Get / set the number of CPUs, which have a tracing | ||
7 | buffer representing it. Note, the buffer may be empty. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | int *tep_get_cpus*(struct tep_handle pass:[*]_tep_); | ||
16 | void *tep_set_cpus*(struct tep_handle pass:[*]_tep_, int _cpus_); | ||
17 | -- | ||
18 | |||
19 | DESCRIPTION | ||
20 | ----------- | ||
21 | The _tep_get_cpus()_ function gets the number of CPUs, which have a tracing | ||
22 | buffer representing it. The _tep_ argument is trace event parser context. | ||
23 | |||
24 | The _tep_set_cpus()_ function sets the number of CPUs, which have a tracing | ||
25 | buffer representing it. The _tep_ argument is trace event parser context. | ||
26 | The _cpu_ argument is the number of CPUs with tracing data. | ||
27 | |||
28 | RETURN VALUE | ||
29 | ------------ | ||
30 | The _tep_get_cpus()_ functions returns the number of CPUs, which have tracing | ||
31 | data recorded. | ||
32 | |||
33 | EXAMPLE | ||
34 | ------- | ||
35 | [source,c] | ||
36 | -- | ||
37 | #include <event-parse.h> | ||
38 | ... | ||
39 | struct tep_handle *tep = tep_alloc(); | ||
40 | ... | ||
41 | tep_set_cpus(tep, 5); | ||
42 | ... | ||
43 | printf("We have tracing data for %d CPUs", tep_get_cpus(tep)); | ||
44 | -- | ||
45 | |||
46 | FILES | ||
47 | ----- | ||
48 | [verse] | ||
49 | -- | ||
50 | *event-parse.h* | ||
51 | Header file to include in order to have access to the library APIs. | ||
52 | *-ltraceevent* | ||
53 | Linker switch to add when building a program that uses the library. | ||
54 | -- | ||
55 | |||
56 | SEE ALSO | ||
57 | -------- | ||
58 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
59 | |||
60 | AUTHOR | ||
61 | ------ | ||
62 | [verse] | ||
63 | -- | ||
64 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
65 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
66 | -- | ||
67 | REPORTING BUGS | ||
68 | -------------- | ||
69 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
70 | |||
71 | LICENSE | ||
72 | ------- | ||
73 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
74 | |||
75 | RESOURCES | ||
76 | --------- | ||
77 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-endian_read.txt b/tools/lib/traceevent/Documentation/libtraceevent-endian_read.txt new file mode 100644 index 000000000000..e64851b6e189 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-endian_read.txt | |||
@@ -0,0 +1,78 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_read_number - Reads a number from raw data. | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | -- | ||
12 | *#include <event-parse.h>* | ||
13 | |||
14 | unsigned long long *tep_read_number*(struct tep_handle pass:[*]_tep_, const void pass:[*]_ptr_, int _size_); | ||
15 | -- | ||
16 | |||
17 | DESCRIPTION | ||
18 | ----------- | ||
19 | The _tep_read_number()_ function reads an integer from raw data, taking into | ||
20 | account the endianness of the raw data and the current host. The _tep_ argument | ||
21 | is the trace event parser context. The _ptr_ is a pointer to the raw data, where | ||
22 | the integer is, and the _size_ is the size of the integer. | ||
23 | |||
24 | RETURN VALUE | ||
25 | ------------ | ||
26 | The _tep_read_number()_ function returns the integer in the byte order of | ||
27 | the current host. In case of an error, 0 is returned. | ||
28 | |||
29 | EXAMPLE | ||
30 | ------- | ||
31 | [source,c] | ||
32 | -- | ||
33 | #include <event-parse.h> | ||
34 | ... | ||
35 | struct tep_handle *tep = tep_alloc(); | ||
36 | ... | ||
37 | void process_record(struct tep_record *record) | ||
38 | { | ||
39 | int offset = 24; | ||
40 | int data = tep_read_number(tep, record->data + offset, 4); | ||
41 | |||
42 | /* Read the 4 bytes at the offset 24 of data as an integer */ | ||
43 | } | ||
44 | ... | ||
45 | -- | ||
46 | |||
47 | FILES | ||
48 | ----- | ||
49 | [verse] | ||
50 | -- | ||
51 | *event-parse.h* | ||
52 | Header file to include in order to have access to the library APIs. | ||
53 | *-ltraceevent* | ||
54 | Linker switch to add when building a program that uses the library. | ||
55 | -- | ||
56 | |||
57 | SEE ALSO | ||
58 | -------- | ||
59 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
60 | |||
61 | AUTHOR | ||
62 | ------ | ||
63 | [verse] | ||
64 | -- | ||
65 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
66 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
67 | -- | ||
68 | REPORTING BUGS | ||
69 | -------------- | ||
70 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
71 | |||
72 | LICENSE | ||
73 | ------- | ||
74 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
75 | |||
76 | RESOURCES | ||
77 | --------- | ||
78 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-event_find.txt b/tools/lib/traceevent/Documentation/libtraceevent-event_find.txt new file mode 100644 index 000000000000..7bc062c9f76f --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-event_find.txt | |||
@@ -0,0 +1,103 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_find_event,tep_find_event_by_name,tep_find_event_by_record - | ||
7 | Find events by given key. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | struct tep_event pass:[*]*tep_find_event*(struct tep_handle pass:[*]_tep_, int _id_); | ||
16 | struct tep_event pass:[*]*tep_find_event_by_name*(struct tep_handle pass:[*]_tep_, const char pass:[*]_sys_, const char pass:[*]_name_); | ||
17 | struct tep_event pass:[*]*tep_find_event_by_record*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_record_); | ||
18 | -- | ||
19 | |||
20 | DESCRIPTION | ||
21 | ----------- | ||
22 | This set of functions can be used to search for an event, based on a given | ||
23 | criteria. All functions require a pointer to a _tep_, trace event parser | ||
24 | context. | ||
25 | |||
26 | The _tep_find_event()_ function searches for an event by given event _id_. The | ||
27 | event ID is assigned dynamically and can be viewed in event's format file, | ||
28 | "ID" field. | ||
29 | |||
30 | The tep_find_event_by_name()_ function searches for an event by given | ||
31 | event _name_, under the system _sys_. If the _sys_ is NULL (not specified), | ||
32 | the first event with _name_ is returned. | ||
33 | |||
34 | The tep_find_event_by_record()_ function searches for an event from a given | ||
35 | _record_. | ||
36 | |||
37 | RETURN VALUE | ||
38 | ------------ | ||
39 | All these functions return a pointer to the found event, or NULL if there is no | ||
40 | such event. | ||
41 | |||
42 | EXAMPLE | ||
43 | ------- | ||
44 | [source,c] | ||
45 | -- | ||
46 | #include <event-parse.h> | ||
47 | ... | ||
48 | struct tep_handle *tep = tep_alloc(); | ||
49 | ... | ||
50 | struct tep_event *event; | ||
51 | |||
52 | event = tep_find_event(tep, 1857); | ||
53 | if (event == NULL) { | ||
54 | /* There is no event with ID 1857 */ | ||
55 | } | ||
56 | |||
57 | event = tep_find_event_by_name(tep, "kvm", "kvm_exit"); | ||
58 | if (event == NULL) { | ||
59 | /* There is no kvm_exit event, from kvm system */ | ||
60 | } | ||
61 | |||
62 | void event_from_record(struct tep_record *record) | ||
63 | { | ||
64 | struct tep_event *event = tep_find_event_by_record(tep, record); | ||
65 | if (event == NULL) { | ||
66 | /* There is no event from given record */ | ||
67 | } | ||
68 | } | ||
69 | ... | ||
70 | -- | ||
71 | |||
72 | FILES | ||
73 | ----- | ||
74 | [verse] | ||
75 | -- | ||
76 | *event-parse.h* | ||
77 | Header file to include in order to have access to the library APIs. | ||
78 | *-ltraceevent* | ||
79 | Linker switch to add when building a program that uses the library. | ||
80 | -- | ||
81 | |||
82 | SEE ALSO | ||
83 | -------- | ||
84 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
85 | |||
86 | AUTHOR | ||
87 | ------ | ||
88 | [verse] | ||
89 | -- | ||
90 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
91 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
92 | -- | ||
93 | REPORTING BUGS | ||
94 | -------------- | ||
95 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
96 | |||
97 | LICENSE | ||
98 | ------- | ||
99 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
100 | |||
101 | RESOURCES | ||
102 | --------- | ||
103 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-event_get.txt b/tools/lib/traceevent/Documentation/libtraceevent-event_get.txt new file mode 100644 index 000000000000..6525092fc417 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-event_get.txt | |||
@@ -0,0 +1,99 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_get_event, tep_get_first_event, tep_get_events_count - Access events. | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | -- | ||
12 | *#include <event-parse.h>* | ||
13 | |||
14 | struct tep_event pass:[*]*tep_get_event*(struct tep_handle pass:[*]_tep_, int _index_); | ||
15 | struct tep_event pass:[*]*tep_get_first_event*(struct tep_handle pass:[*]_tep_); | ||
16 | int *tep_get_events_count*(struct tep_handle pass:[*]_tep_); | ||
17 | -- | ||
18 | |||
19 | DESCRIPTION | ||
20 | ----------- | ||
21 | The _tep_get_event()_ function returns a pointer to event at the given _index_. | ||
22 | The _tep_ argument is trace event parser context, the _index_ is the index of | ||
23 | the requested event. | ||
24 | |||
25 | The _tep_get_first_event()_ function returns a pointer to the first event. | ||
26 | As events are stored in an array, this function returns the pointer to the | ||
27 | beginning of the array. The _tep_ argument is trace event parser context. | ||
28 | |||
29 | The _tep_get_events_count()_ function returns the number of the events | ||
30 | in the array. The _tep_ argument is trace event parser context. | ||
31 | |||
32 | RETURN VALUE | ||
33 | ------------ | ||
34 | The _tep_get_event()_ returns a pointer to the event located at _index_. | ||
35 | NULL is returned in case of error, in case there are no events or _index_ is | ||
36 | out of range. | ||
37 | |||
38 | The _tep_get_first_event()_ returns a pointer to the first event. NULL is | ||
39 | returned in case of error, or in case there are no events. | ||
40 | |||
41 | The _tep_get_events_count()_ returns the number of the events. 0 is | ||
42 | returned in case of error, or in case there are no events. | ||
43 | |||
44 | EXAMPLE | ||
45 | ------- | ||
46 | [source,c] | ||
47 | -- | ||
48 | #include <event-parse.h> | ||
49 | ... | ||
50 | struct tep_handle *tep = tep_alloc(); | ||
51 | ... | ||
52 | int i,count = tep_get_events_count(tep); | ||
53 | struct tep_event *event, *events = tep_get_first_event(tep); | ||
54 | |||
55 | if (events == NULL) { | ||
56 | /* There are no events */ | ||
57 | } else { | ||
58 | for (i = 0; i < count; i++) { | ||
59 | event = (events+i); | ||
60 | /* process events[i] */ | ||
61 | } | ||
62 | |||
63 | /* Get the last event */ | ||
64 | event = tep_get_event(tep, count-1); | ||
65 | } | ||
66 | -- | ||
67 | |||
68 | FILES | ||
69 | ----- | ||
70 | [verse] | ||
71 | -- | ||
72 | *event-parse.h* | ||
73 | Header file to include in order to have access to the library APIs. | ||
74 | *-ltraceevent* | ||
75 | Linker switch to add when building a program that uses the library. | ||
76 | -- | ||
77 | |||
78 | SEE ALSO | ||
79 | -------- | ||
80 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
81 | |||
82 | AUTHOR | ||
83 | ------ | ||
84 | [verse] | ||
85 | -- | ||
86 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
87 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
88 | -- | ||
89 | REPORTING BUGS | ||
90 | -------------- | ||
91 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
92 | |||
93 | LICENSE | ||
94 | ------- | ||
95 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
96 | |||
97 | RESOURCES | ||
98 | --------- | ||
99 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-event_list.txt b/tools/lib/traceevent/Documentation/libtraceevent-event_list.txt new file mode 100644 index 000000000000..fba350e5a4cb --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-event_list.txt | |||
@@ -0,0 +1,122 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_list_events, tep_list_events_copy - | ||
7 | Get list of events, sorted by given criteria. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | enum *tep_event_sort_type* { | ||
16 | _TEP_EVENT_SORT_ID_, | ||
17 | _TEP_EVENT_SORT_NAME_, | ||
18 | _TEP_EVENT_SORT_SYSTEM_, | ||
19 | }; | ||
20 | |||
21 | struct tep_event pass:[*]pass:[*]*tep_list_events*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_); | ||
22 | struct tep_event pass:[*]pass:[*]*tep_list_events_copy*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_); | ||
23 | -- | ||
24 | |||
25 | DESCRIPTION | ||
26 | ----------- | ||
27 | The _tep_list_events()_ function returns an array of pointers to the events, | ||
28 | sorted by the _sort_type_ criteria. The last element of the array is NULL. | ||
29 | The returned memory must not be freed, it is managed by the library. | ||
30 | The function is not thread safe. The _tep_ argument is trace event parser | ||
31 | context. The _sort_type_ argument is the required sort criteria: | ||
32 | [verse] | ||
33 | -- | ||
34 | _TEP_EVENT_SORT_ID_ - sort by the event ID. | ||
35 | _TEP_EVENT_SORT_NAME_ - sort by the event (name, system, id) triplet. | ||
36 | _TEP_EVENT_SORT_SYSTEM_ - sort by the event (system, name, id) triplet. | ||
37 | -- | ||
38 | |||
39 | The _tep_list_events_copy()_ is a thread safe version of _tep_list_events()_. | ||
40 | It has the same behavior, but the returned array is allocated internally and | ||
41 | must be freed by the caller. Note that the content of the array must not be | ||
42 | freed (see the EXAMPLE below). | ||
43 | |||
44 | RETURN VALUE | ||
45 | ------------ | ||
46 | The _tep_list_events()_ function returns an array of pointers to events. | ||
47 | In case of an error, NULL is returned. The returned array must not be freed, | ||
48 | it is managed by the library. | ||
49 | |||
50 | The _tep_list_events_copy()_ function returns an array of pointers to events. | ||
51 | In case of an error, NULL is returned. The returned array must be freed by | ||
52 | the caller. | ||
53 | |||
54 | EXAMPLE | ||
55 | ------- | ||
56 | [source,c] | ||
57 | -- | ||
58 | #include <event-parse.h> | ||
59 | ... | ||
60 | struct tep_handle *tep = tep_alloc(); | ||
61 | ... | ||
62 | int i; | ||
63 | struct tep_event_format **events; | ||
64 | |||
65 | i=0; | ||
66 | events = tep_list_events(tep, TEP_EVENT_SORT_ID); | ||
67 | if (events == NULL) { | ||
68 | /* Failed to get the events, sorted by ID */ | ||
69 | } else { | ||
70 | while(events[i]) { | ||
71 | /* walk through the list of the events, sorted by ID */ | ||
72 | i++; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | i=0; | ||
77 | events = tep_list_events_copy(tep, TEP_EVENT_SORT_NAME); | ||
78 | if (events == NULL) { | ||
79 | /* Failed to get the events, sorted by name */ | ||
80 | } else { | ||
81 | while(events[i]) { | ||
82 | /* walk through the list of the events, sorted by name */ | ||
83 | i++; | ||
84 | } | ||
85 | free(events); | ||
86 | } | ||
87 | |||
88 | ... | ||
89 | -- | ||
90 | |||
91 | FILES | ||
92 | ----- | ||
93 | [verse] | ||
94 | -- | ||
95 | *event-parse.h* | ||
96 | Header file to include in order to have access to the library APIs. | ||
97 | *-ltraceevent* | ||
98 | Linker switch to add when building a program that uses the library. | ||
99 | -- | ||
100 | |||
101 | SEE ALSO | ||
102 | -------- | ||
103 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
104 | |||
105 | AUTHOR | ||
106 | ------ | ||
107 | [verse] | ||
108 | -- | ||
109 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
110 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
111 | -- | ||
112 | REPORTING BUGS | ||
113 | -------------- | ||
114 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
115 | |||
116 | LICENSE | ||
117 | ------- | ||
118 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
119 | |||
120 | RESOURCES | ||
121 | --------- | ||
122 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-field_find.txt b/tools/lib/traceevent/Documentation/libtraceevent-field_find.txt new file mode 100644 index 000000000000..0896af5b9eff --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-field_find.txt | |||
@@ -0,0 +1,118 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_find_common_field, tep_find_field, tep_find_any_field - | ||
7 | Search for a field in an event. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | struct tep_format_field pass:[*]*tep_find_common_field*(struct tep_event pass:[*]_event_, const char pass:[*]_name_); | ||
16 | struct tep_format_field pass:[*]*tep_find_field*(struct tep_event_ormat pass:[*]_event_, const char pass:[*]_name_); | ||
17 | struct tep_format_field pass:[*]*tep_find_any_field*(struct tep_event pass:[*]_event_, const char pass:[*]_name_); | ||
18 | -- | ||
19 | |||
20 | DESCRIPTION | ||
21 | ----------- | ||
22 | These functions search for a field with given name in an event. The field | ||
23 | returned can be used to find the field content from within a data record. | ||
24 | |||
25 | The _tep_find_common_field()_ function searches for a common field with _name_ | ||
26 | in the _event_. | ||
27 | |||
28 | The _tep_find_field()_ function searches for an event specific field with | ||
29 | _name_ in the _event_. | ||
30 | |||
31 | The _tep_find_any_field()_ function searches for any field with _name_ in the | ||
32 | _event_. | ||
33 | |||
34 | RETURN VALUE | ||
35 | ------------ | ||
36 | The _tep_find_common_field(), _tep_find_field()_ and _tep_find_any_field()_ | ||
37 | functions return a pointer to the found field, or NULL in case there is no field | ||
38 | with the requested name. | ||
39 | |||
40 | EXAMPLE | ||
41 | ------- | ||
42 | [source,c] | ||
43 | -- | ||
44 | #include <event-parse.h> | ||
45 | ... | ||
46 | void get_htimer_info(struct tep_handle *tep, struct tep_record *record) | ||
47 | { | ||
48 | struct tep_format_field *field; | ||
49 | struct tep_event *event; | ||
50 | long long softexpires; | ||
51 | int mode; | ||
52 | int pid; | ||
53 | |||
54 | event = tep_find_event_by_name(tep, "timer", "hrtimer_start"); | ||
55 | |||
56 | field = tep_find_common_field(event, "common_pid"); | ||
57 | if (field == NULL) { | ||
58 | /* Cannot find "common_pid" field in the event */ | ||
59 | } else { | ||
60 | /* Get pid from the data record */ | ||
61 | pid = tep_read_number(tep, record->data + field->offset, | ||
62 | field->size); | ||
63 | } | ||
64 | |||
65 | field = tep_find_field(event, "softexpires"); | ||
66 | if (field == NULL) { | ||
67 | /* Cannot find "softexpires" event specific field in the event */ | ||
68 | } else { | ||
69 | /* Get softexpires parameter from the data record */ | ||
70 | softexpires = tep_read_number(tep, record->data + field->offset, | ||
71 | field->size); | ||
72 | } | ||
73 | |||
74 | field = tep_find_any_field(event, "mode"); | ||
75 | if (field == NULL) { | ||
76 | /* Cannot find "mode" field in the event */ | ||
77 | } else | ||
78 | { | ||
79 | /* Get mode parameter from the data record */ | ||
80 | mode = tep_read_number(tep, record->data + field->offset, | ||
81 | field->size); | ||
82 | } | ||
83 | } | ||
84 | ... | ||
85 | -- | ||
86 | |||
87 | FILES | ||
88 | ----- | ||
89 | [verse] | ||
90 | -- | ||
91 | *event-parse.h* | ||
92 | Header file to include in order to have access to the library APIs. | ||
93 | *-ltraceevent* | ||
94 | Linker switch to add when building a program that uses the library. | ||
95 | -- | ||
96 | |||
97 | SEE ALSO | ||
98 | -------- | ||
99 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
100 | |||
101 | AUTHOR | ||
102 | ------ | ||
103 | [verse] | ||
104 | -- | ||
105 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
106 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
107 | -- | ||
108 | REPORTING BUGS | ||
109 | -------------- | ||
110 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
111 | |||
112 | LICENSE | ||
113 | ------- | ||
114 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
115 | |||
116 | RESOURCES | ||
117 | --------- | ||
118 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-field_get_val.txt b/tools/lib/traceevent/Documentation/libtraceevent-field_get_val.txt new file mode 100644 index 000000000000..6324f0d48aeb --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-field_get_val.txt | |||
@@ -0,0 +1,122 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_get_any_field_val, tep_get_common_field_val, tep_get_field_val, | ||
7 | tep_get_field_raw - Get value of a field. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | *#include <trace-seq.h>* | ||
15 | |||
16 | int *tep_get_any_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_); | ||
17 | int *tep_get_common_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_); | ||
18 | int *tep_get_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_); | ||
19 | void pass:[*]*tep_get_field_raw*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int pass:[*]_len_, int _err_); | ||
20 | -- | ||
21 | |||
22 | DESCRIPTION | ||
23 | ----------- | ||
24 | These functions can be used to find a field and retrieve its value. | ||
25 | |||
26 | The _tep_get_any_field_val()_ function searches in the _record_ for a field | ||
27 | with _name_, part of the _event_. If the field is found, its value is stored in | ||
28 | _val_. If there is an error and _err_ is not zero, then an error string is | ||
29 | written into _s_. | ||
30 | |||
31 | The _tep_get_common_field_val()_ function does the same as | ||
32 | _tep_get_any_field_val()_, but searches only in the common fields. This works | ||
33 | for any event as all events include the common fields. | ||
34 | |||
35 | The _tep_get_field_val()_ function does the same as _tep_get_any_field_val()_, | ||
36 | but searches only in the event specific fields. | ||
37 | |||
38 | The _tep_get_field_raw()_ function searches in the _record_ for a field with | ||
39 | _name_, part of the _event_. If the field is found, a pointer to where the field | ||
40 | exists in the record's raw data is returned. The size of the data is stored in | ||
41 | _len_. If there is an error and _err_ is not zero, then an error string is | ||
42 | written into _s_. | ||
43 | |||
44 | RETURN VALUE | ||
45 | ------------ | ||
46 | The _tep_get_any_field_val()_, _tep_get_common_field_val()_ and | ||
47 | _tep_get_field_val()_ functions return 0 on success, or -1 in case of an error. | ||
48 | |||
49 | The _tep_get_field_raw()_ function returns a pointer to field's raw data, and | ||
50 | places the length of this data in _len_. In case of an error NULL is returned. | ||
51 | |||
52 | EXAMPLE | ||
53 | ------- | ||
54 | [source,c] | ||
55 | -- | ||
56 | #include <event-parse.h> | ||
57 | #include <trace-seq.h> | ||
58 | ... | ||
59 | struct tep_handle *tep = tep_alloc(); | ||
60 | ... | ||
61 | struct tep_event *event = tep_find_event_by_name(tep, "kvm", "kvm_exit"); | ||
62 | ... | ||
63 | void process_record(struct tep_record *record) | ||
64 | { | ||
65 | int len; | ||
66 | char *comm; | ||
67 | struct tep_event_format *event; | ||
68 | unsigned long long val; | ||
69 | |||
70 | event = tep_find_event_by_record(pevent, record); | ||
71 | if (event != NULL) { | ||
72 | if (tep_get_common_field_val(NULL, event, "common_type", | ||
73 | record, &val, 0) == 0) { | ||
74 | /* Got the value of common type field */ | ||
75 | } | ||
76 | if (tep_get_field_val(NULL, event, "pid", record, &val, 0) == 0) { | ||
77 | /* Got the value of pid specific field */ | ||
78 | } | ||
79 | comm = tep_get_field_raw(NULL, event, "comm", record, &len, 0); | ||
80 | if (comm != NULL) { | ||
81 | /* Got a pointer to the comm event specific field */ | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | -- | ||
86 | |||
87 | FILES | ||
88 | ----- | ||
89 | [verse] | ||
90 | -- | ||
91 | *event-parse.h* | ||
92 | Header file to include in order to have access to the library APIs. | ||
93 | *trace-seq.h* | ||
94 | Header file to include in order to have access to trace sequences | ||
95 | related APIs. Trace sequences are used to allow a function to call | ||
96 | several other functions to create a string of data to use. | ||
97 | *-ltraceevent* | ||
98 | Linker switch to add when building a program that uses the library. | ||
99 | -- | ||
100 | |||
101 | SEE ALSO | ||
102 | -------- | ||
103 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
104 | |||
105 | AUTHOR | ||
106 | ------ | ||
107 | [verse] | ||
108 | -- | ||
109 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
110 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
111 | -- | ||
112 | REPORTING BUGS | ||
113 | -------------- | ||
114 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
115 | |||
116 | LICENSE | ||
117 | ------- | ||
118 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
119 | |||
120 | RESOURCES | ||
121 | --------- | ||
122 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-field_print.txt b/tools/lib/traceevent/Documentation/libtraceevent-field_print.txt new file mode 100644 index 000000000000..9a9df98ac44d --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-field_print.txt | |||
@@ -0,0 +1,126 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_print_field, tep_print_fields, tep_print_num_field, tep_print_func_field - | ||
7 | Print the field content. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | *#include <trace-seq.h>* | ||
15 | |||
16 | void *tep_print_field*(struct trace_seq pass:[*]_s_, void pass:[*]_data_, struct tep_format_field pass:[*]_field_); | ||
17 | void *tep_print_fields*(struct trace_seq pass:[*]_s_, void pass:[*]_data_, int _size_, struct tep_event pass:[*]_event_); | ||
18 | int *tep_print_num_field*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int _err_); | ||
19 | int *tep_print_func_field*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int _err_); | ||
20 | -- | ||
21 | |||
22 | DESCRIPTION | ||
23 | ----------- | ||
24 | These functions print recorded field's data, according to the field's type. | ||
25 | |||
26 | The _tep_print_field()_ function extracts from the recorded raw _data_ value of | ||
27 | the _field_ and prints it into _s_, according to the field type. | ||
28 | |||
29 | The _tep_print_fields()_ prints each field name followed by the record's field | ||
30 | value according to the field's type: | ||
31 | [verse] | ||
32 | -- | ||
33 | "field1_name=field1_value field2_name=field2_value ..." | ||
34 | -- | ||
35 | It iterates all fields of the _event_, and calls _tep_print_field()_ for each of | ||
36 | them. | ||
37 | |||
38 | The _tep_print_num_field()_ function prints a numeric field with given format | ||
39 | string. A search is performed in the _event_ for a field with _name_. If such | ||
40 | field is found, its value is extracted from the _record_ and is printed in the | ||
41 | _s_, according to the given format string _fmt_. If the argument _err_ is | ||
42 | non-zero, and an error occures - it is printed in the _s_. | ||
43 | |||
44 | The _tep_print_func_field()_ function prints a function field with given format | ||
45 | string. A search is performed in the _event_ for a field with _name_. If such | ||
46 | field is found, its value is extracted from the _record_. The value is assumed | ||
47 | to be a function address, and a search is perform to find the name of this | ||
48 | function. The function name (if found) and its address are printed in the _s_, | ||
49 | according to the given format string _fmt_. If the argument _err_ is non-zero, | ||
50 | and an error occures - it is printed in _s_. | ||
51 | |||
52 | RETURN VALUE | ||
53 | ------------ | ||
54 | The _tep_print_num_field()_ and _tep_print_func_field()_ functions return 1 | ||
55 | on success, -1 in case of an error or 0 if the print buffer _s_ is full. | ||
56 | |||
57 | EXAMPLE | ||
58 | ------- | ||
59 | [source,c] | ||
60 | -- | ||
61 | #include <event-parse.h> | ||
62 | #include <trace-seq.h> | ||
63 | ... | ||
64 | struct tep_handle *tep = tep_alloc(); | ||
65 | ... | ||
66 | struct trace_seq seq; | ||
67 | trace_seq_init(&seq); | ||
68 | struct tep_event *event = tep_find_event_by_name(tep, "timer", "hrtimer_start"); | ||
69 | ... | ||
70 | void process_record(struct tep_record *record) | ||
71 | { | ||
72 | struct tep_format_field *field_pid = tep_find_common_field(event, "common_pid"); | ||
73 | |||
74 | trace_seq_reset(&seq); | ||
75 | |||
76 | /* Print the value of "common_pid" */ | ||
77 | tep_print_field(&seq, record->data, field_pid); | ||
78 | |||
79 | /* Print all fields of the "hrtimer_start" event */ | ||
80 | tep_print_fields(&seq, record->data, record->size, event); | ||
81 | |||
82 | /* Print the value of "expires" field with custom format string */ | ||
83 | tep_print_num_field(&seq, " timer expires in %llu ", event, "expires", record, 0); | ||
84 | |||
85 | /* Print the address and the name of "function" field with custom format string */ | ||
86 | tep_print_func_field(&seq, " timer function is %s ", event, "function", record, 0); | ||
87 | } | ||
88 | ... | ||
89 | -- | ||
90 | |||
91 | FILES | ||
92 | ----- | ||
93 | [verse] | ||
94 | -- | ||
95 | *event-parse.h* | ||
96 | Header file to include in order to have access to the library APIs. | ||
97 | *trace-seq.h* | ||
98 | Header file to include in order to have access to trace sequences related APIs. | ||
99 | Trace sequences are used to allow a function to call several other functions | ||
100 | to create a string of data to use. | ||
101 | *-ltraceevent* | ||
102 | Linker switch to add when building a program that uses the library. | ||
103 | -- | ||
104 | |||
105 | SEE ALSO | ||
106 | -------- | ||
107 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
108 | |||
109 | AUTHOR | ||
110 | ------ | ||
111 | [verse] | ||
112 | -- | ||
113 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
114 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
115 | -- | ||
116 | REPORTING BUGS | ||
117 | -------------- | ||
118 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
119 | |||
120 | LICENSE | ||
121 | ------- | ||
122 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
123 | |||
124 | RESOURCES | ||
125 | --------- | ||
126 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-field_read.txt b/tools/lib/traceevent/Documentation/libtraceevent-field_read.txt new file mode 100644 index 000000000000..64e9e25d3fd9 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-field_read.txt | |||
@@ -0,0 +1,81 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_read_number_field - Reads a number from raw data. | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | -- | ||
12 | *#include <event-parse.h>* | ||
13 | |||
14 | int *tep_read_number_field*(struct tep_format_field pass:[*]_field_, const void pass:[*]_data_, unsigned long long pass:[*]_value_); | ||
15 | -- | ||
16 | |||
17 | DESCRIPTION | ||
18 | ----------- | ||
19 | The _tep_read_number_field()_ function reads the value of the _field_ from the | ||
20 | raw _data_ and stores it in the _value_. The function sets the _value_ according | ||
21 | to the endianness of the raw data and the current machine and stores it in | ||
22 | _value_. | ||
23 | |||
24 | RETURN VALUE | ||
25 | ------------ | ||
26 | The _tep_read_number_field()_ function retunrs 0 in case of success, or -1 in | ||
27 | case of an error. | ||
28 | |||
29 | EXAMPLE | ||
30 | ------- | ||
31 | [source,c] | ||
32 | -- | ||
33 | #include <event-parse.h> | ||
34 | ... | ||
35 | struct tep_handle *tep = tep_alloc(); | ||
36 | ... | ||
37 | struct tep_event *event = tep_find_event_by_name(tep, "timer", "hrtimer_start"); | ||
38 | ... | ||
39 | void process_record(struct tep_record *record) | ||
40 | { | ||
41 | unsigned long long pid; | ||
42 | struct tep_format_field *field_pid = tep_find_common_field(event, "common_pid"); | ||
43 | |||
44 | if (tep_read_number_field(field_pid, record->data, &pid) != 0) { | ||
45 | /* Failed to get "common_pid" value */ | ||
46 | } | ||
47 | } | ||
48 | ... | ||
49 | -- | ||
50 | FILES | ||
51 | ----- | ||
52 | [verse] | ||
53 | -- | ||
54 | *event-parse.h* | ||
55 | Header file to include in order to have access to the library APIs. | ||
56 | *-ltraceevent* | ||
57 | Linker switch to add when building a program that uses the library. | ||
58 | -- | ||
59 | |||
60 | SEE ALSO | ||
61 | -------- | ||
62 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
63 | |||
64 | AUTHOR | ||
65 | ------ | ||
66 | [verse] | ||
67 | -- | ||
68 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
69 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
70 | -- | ||
71 | REPORTING BUGS | ||
72 | -------------- | ||
73 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
74 | |||
75 | LICENSE | ||
76 | ------- | ||
77 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
78 | |||
79 | RESOURCES | ||
80 | --------- | ||
81 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-fields.txt b/tools/lib/traceevent/Documentation/libtraceevent-fields.txt new file mode 100644 index 000000000000..1ccb531d5114 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-fields.txt | |||
@@ -0,0 +1,105 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_event_common_fields, tep_event_fields - Get a list of fields for an event. | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | -- | ||
12 | *#include <event-parse.h>* | ||
13 | |||
14 | struct tep_format_field pass:[*]pass:[*]*tep_event_common_fields*(struct tep_event pass:[*]_event_); | ||
15 | struct tep_format_field pass:[*]pass:[*]*tep_event_fields*(struct tep_event pass:[*]_event_); | ||
16 | -- | ||
17 | |||
18 | DESCRIPTION | ||
19 | ----------- | ||
20 | The _tep_event_common_fields()_ function returns an array of pointers to common | ||
21 | fields for the _event_. The array is allocated in the function and must be freed | ||
22 | by free(). The last element of the array is NULL. | ||
23 | |||
24 | The _tep_event_fields()_ function returns an array of pointers to event specific | ||
25 | fields for the _event_. The array is allocated in the function and must be freed | ||
26 | by free(). The last element of the array is NULL. | ||
27 | |||
28 | RETURN VALUE | ||
29 | ------------ | ||
30 | Both _tep_event_common_fields()_ and _tep_event_fields()_ functions return | ||
31 | an array of pointers to tep_format_field structures in case of success, or | ||
32 | NULL in case of an error. | ||
33 | |||
34 | EXAMPLE | ||
35 | ------- | ||
36 | [source,c] | ||
37 | -- | ||
38 | #include <event-parse.h> | ||
39 | ... | ||
40 | struct tep_handle *tep = tep_alloc(); | ||
41 | ... | ||
42 | int i; | ||
43 | struct tep_format_field **fields; | ||
44 | struct tep_event *event = tep_find_event_by_name(tep, "kvm", "kvm_exit"); | ||
45 | if (event != NULL) { | ||
46 | fields = tep_event_common_fields(event); | ||
47 | if (fields != NULL) { | ||
48 | i = 0; | ||
49 | while (fields[i]) { | ||
50 | /* | ||
51 | walk through the list of the common fields | ||
52 | of the kvm_exit event | ||
53 | */ | ||
54 | i++; | ||
55 | } | ||
56 | free(fields); | ||
57 | } | ||
58 | fields = tep_event_fields(event); | ||
59 | if (fields != NULL) { | ||
60 | i = 0; | ||
61 | while (fields[i]) { | ||
62 | /* | ||
63 | walk through the list of the event specific | ||
64 | fields of the kvm_exit event | ||
65 | */ | ||
66 | i++; | ||
67 | } | ||
68 | free(fields); | ||
69 | } | ||
70 | } | ||
71 | ... | ||
72 | -- | ||
73 | |||
74 | FILES | ||
75 | ----- | ||
76 | [verse] | ||
77 | -- | ||
78 | *event-parse.h* | ||
79 | Header file to include in order to have access to the library APIs. | ||
80 | *-ltraceevent* | ||
81 | Linker switch to add when building a program that uses the library. | ||
82 | -- | ||
83 | |||
84 | SEE ALSO | ||
85 | -------- | ||
86 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
87 | |||
88 | AUTHOR | ||
89 | ------ | ||
90 | [verse] | ||
91 | -- | ||
92 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
93 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
94 | -- | ||
95 | REPORTING BUGS | ||
96 | -------------- | ||
97 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
98 | |||
99 | LICENSE | ||
100 | ------- | ||
101 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
102 | |||
103 | RESOURCES | ||
104 | --------- | ||
105 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-file_endian.txt b/tools/lib/traceevent/Documentation/libtraceevent-file_endian.txt new file mode 100644 index 000000000000..f401ad311047 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-file_endian.txt | |||
@@ -0,0 +1,91 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_is_file_bigendian, tep_set_file_bigendian - Get / set the endianness of the | ||
7 | raw data being accessed by the tep handler. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | enum *tep_endian* { | ||
16 | TEP_LITTLE_ENDIAN = 0, | ||
17 | TEP_BIG_ENDIAN | ||
18 | }; | ||
19 | |||
20 | bool *tep_is_file_bigendian*(struct tep_handle pass:[*]_tep_); | ||
21 | void *tep_set_file_bigendian*(struct tep_handle pass:[*]_tep_, enum tep_endian _endian_); | ||
22 | |||
23 | -- | ||
24 | DESCRIPTION | ||
25 | ----------- | ||
26 | The _tep_is_file_bigendian()_ function gets the endianness of the raw data, | ||
27 | being accessed by the tep handler. The _tep_ argument is trace event parser | ||
28 | context. | ||
29 | |||
30 | The _tep_set_file_bigendian()_ function sets the endianness of raw data being | ||
31 | accessed by the tep handler. The _tep_ argument is trace event parser context. | ||
32 | [verse] | ||
33 | -- | ||
34 | The _endian_ argument is the endianness: | ||
35 | _TEP_LITTLE_ENDIAN_ - the raw data is in little endian format, | ||
36 | _TEP_BIG_ENDIAN_ - the raw data is in big endian format. | ||
37 | -- | ||
38 | RETURN VALUE | ||
39 | ------------ | ||
40 | The _tep_is_file_bigendian()_ function returns true if the data is in bigendian | ||
41 | format, false otherwise. | ||
42 | |||
43 | EXAMPLE | ||
44 | ------- | ||
45 | [source,c] | ||
46 | -- | ||
47 | #include <event-parse.h> | ||
48 | ... | ||
49 | struct tep_handle *tep = tep_alloc(); | ||
50 | ... | ||
51 | tep_set_file_bigendian(tep, TEP_LITTLE_ENDIAN); | ||
52 | ... | ||
53 | if (tep_is_file_bigendian(tep)) { | ||
54 | /* The raw data is in big endian */ | ||
55 | } else { | ||
56 | /* The raw data is in little endian */ | ||
57 | } | ||
58 | -- | ||
59 | |||
60 | FILES | ||
61 | ----- | ||
62 | [verse] | ||
63 | -- | ||
64 | *event-parse.h* | ||
65 | Header file to include in order to have access to the library APIs. | ||
66 | *-ltraceevent* | ||
67 | Linker switch to add when building a program that uses the library. | ||
68 | -- | ||
69 | |||
70 | SEE ALSO | ||
71 | -------- | ||
72 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
73 | |||
74 | AUTHOR | ||
75 | ------ | ||
76 | [verse] | ||
77 | -- | ||
78 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
79 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
80 | -- | ||
81 | REPORTING BUGS | ||
82 | -------------- | ||
83 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
84 | |||
85 | LICENSE | ||
86 | ------- | ||
87 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
88 | |||
89 | RESOURCES | ||
90 | --------- | ||
91 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-filter.txt b/tools/lib/traceevent/Documentation/libtraceevent-filter.txt new file mode 100644 index 000000000000..4a9962d8cb59 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-filter.txt | |||
@@ -0,0 +1,209 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_filter_alloc, tep_filter_free, tep_filter_reset, tep_filter_make_string, | ||
7 | tep_filter_copy, tep_filter_compare, tep_filter_match, tep_event_filtered, | ||
8 | tep_filter_remove_event, tep_filter_strerror, tep_filter_add_filter_str - | ||
9 | Event filter related APIs. | ||
10 | |||
11 | SYNOPSIS | ||
12 | -------- | ||
13 | [verse] | ||
14 | -- | ||
15 | *#include <event-parse.h>* | ||
16 | |||
17 | struct tep_event_filter pass:[*]*tep_filter_alloc*(struct tep_handle pass:[*]_tep_); | ||
18 | void *tep_filter_free*(struct tep_event_filter pass:[*]_filter_); | ||
19 | void *tep_filter_reset*(struct tep_event_filter pass:[*]_filter_); | ||
20 | enum tep_errno *tep_filter_add_filter_str*(struct tep_event_filter pass:[*]_filter_, const char pass:[*]_filter_str_); | ||
21 | int *tep_event_filtered*(struct tep_event_filter pass:[*]_filter_, int _event_id_); | ||
22 | int *tep_filter_remove_event*(struct tep_event_filter pass:[*]_filter_, int _event_id_); | ||
23 | enum tep_errno *tep_filter_match*(struct tep_event_filter pass:[*]_filter_, struct tep_record pass:[*]_record_); | ||
24 | int *tep_filter_copy*(struct tep_event_filter pass:[*]_dest_, struct tep_event_filter pass:[*]_source_); | ||
25 | int *tep_filter_compare*(struct tep_event_filter pass:[*]_filter1_, struct tep_event_filter pass:[*]_filter2_); | ||
26 | char pass:[*]*tep_filter_make_string*(struct tep_event_filter pass:[*]_filter_, int _event_id_); | ||
27 | int *tep_filter_strerror*(struct tep_event_filter pass:[*]_filter_, enum tep_errno _err_, char pass:[*]buf, size_t _buflen_); | ||
28 | -- | ||
29 | |||
30 | DESCRIPTION | ||
31 | ----------- | ||
32 | Filters can be attached to traced events. They can be used to filter out various | ||
33 | events when outputting them. Each event can be filtered based on its parameters, | ||
34 | described in the event's format file. This set of functions can be used to | ||
35 | create, delete, modify and attach event filters. | ||
36 | |||
37 | The _tep_filter_alloc()_ function creates a new event filter. The _tep_ argument | ||
38 | is the trace event parser context. | ||
39 | |||
40 | The _tep_filter_free()_ function frees an event filter and all resources that it | ||
41 | had used. | ||
42 | |||
43 | The _tep_filter_reset()_ function removes all rules from an event filter and | ||
44 | resets it. | ||
45 | |||
46 | The _tep_filter_add_filter_str()_ function adds a new rule to the _filter_. The | ||
47 | _filter_str_ argument is the filter string, that contains the rule. | ||
48 | |||
49 | The _tep_event_filtered()_ function checks if the event with _event_id_ has | ||
50 | _filter_. | ||
51 | |||
52 | The _tep_filter_remove_event()_ function removes a _filter_ for an event with | ||
53 | _event_id_. | ||
54 | |||
55 | The _tep_filter_match()_ function tests if a _record_ matches given _filter_. | ||
56 | |||
57 | The _tep_filter_copy()_ function copies a _source_ filter into a _dest_ filter. | ||
58 | |||
59 | The _tep_filter_compare()_ function compares two filers - _filter1_ and _filter2_. | ||
60 | |||
61 | The _tep_filter_make_string()_ function constructs a string, displaying | ||
62 | the _filter_ contents for given _event_id_. | ||
63 | |||
64 | The _tep_filter_strerror()_ function copies the _filter_ error buffer into the | ||
65 | given _buf_ with the size _buflen_. If the error buffer is empty, in the _buf_ | ||
66 | is copied a string, describing the error _err_. | ||
67 | |||
68 | RETURN VALUE | ||
69 | ------------ | ||
70 | The _tep_filter_alloc()_ function returns a pointer to the newly created event | ||
71 | filter, or NULL in case of an error. | ||
72 | |||
73 | The _tep_filter_add_filter_str()_ function returns 0 if the rule was | ||
74 | successfully added or a negative error code. Use _tep_filter_strerror()_ to see | ||
75 | actual error message in case of an error. | ||
76 | |||
77 | The _tep_event_filtered()_ function returns 1 if the filter is found for given | ||
78 | event, or 0 otherwise. | ||
79 | |||
80 | The _tep_filter_remove_event()_ function returns 1 if the vent was removed, or | ||
81 | 0 if the event was not found. | ||
82 | |||
83 | The _tep_filter_match()_ function returns _tep_errno_, according to the result: | ||
84 | [verse] | ||
85 | -- | ||
86 | _pass:[TEP_ERRNO__FILTER_MATCH]_ - filter found for event, the record matches. | ||
87 | _pass:[TEP_ERRNO__FILTER_MISS]_ - filter found for event, the record does not match. | ||
88 | _pass:[TEP_ERRNO__FILTER_NOT_FOUND]_ - no filter found for record's event. | ||
89 | _pass:[TEP_ERRNO__NO_FILTER]_ - no rules in the filter. | ||
90 | -- | ||
91 | or any other _tep_errno_, if an error occurred during the test. | ||
92 | |||
93 | The _tep_filter_copy()_ function returns 0 on success or -1 if not all rules | ||
94 | were copied. | ||
95 | |||
96 | The _tep_filter_compare()_ function returns 1 if the two filters hold the same | ||
97 | content, or 0 if they do not. | ||
98 | |||
99 | The _tep_filter_make_string()_ function returns a string, which must be freed | ||
100 | with free(), or NULL in case of an error. | ||
101 | |||
102 | The _tep_filter_strerror()_ function returns 0 if message was filled | ||
103 | successfully, or -1 in case of an error. | ||
104 | |||
105 | EXAMPLE | ||
106 | ------- | ||
107 | [source,c] | ||
108 | -- | ||
109 | #include <event-parse.h> | ||
110 | ... | ||
111 | struct tep_handle *tep = tep_alloc(); | ||
112 | ... | ||
113 | char errstr[200]; | ||
114 | int ret; | ||
115 | |||
116 | struct tep_event_filter *filter = tep_filter_alloc(tep); | ||
117 | struct tep_event_filter *filter1 = tep_filter_alloc(tep); | ||
118 | ret = tep_filter_add_filter_str(filter, "sched/sched_wakeup:target_cpu==1"); | ||
119 | if(ret < 0) { | ||
120 | tep_filter_strerror(filter, ret, errstr, sizeof(errstr)); | ||
121 | /* Failed to add a new rule to the filter, the error string is in errstr */ | ||
122 | } | ||
123 | if (tep_filter_copy(filter1, filter) != 0) { | ||
124 | /* Failed to copy filter in filter1 */ | ||
125 | } | ||
126 | ... | ||
127 | if (tep_filter_compare(filter, filter1) != 1) { | ||
128 | /* Both filters are different */ | ||
129 | } | ||
130 | ... | ||
131 | void process_record(struct tep_handle *tep, struct tep_record *record) | ||
132 | { | ||
133 | struct tep_event *event; | ||
134 | char *fstring; | ||
135 | |||
136 | event = tep_find_event_by_record(tep, record); | ||
137 | |||
138 | if (tep_event_filtered(filter, event->id) == 1) { | ||
139 | /* The event has filter */ | ||
140 | fstring = tep_filter_make_string(filter, event->id); | ||
141 | if (fstring != NULL) { | ||
142 | /* The filter for the event is in fstring */ | ||
143 | free(fstring); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | switch (tep_filter_match(filter, record)) { | ||
148 | case TEP_ERRNO__FILTER_MATCH: | ||
149 | /* The filter matches the record */ | ||
150 | break; | ||
151 | case TEP_ERRNO__FILTER_MISS: | ||
152 | /* The filter does not match the record */ | ||
153 | break; | ||
154 | case TEP_ERRNO__FILTER_NOT_FOUND: | ||
155 | /* No filter found for record's event */ | ||
156 | break; | ||
157 | case TEP_ERRNO__NO_FILTER: | ||
158 | /* There are no rules in the filter */ | ||
159 | break | ||
160 | default: | ||
161 | /* An error occurred during the test */ | ||
162 | break; | ||
163 | } | ||
164 | |||
165 | if (tep_filter_remove_event(filter, event->id) == 1) { | ||
166 | /* The event was removed from the filter */ | ||
167 | } | ||
168 | } | ||
169 | |||
170 | ... | ||
171 | tep_filter_reset(filter); | ||
172 | ... | ||
173 | tep_filter_free(filter); | ||
174 | tep_filter_free(filter1); | ||
175 | ... | ||
176 | -- | ||
177 | |||
178 | FILES | ||
179 | ----- | ||
180 | [verse] | ||
181 | -- | ||
182 | *event-parse.h* | ||
183 | Header file to include in order to have access to the library APIs. | ||
184 | *-ltraceevent* | ||
185 | Linker switch to add when building a program that uses the library. | ||
186 | -- | ||
187 | |||
188 | SEE ALSO | ||
189 | -------- | ||
190 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
191 | |||
192 | AUTHOR | ||
193 | ------ | ||
194 | [verse] | ||
195 | -- | ||
196 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
197 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
198 | -- | ||
199 | REPORTING BUGS | ||
200 | -------------- | ||
201 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
202 | |||
203 | LICENSE | ||
204 | ------- | ||
205 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
206 | |||
207 | RESOURCES | ||
208 | --------- | ||
209 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt b/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt new file mode 100644 index 000000000000..38bfea30a5f6 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt | |||
@@ -0,0 +1,183 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_find_function, tep_find_function_address, tep_set_function_resolver, | ||
7 | tep_reset_function_resolver, tep_register_function, tep_register_print_string - | ||
8 | function related tep APIs | ||
9 | |||
10 | SYNOPSIS | ||
11 | -------- | ||
12 | [verse] | ||
13 | -- | ||
14 | *#include <event-parse.h>* | ||
15 | |||
16 | typedef char pass:[*](*tep_func_resolver_t*)(void pass:[*]_priv_, unsigned long long pass:[*]_addrp_, char pass:[**]_modp_); | ||
17 | int *tep_set_function_resolver*(struct tep_handle pass:[*]_tep_, tep_func_resolver_t pass:[*]_func_, void pass:[*]_priv_); | ||
18 | void *tep_reset_function_resolver*(struct tep_handle pass:[*]_tep_); | ||
19 | const char pass:[*]*tep_find_function*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_); | ||
20 | unsigned long long *tep_find_function_address*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_); | ||
21 | int *tep_register_function*(struct tep_handle pass:[*]_tep_, char pass:[*]_name_, unsigned long long _addr_, char pass:[*]_mod_); | ||
22 | int *tep_register_print_string*(struct tep_handle pass:[*]_tep_, const char pass:[*]_fmt_, unsigned long long _addr_); | ||
23 | -- | ||
24 | |||
25 | DESCRIPTION | ||
26 | ----------- | ||
27 | Some tools may have already a way to resolve the kernel functions. These APIs | ||
28 | allow them to keep using it instead of duplicating all the entries inside. | ||
29 | |||
30 | The _tep_func_resolver_t_ type is the prototype of the alternative kernel | ||
31 | functions resolver. This function receives a pointer to its custom context | ||
32 | (set with the _tep_set_function_resolver()_ call ) and the address of a kernel | ||
33 | function, which has to be resolved. In case of success, it should return | ||
34 | the name of the function and its module (if any) in _modp_. | ||
35 | |||
36 | The _tep_set_function_resolver()_ function registers _func_ as an alternative | ||
37 | kernel functions resolver. The _tep_ argument is trace event parser context. | ||
38 | The _priv_ argument is a custom context of the _func_ function. The function | ||
39 | resolver is used by the APIs _tep_find_function()_, | ||
40 | _tep_find_function_address()_, and _tep_print_func_field()_ to resolve | ||
41 | a function address to a function name. | ||
42 | |||
43 | The _tep_reset_function_resolver()_ function resets the kernel functions | ||
44 | resolver to the default function. The _tep_ argument is trace event parser | ||
45 | context. | ||
46 | |||
47 | |||
48 | These APIs can be used to find function name and start address, by given | ||
49 | address. The given address does not have to be exact, it will select | ||
50 | the function that would contain it. | ||
51 | |||
52 | The _tep_find_function()_ function returns the function name, which contains the | ||
53 | given address _addr_. The _tep_ argument is the trace event parser context. | ||
54 | |||
55 | The _tep_find_function_address()_ function returns the function start address, | ||
56 | by given address _addr_. The _addr_ does not have to be exact, it will select | ||
57 | the function that would contain it. The _tep_ argument is the trace event | ||
58 | parser context. | ||
59 | |||
60 | The _tep_register_function()_ function registers a function name mapped to an | ||
61 | address and (optional) module. This mapping is used in case the function tracer | ||
62 | or events have "%pF" or "%pS" parameter in its format string. It is common to | ||
63 | pass in the kallsyms function names with their corresponding addresses with this | ||
64 | function. The _tep_ argument is the trace event parser context. The _name_ is | ||
65 | the name of the function, the string is copied internally. The _addr_ is | ||
66 | the start address of the function. The _mod_ is the kernel module | ||
67 | the function may be in (NULL for none). | ||
68 | |||
69 | The _tep_register_print_string()_ function registers a string by the address | ||
70 | it was stored in the kernel. Some strings internal to the kernel with static | ||
71 | address are passed to certain events. The "%s" in the event's format field | ||
72 | which has an address needs to know what string would be at that address. The | ||
73 | tep_register_print_string() supplies the parsing with the mapping between kernel | ||
74 | addresses and those strings. The _tep_ argument is the trace event parser | ||
75 | context. The _fmt_ is the string to register, it is copied internally. | ||
76 | The _addr_ is the address the string was located at. | ||
77 | |||
78 | |||
79 | RETURN VALUE | ||
80 | ------------ | ||
81 | The _tep_set_function_resolver()_ function returns 0 in case of success, or -1 | ||
82 | in case of an error. | ||
83 | |||
84 | The _tep_find_function()_ function returns the function name, or NULL in case | ||
85 | it cannot be found. | ||
86 | |||
87 | The _tep_find_function_address()_ function returns the function start address, | ||
88 | or 0 in case it cannot be found. | ||
89 | |||
90 | The _tep_register_function()_ function returns 0 in case of success. In case of | ||
91 | an error -1 is returned, and errno is set to the appropriate error number. | ||
92 | |||
93 | The _tep_register_print_string()_ function returns 0 in case of success. In case | ||
94 | of an error -1 is returned, and errno is set to the appropriate error number. | ||
95 | |||
96 | EXAMPLE | ||
97 | ------- | ||
98 | [source,c] | ||
99 | -- | ||
100 | #include <event-parse.h> | ||
101 | ... | ||
102 | struct tep_handle *tep = tep_alloc(); | ||
103 | ... | ||
104 | char *my_resolve_kernel_addr(void *context, | ||
105 | unsigned long long *addrp, char **modp) | ||
106 | { | ||
107 | struct db *function_database = context; | ||
108 | struct symbol *sym = sql_lookup(function_database, *addrp); | ||
109 | |||
110 | if (!sym) | ||
111 | return NULL; | ||
112 | |||
113 | *modp = sym->module_name; | ||
114 | return sym->name; | ||
115 | } | ||
116 | |||
117 | void show_function( unsigned long long addr) | ||
118 | { | ||
119 | unsigned long long fstart; | ||
120 | const char *fname; | ||
121 | |||
122 | if (tep_set_function_resolver(tep, my_resolve_kernel_addr, | ||
123 | function_database) != 0) { | ||
124 | /* failed to register my_resolve_kernel_addr */ | ||
125 | } | ||
126 | |||
127 | /* These APIs use my_resolve_kernel_addr() to resolve the addr */ | ||
128 | fname = tep_find_function(tep, addr); | ||
129 | fstart = tep_find_function_address(tep, addr); | ||
130 | |||
131 | /* | ||
132 | addr is in function named fname, starting at fstart address, | ||
133 | at offset (addr - fstart) | ||
134 | */ | ||
135 | |||
136 | tep_reset_function_resolver(tep); | ||
137 | |||
138 | } | ||
139 | ... | ||
140 | if (tep_register_function(tep, "kvm_exit", | ||
141 | (unsigned long long) 0x12345678, "kvm") != 0) { | ||
142 | /* Failed to register kvm_exit address mapping */ | ||
143 | } | ||
144 | ... | ||
145 | if (tep_register_print_string(tep, "print string", | ||
146 | (unsigned long long) 0x87654321, NULL) != 0) { | ||
147 | /* Failed to register "print string" address mapping */ | ||
148 | } | ||
149 | ... | ||
150 | -- | ||
151 | |||
152 | FILES | ||
153 | ----- | ||
154 | [verse] | ||
155 | -- | ||
156 | *event-parse.h* | ||
157 | Header file to include in order to have access to the library APIs. | ||
158 | *-ltraceevent* | ||
159 | Linker switch to add when building a program that uses the library. | ||
160 | -- | ||
161 | |||
162 | SEE ALSO | ||
163 | -------- | ||
164 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
165 | |||
166 | AUTHOR | ||
167 | ------ | ||
168 | [verse] | ||
169 | -- | ||
170 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
171 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
172 | -- | ||
173 | REPORTING BUGS | ||
174 | -------------- | ||
175 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
176 | |||
177 | LICENSE | ||
178 | ------- | ||
179 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
180 | |||
181 | RESOURCES | ||
182 | --------- | ||
183 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-func_find.txt b/tools/lib/traceevent/Documentation/libtraceevent-func_find.txt new file mode 100644 index 000000000000..04840e244445 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-func_find.txt | |||
@@ -0,0 +1,88 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_find_function,tep_find_function_address - Find function name / start address. | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | -- | ||
12 | *#include <event-parse.h>* | ||
13 | |||
14 | const char pass:[*]*tep_find_function*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_); | ||
15 | unsigned long long *tep_find_function_address*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_); | ||
16 | -- | ||
17 | |||
18 | DESCRIPTION | ||
19 | ----------- | ||
20 | These functions can be used to find function name and start address, by given | ||
21 | address. The given address does not have to be exact, it will select the function | ||
22 | that would contain it. | ||
23 | |||
24 | The _tep_find_function()_ function returns the function name, which contains the | ||
25 | given address _addr_. The _tep_ argument is the trace event parser context. | ||
26 | |||
27 | The _tep_find_function_address()_ function returns the function start address, | ||
28 | by given address _addr_. The _addr_ does not have to be exact, it will select the | ||
29 | function that would contain it. The _tep_ argument is the trace event parser context. | ||
30 | |||
31 | RETURN VALUE | ||
32 | ------------ | ||
33 | The _tep_find_function()_ function returns the function name, or NULL in case | ||
34 | it cannot be found. | ||
35 | |||
36 | The _tep_find_function_address()_ function returns the function start address, | ||
37 | or 0 in case it cannot be found. | ||
38 | |||
39 | EXAMPLE | ||
40 | ------- | ||
41 | [source,c] | ||
42 | -- | ||
43 | #include <event-parse.h> | ||
44 | ... | ||
45 | struct tep_handle *tep = tep_alloc(); | ||
46 | ... | ||
47 | void show_function( unsigned long long addr) | ||
48 | { | ||
49 | const char *fname = tep_find_function(tep, addr); | ||
50 | unsigned long long fstart = tep_find_function_address(tep, addr); | ||
51 | |||
52 | /* addr is in function named fname, starting at fstart address, at offset (addr - fstart) */ | ||
53 | } | ||
54 | ... | ||
55 | -- | ||
56 | |||
57 | FILES | ||
58 | ----- | ||
59 | [verse] | ||
60 | -- | ||
61 | *event-parse.h* | ||
62 | Header file to include in order to have access to the library APIs. | ||
63 | *-ltraceevent* | ||
64 | Linker switch to add when building a program that uses the library. | ||
65 | -- | ||
66 | |||
67 | SEE ALSO | ||
68 | -------- | ||
69 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
70 | |||
71 | AUTHOR | ||
72 | ------ | ||
73 | [verse] | ||
74 | -- | ||
75 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
76 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
77 | -- | ||
78 | REPORTING BUGS | ||
79 | -------------- | ||
80 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
81 | |||
82 | LICENSE | ||
83 | ------- | ||
84 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
85 | |||
86 | RESOURCES | ||
87 | --------- | ||
88 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-handle.txt b/tools/lib/traceevent/Documentation/libtraceevent-handle.txt new file mode 100644 index 000000000000..8d568316847d --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-handle.txt | |||
@@ -0,0 +1,101 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_alloc, tep_free,tep_ref, tep_unref,tep_ref_get - Create, destroy, manage | ||
7 | references of trace event parser context. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | struct tep_handle pass:[*]*tep_alloc*(void); | ||
16 | void *tep_free*(struct tep_handle pass:[*]_tep_); | ||
17 | void *tep_ref*(struct tep_handle pass:[*]_tep_); | ||
18 | void *tep_unref*(struct tep_handle pass:[*]_tep_); | ||
19 | int *tep_ref_get*(struct tep_handle pass:[*]_tep_); | ||
20 | -- | ||
21 | |||
22 | DESCRIPTION | ||
23 | ----------- | ||
24 | These are the main functions to create and destroy tep_handle - the main | ||
25 | structure, representing the trace event parser context. This context is used as | ||
26 | the input parameter of most library APIs. | ||
27 | |||
28 | The _tep_alloc()_ function allocates and initializes the tep context. | ||
29 | |||
30 | The _tep_free()_ function will decrement the reference of the _tep_ handler. | ||
31 | When there is no more references, then it will free the handler, as well | ||
32 | as clean up all its resources that it had used. The argument _tep_ is | ||
33 | the pointer to the trace event parser context. | ||
34 | |||
35 | The _tep_ref()_ function adds a reference to the _tep_ handler. | ||
36 | |||
37 | The _tep_unref()_ function removes a reference from the _tep_ handler. When | ||
38 | the last reference is removed, the _tep_ is destroyed, and all resources that | ||
39 | it had used are cleaned up. | ||
40 | |||
41 | The _tep_ref_get()_ functions gets the current references of the _tep_ handler. | ||
42 | |||
43 | RETURN VALUE | ||
44 | ------------ | ||
45 | _tep_alloc()_ returns a pointer to a newly created tep_handle structure. | ||
46 | NULL is returned in case there is not enough free memory to allocate it. | ||
47 | |||
48 | _tep_ref_get()_ returns the current references of _tep_. | ||
49 | If _tep_ is NULL, 0 is returned. | ||
50 | |||
51 | EXAMPLE | ||
52 | ------- | ||
53 | [source,c] | ||
54 | -- | ||
55 | #include <event-parse.h> | ||
56 | |||
57 | ... | ||
58 | struct tep_handle *tep = tep_alloc(); | ||
59 | ... | ||
60 | int ref = tep_ref_get(tep); | ||
61 | tep_ref(tep); | ||
62 | if ( (ref+1) != tep_ref_get(tep)) { | ||
63 | /* Something wrong happened, the counter is not incremented by 1 */ | ||
64 | } | ||
65 | tep_unref(tep); | ||
66 | ... | ||
67 | tep_free(tep); | ||
68 | ... | ||
69 | -- | ||
70 | FILES | ||
71 | ----- | ||
72 | [verse] | ||
73 | -- | ||
74 | *event-parse.h* | ||
75 | Header file to include in order to have access to the library APIs. | ||
76 | *-ltraceevent* | ||
77 | Linker switch to add when building a program that uses the library. | ||
78 | -- | ||
79 | |||
80 | SEE ALSO | ||
81 | -------- | ||
82 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
83 | |||
84 | AUTHOR | ||
85 | ------ | ||
86 | [verse] | ||
87 | -- | ||
88 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
89 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
90 | -- | ||
91 | REPORTING BUGS | ||
92 | -------------- | ||
93 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
94 | |||
95 | LICENSE | ||
96 | ------- | ||
97 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
98 | |||
99 | RESOURCES | ||
100 | --------- | ||
101 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-header_page.txt b/tools/lib/traceevent/Documentation/libtraceevent-header_page.txt new file mode 100644 index 000000000000..615d117dc39f --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-header_page.txt | |||
@@ -0,0 +1,102 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_get_header_page_size, tep_get_header_timestamp_size, tep_is_old_format - | ||
7 | Get the data stored in the header page, in kernel context. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | int *tep_get_header_page_size*(struct tep_handle pass:[*]_tep_); | ||
16 | int *tep_get_header_timestamp_size*(struct tep_handle pass:[*]_tep_); | ||
17 | bool *tep_is_old_format*(struct tep_handle pass:[*]_tep_); | ||
18 | -- | ||
19 | DESCRIPTION | ||
20 | ----------- | ||
21 | These functions retrieve information from kernel context, stored in tracefs | ||
22 | events/header_page. Old kernels do not have header page info, so default values | ||
23 | from user space context are used. | ||
24 | |||
25 | The _tep_get_header_page_size()_ function returns the size of a long integer, | ||
26 | in kernel context. The _tep_ argument is trace event parser context. | ||
27 | This information is retrieved from tracefs events/header_page, "commit" field. | ||
28 | |||
29 | The _tep_get_header_timestamp_size()_ function returns the size of timestamps, | ||
30 | in kernel context. The _tep_ argument is trace event parser context. This | ||
31 | information is retrieved from tracefs events/header_page, "timestamp" field. | ||
32 | |||
33 | The _tep_is_old_format()_ function returns true if the kernel predates | ||
34 | the addition of events/header_page, otherwise it returns false. | ||
35 | |||
36 | RETURN VALUE | ||
37 | ------------ | ||
38 | The _tep_get_header_page_size()_ function returns the size of a long integer, | ||
39 | in bytes. | ||
40 | |||
41 | The _tep_get_header_timestamp_size()_ function returns the size of timestamps, | ||
42 | in bytes. | ||
43 | |||
44 | The _tep_is_old_format()_ function returns true, if an old kernel is used to | ||
45 | generate the tracing data, which has no event/header_page. If the kernel is new, | ||
46 | or _tep_ is NULL, false is returned. | ||
47 | |||
48 | EXAMPLE | ||
49 | ------- | ||
50 | [source,c] | ||
51 | -- | ||
52 | #include <event-parse.h> | ||
53 | ... | ||
54 | struct tep_handle *tep = tep_alloc(); | ||
55 | ... | ||
56 | int longsize; | ||
57 | int timesize; | ||
58 | bool old; | ||
59 | |||
60 | longsize = tep_get_header_page_size(tep); | ||
61 | timesize = tep_get_header_timestamp_size(tep); | ||
62 | old = tep_is_old_format(tep); | ||
63 | |||
64 | printf ("%s kernel is used to generate the tracing data.\n", | ||
65 | old?"Old":"New"); | ||
66 | printf("The size of a long integer is %d bytes.\n", longsize); | ||
67 | printf("The timestamps size is %d bytes.\n", timesize); | ||
68 | ... | ||
69 | -- | ||
70 | |||
71 | FILES | ||
72 | ----- | ||
73 | [verse] | ||
74 | -- | ||
75 | *event-parse.h* | ||
76 | Header file to include in order to have access to the library APIs. | ||
77 | *-ltraceevent* | ||
78 | Linker switch to add when building a program that uses the library. | ||
79 | -- | ||
80 | |||
81 | SEE ALSO | ||
82 | -------- | ||
83 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
84 | |||
85 | AUTHOR | ||
86 | ------ | ||
87 | [verse] | ||
88 | -- | ||
89 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
90 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
91 | -- | ||
92 | REPORTING BUGS | ||
93 | -------------- | ||
94 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
95 | |||
96 | LICENSE | ||
97 | ------- | ||
98 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
99 | |||
100 | RESOURCES | ||
101 | --------- | ||
102 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-host_endian.txt b/tools/lib/traceevent/Documentation/libtraceevent-host_endian.txt new file mode 100644 index 000000000000..d5d375eb8d1e --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-host_endian.txt | |||
@@ -0,0 +1,104 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_is_bigendian, tep_is_local_bigendian, tep_set_local_bigendian - Get / set | ||
7 | the endianness of the local machine. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | enum *tep_endian* { | ||
16 | TEP_LITTLE_ENDIAN = 0, | ||
17 | TEP_BIG_ENDIAN | ||
18 | }; | ||
19 | |||
20 | int *tep_is_bigendian*(void); | ||
21 | bool *tep_is_local_bigendian*(struct tep_handle pass:[*]_tep_); | ||
22 | void *tep_set_local_bigendian*(struct tep_handle pass:[*]_tep_, enum tep_endian _endian_); | ||
23 | -- | ||
24 | |||
25 | DESCRIPTION | ||
26 | ----------- | ||
27 | |||
28 | The _tep_is_bigendian()_ gets the endianness of the machine, executing | ||
29 | the function. | ||
30 | |||
31 | The _tep_is_local_bigendian()_ function gets the endianness of the local | ||
32 | machine, saved in the _tep_ handler. The _tep_ argument is the trace event | ||
33 | parser context. This API is a bit faster than _tep_is_bigendian()_, as it | ||
34 | returns cached endianness of the local machine instead of checking it each time. | ||
35 | |||
36 | The _tep_set_local_bigendian()_ function sets the endianness of the local | ||
37 | machine in the _tep_ handler. The _tep_ argument is trace event parser context. | ||
38 | The _endian_ argument is the endianness: | ||
39 | [verse] | ||
40 | -- | ||
41 | _TEP_LITTLE_ENDIAN_ - the machine is little endian, | ||
42 | _TEP_BIG_ENDIAN_ - the machine is big endian. | ||
43 | -- | ||
44 | |||
45 | RETURN VALUE | ||
46 | ------------ | ||
47 | The _tep_is_bigendian()_ function returns non zero if the endianness of the | ||
48 | machine, executing the code, is big endian and zero otherwise. | ||
49 | |||
50 | The _tep_is_local_bigendian()_ function returns true, if the endianness of the | ||
51 | local machine, saved in the _tep_ handler, is big endian, or false otherwise. | ||
52 | |||
53 | EXAMPLE | ||
54 | ------- | ||
55 | [source,c] | ||
56 | -- | ||
57 | #include <event-parse.h> | ||
58 | ... | ||
59 | struct tep_handle *tep = tep_alloc(); | ||
60 | ... | ||
61 | if (tep_is_bigendian()) | ||
62 | tep_set_local_bigendian(tep, TEP_BIG_ENDIAN); | ||
63 | else | ||
64 | tep_set_local_bigendian(tep, TEP_LITTLE_ENDIAN); | ||
65 | ... | ||
66 | if (tep_is_local_bigendian(tep)) | ||
67 | printf("This machine you are running on is bigendian\n"); | ||
68 | else | ||
69 | printf("This machine you are running on is little endian\n"); | ||
70 | |||
71 | -- | ||
72 | |||
73 | FILES | ||
74 | ----- | ||
75 | [verse] | ||
76 | -- | ||
77 | *event-parse.h* | ||
78 | Header file to include in order to have access to the library APIs. | ||
79 | *-ltraceevent* | ||
80 | Linker switch to add when building a program that uses the library. | ||
81 | -- | ||
82 | |||
83 | SEE ALSO | ||
84 | -------- | ||
85 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
86 | |||
87 | AUTHOR | ||
88 | ------ | ||
89 | [verse] | ||
90 | -- | ||
91 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
92 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
93 | -- | ||
94 | REPORTING BUGS | ||
95 | -------------- | ||
96 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
97 | |||
98 | LICENSE | ||
99 | ------- | ||
100 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
101 | |||
102 | RESOURCES | ||
103 | --------- | ||
104 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-long_size.txt b/tools/lib/traceevent/Documentation/libtraceevent-long_size.txt new file mode 100644 index 000000000000..01d78ea2519a --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-long_size.txt | |||
@@ -0,0 +1,78 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_get_long_size, tep_set_long_size - Get / set the size of a long integer on | ||
7 | the machine, where the trace is generated, in bytes | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | int *tep_get_long_size*(strucqt tep_handle pass:[*]_tep_); | ||
16 | void *tep_set_long_size*(struct tep_handle pass:[*]_tep_, int _long_size_); | ||
17 | -- | ||
18 | |||
19 | DESCRIPTION | ||
20 | ----------- | ||
21 | The _tep_get_long_size()_ function returns the size of a long integer on the machine, | ||
22 | where the trace is generated. The _tep_ argument is trace event parser context. | ||
23 | |||
24 | The _tep_set_long_size()_ function sets the size of a long integer on the machine, | ||
25 | where the trace is generated. The _tep_ argument is trace event parser context. | ||
26 | The _long_size_ is the size of a long integer, in bytes. | ||
27 | |||
28 | RETURN VALUE | ||
29 | ------------ | ||
30 | The _tep_get_long_size()_ function returns the size of a long integer on the machine, | ||
31 | where the trace is generated, in bytes. | ||
32 | |||
33 | EXAMPLE | ||
34 | ------- | ||
35 | [source,c] | ||
36 | -- | ||
37 | #include <event-parse.h> | ||
38 | ... | ||
39 | struct tep_handle *tep = tep_alloc(); | ||
40 | ... | ||
41 | tep_set_long_size(tep, 4); | ||
42 | ... | ||
43 | int long_size = tep_get_long_size(tep); | ||
44 | ... | ||
45 | -- | ||
46 | |||
47 | FILES | ||
48 | ----- | ||
49 | [verse] | ||
50 | -- | ||
51 | *event-parse.h* | ||
52 | Header file to include in order to have access to the library APIs. | ||
53 | *-ltraceevent* | ||
54 | Linker switch to add when building a program that uses the library. | ||
55 | -- | ||
56 | |||
57 | SEE ALSO | ||
58 | -------- | ||
59 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
60 | |||
61 | AUTHOR | ||
62 | ------ | ||
63 | [verse] | ||
64 | -- | ||
65 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
66 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
67 | -- | ||
68 | REPORTING BUGS | ||
69 | -------------- | ||
70 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
71 | |||
72 | LICENSE | ||
73 | ------- | ||
74 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
75 | |||
76 | RESOURCES | ||
77 | --------- | ||
78 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-page_size.txt b/tools/lib/traceevent/Documentation/libtraceevent-page_size.txt new file mode 100644 index 000000000000..452c0cfa1822 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-page_size.txt | |||
@@ -0,0 +1,82 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_get_page_size, tep_set_page_size - Get / set the size of a memory page on | ||
7 | the machine, where the trace is generated | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | int *tep_get_page_size*(struct tep_handle pass:[*]_tep_); | ||
16 | void *tep_set_page_size*(struct tep_handle pass:[*]_tep_, int _page_size_); | ||
17 | -- | ||
18 | |||
19 | DESCRIPTION | ||
20 | ----------- | ||
21 | The _tep_get_page_size()_ function returns the size of a memory page on | ||
22 | the machine, where the trace is generated. The _tep_ argument is trace | ||
23 | event parser context. | ||
24 | |||
25 | The _tep_set_page_size()_ function stores in the _tep_ context the size of a | ||
26 | memory page on the machine, where the trace is generated. | ||
27 | The _tep_ argument is trace event parser context. | ||
28 | The _page_size_ argument is the size of a memory page, in bytes. | ||
29 | |||
30 | RETURN VALUE | ||
31 | ------------ | ||
32 | The _tep_get_page_size()_ function returns size of the memory page, in bytes. | ||
33 | |||
34 | EXAMPLE | ||
35 | ------- | ||
36 | [source,c] | ||
37 | -- | ||
38 | #include <unistd.h> | ||
39 | #include <event-parse.h> | ||
40 | ... | ||
41 | struct tep_handle *tep = tep_alloc(); | ||
42 | ... | ||
43 | int page_size = getpagesize(); | ||
44 | |||
45 | tep_set_page_size(tep, page_size); | ||
46 | |||
47 | printf("The page size for this machine is %d\n", tep_get_page_size(tep)); | ||
48 | |||
49 | -- | ||
50 | |||
51 | FILES | ||
52 | ----- | ||
53 | [verse] | ||
54 | -- | ||
55 | *event-parse.h* | ||
56 | Header file to include in order to have access to the library APIs. | ||
57 | *-ltraceevent* | ||
58 | Linker switch to add when building a program that uses the library. | ||
59 | -- | ||
60 | |||
61 | SEE ALSO | ||
62 | -------- | ||
63 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
64 | |||
65 | AUTHOR | ||
66 | ------ | ||
67 | [verse] | ||
68 | -- | ||
69 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
70 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
71 | -- | ||
72 | REPORTING BUGS | ||
73 | -------------- | ||
74 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
75 | |||
76 | LICENSE | ||
77 | ------- | ||
78 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
79 | |||
80 | RESOURCES | ||
81 | --------- | ||
82 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-parse_event.txt b/tools/lib/traceevent/Documentation/libtraceevent-parse_event.txt new file mode 100644 index 000000000000..f248114ca1ff --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-parse_event.txt | |||
@@ -0,0 +1,90 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_parse_event, tep_parse_format - Parse the event format information | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | -- | ||
12 | *#include <event-parse.h>* | ||
13 | |||
14 | enum tep_errno *tep_parse_event*(struct tep_handle pass:[*]_tep_, const char pass:[*]_buf_, unsigned long _size_, const char pass:[*]_sys_); | ||
15 | enum tep_errno *tep_parse_format*(struct tep_handle pass:[*]_tep_, struct tep_event pass:[*]pass:[*]_eventp_, const char pass:[*]_buf_, unsigned long _size_, const char pass:[*]_sys_); | ||
16 | -- | ||
17 | |||
18 | DESCRIPTION | ||
19 | ----------- | ||
20 | The _tep_parse_event()_ function parses the event format and creates an event | ||
21 | structure to quickly parse raw data for a given event. The _tep_ argument is | ||
22 | the trace event parser context. The created event structure is stored in the | ||
23 | _tep_ context. The _buf_ argument is a buffer with _size_, where the event | ||
24 | format data is. The event format data can be taken from | ||
25 | tracefs/events/.../.../format files. The _sys_ argument is the system of | ||
26 | the event. | ||
27 | |||
28 | The _tep_parse_format()_ function does the same as _tep_parse_event()_. The only | ||
29 | difference is in the extra _eventp_ argument, where the newly created event | ||
30 | structure is returned. | ||
31 | |||
32 | RETURN VALUE | ||
33 | ------------ | ||
34 | Both _tep_parse_event()_ and _tep_parse_format()_ functions return 0 on success, | ||
35 | or TEP_ERRNO__... in case of an error. | ||
36 | |||
37 | EXAMPLE | ||
38 | ------- | ||
39 | [source,c] | ||
40 | -- | ||
41 | #include <event-parse.h> | ||
42 | ... | ||
43 | struct tep_handle *tep = tep_alloc(); | ||
44 | ... | ||
45 | char *buf; | ||
46 | int size; | ||
47 | struct tep_event *event = NULL; | ||
48 | buf = read_file("/sys/kernel/tracing/events/ftrace/print/format", &size); | ||
49 | if (tep_parse_event(tep, buf, size, "ftrace") != 0) { | ||
50 | /* Failed to parse the ftrace print format */ | ||
51 | } | ||
52 | |||
53 | if (tep_parse_format(tep, &event, buf, size, "ftrace") != 0) { | ||
54 | /* Failed to parse the ftrace print format */ | ||
55 | } | ||
56 | ... | ||
57 | -- | ||
58 | |||
59 | FILES | ||
60 | ----- | ||
61 | [verse] | ||
62 | -- | ||
63 | *event-parse.h* | ||
64 | Header file to include in order to have access to the library APIs. | ||
65 | *-ltraceevent* | ||
66 | Linker switch to add when building a program that uses the library. | ||
67 | -- | ||
68 | |||
69 | SEE ALSO | ||
70 | -------- | ||
71 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
72 | |||
73 | AUTHOR | ||
74 | ------ | ||
75 | [verse] | ||
76 | -- | ||
77 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
78 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
79 | -- | ||
80 | REPORTING BUGS | ||
81 | -------------- | ||
82 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
83 | |||
84 | LICENSE | ||
85 | ------- | ||
86 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
87 | |||
88 | RESOURCES | ||
89 | --------- | ||
90 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-parse_head.txt b/tools/lib/traceevent/Documentation/libtraceevent-parse_head.txt new file mode 100644 index 000000000000..c90f16c7d8e6 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-parse_head.txt | |||
@@ -0,0 +1,82 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_parse_header_page - Parses the data stored in the header page. | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | -- | ||
12 | *#include <event-parse.h>* | ||
13 | |||
14 | int *tep_parse_header_page*(struct tep_handle pass:[*]_tep_, char pass:[*]_buf_, unsigned long _size_, int _long_size_); | ||
15 | -- | ||
16 | |||
17 | DESCRIPTION | ||
18 | ----------- | ||
19 | The _tep_parse_header_page()_ function parses the header page data from _buf_, | ||
20 | and initializes the _tep_, trace event parser context, with it. The buffer | ||
21 | _buf_ is with _size_, and is supposed to be copied from | ||
22 | tracefs/events/header_page. | ||
23 | |||
24 | Some old kernels do not have header page info, in this case the | ||
25 | _tep_parse_header_page()_ function can be called with _size_ equal to 0. The | ||
26 | _tep_ context is initialized with default values. The _long_size_ can be used in | ||
27 | this use case, to set the size of a long integer to be used. | ||
28 | |||
29 | RETURN VALUE | ||
30 | ------------ | ||
31 | The _tep_parse_header_page()_ function returns 0 in case of success, or -1 | ||
32 | in case of an error. | ||
33 | |||
34 | EXAMPLE | ||
35 | ------- | ||
36 | [source,c] | ||
37 | -- | ||
38 | #include <event-parse.h> | ||
39 | ... | ||
40 | struct tep_handle *tep = tep_alloc(); | ||
41 | ... | ||
42 | char *buf; | ||
43 | int size; | ||
44 | buf = read_file("/sys/kernel/tracing/events/header_page", &size); | ||
45 | if (tep_parse_header_page(tep, buf, size, sizeof(unsigned long)) != 0) { | ||
46 | /* Failed to parse the header page */ | ||
47 | } | ||
48 | ... | ||
49 | -- | ||
50 | |||
51 | FILES | ||
52 | ----- | ||
53 | [verse] | ||
54 | -- | ||
55 | *event-parse.h* | ||
56 | Header file to include in order to have access to the library APIs. | ||
57 | *-ltraceevent* | ||
58 | Linker switch to add when building a program that uses the library. | ||
59 | -- | ||
60 | |||
61 | SEE ALSO | ||
62 | -------- | ||
63 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
64 | |||
65 | AUTHOR | ||
66 | ------ | ||
67 | [verse] | ||
68 | -- | ||
69 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
70 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
71 | -- | ||
72 | REPORTING BUGS | ||
73 | -------------- | ||
74 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
75 | |||
76 | LICENSE | ||
77 | ------- | ||
78 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
79 | |||
80 | RESOURCES | ||
81 | --------- | ||
82 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-record_parse.txt b/tools/lib/traceevent/Documentation/libtraceevent-record_parse.txt new file mode 100644 index 000000000000..e9a69116c78b --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-record_parse.txt | |||
@@ -0,0 +1,137 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_data_type, tep_data_pid,tep_data_preempt_count, tep_data_flags - | ||
7 | Extract common fields from a record. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | enum *trace_flag_type* { | ||
16 | _TRACE_FLAG_IRQS_OFF_, | ||
17 | _TRACE_FLAG_IRQS_NOSUPPORT_, | ||
18 | _TRACE_FLAG_NEED_RESCHED_, | ||
19 | _TRACE_FLAG_HARDIRQ_, | ||
20 | _TRACE_FLAG_SOFTIRQ_, | ||
21 | }; | ||
22 | |||
23 | int *tep_data_type*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); | ||
24 | int *tep_data_pid*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); | ||
25 | int *tep_data_preempt_count*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); | ||
26 | int *tep_data_flags*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); | ||
27 | -- | ||
28 | |||
29 | DESCRIPTION | ||
30 | ----------- | ||
31 | This set of functions can be used to extract common fields from a record. | ||
32 | |||
33 | The _tep_data_type()_ function gets the event id from the record _rec_. | ||
34 | It reads the "common_type" field. The _tep_ argument is the trace event parser | ||
35 | context. | ||
36 | |||
37 | The _tep_data_pid()_ function gets the process id from the record _rec_. | ||
38 | It reads the "common_pid" field. The _tep_ argument is the trace event parser | ||
39 | context. | ||
40 | |||
41 | The _tep_data_preempt_count()_ function gets the preemption count from the | ||
42 | record _rec_. It reads the "common_preempt_count" field. The _tep_ argument is | ||
43 | the trace event parser context. | ||
44 | |||
45 | The _tep_data_flags()_ function gets the latency flags from the record _rec_. | ||
46 | It reads the "common_flags" field. The _tep_ argument is the trace event parser | ||
47 | context. Supported latency flags are: | ||
48 | [verse] | ||
49 | -- | ||
50 | _TRACE_FLAG_IRQS_OFF_, Interrupts are disabled. | ||
51 | _TRACE_FLAG_IRQS_NOSUPPORT_, Reading IRQ flag is not supported by the architecture. | ||
52 | _TRACE_FLAG_NEED_RESCHED_, Task needs rescheduling. | ||
53 | _TRACE_FLAG_HARDIRQ_, Hard IRQ is running. | ||
54 | _TRACE_FLAG_SOFTIRQ_, Soft IRQ is running. | ||
55 | -- | ||
56 | |||
57 | RETURN VALUE | ||
58 | ------------ | ||
59 | The _tep_data_type()_ function returns an integer, representing the event id. | ||
60 | |||
61 | The _tep_data_pid()_ function returns an integer, representing the process id | ||
62 | |||
63 | The _tep_data_preempt_count()_ function returns an integer, representing the | ||
64 | preemption count. | ||
65 | |||
66 | The _tep_data_flags()_ function returns an integer, representing the latency | ||
67 | flags. Look at the _trace_flag_type_ enum for supported flags. | ||
68 | |||
69 | All these functions in case of an error return a negative integer. | ||
70 | |||
71 | EXAMPLE | ||
72 | ------- | ||
73 | [source,c] | ||
74 | -- | ||
75 | #include <event-parse.h> | ||
76 | ... | ||
77 | struct tep_handle *tep = tep_alloc(); | ||
78 | ... | ||
79 | void process_record(struct tep_record *record) | ||
80 | { | ||
81 | int data; | ||
82 | |||
83 | data = tep_data_type(tep, record); | ||
84 | if (data >= 0) { | ||
85 | /* Got the ID of the event */ | ||
86 | } | ||
87 | |||
88 | data = tep_data_pid(tep, record); | ||
89 | if (data >= 0) { | ||
90 | /* Got the process ID */ | ||
91 | } | ||
92 | |||
93 | data = tep_data_preempt_count(tep, record); | ||
94 | if (data >= 0) { | ||
95 | /* Got the preemption count */ | ||
96 | } | ||
97 | |||
98 | data = tep_data_flags(tep, record); | ||
99 | if (data >= 0) { | ||
100 | /* Got the latency flags */ | ||
101 | } | ||
102 | } | ||
103 | ... | ||
104 | -- | ||
105 | |||
106 | FILES | ||
107 | ----- | ||
108 | [verse] | ||
109 | -- | ||
110 | *event-parse.h* | ||
111 | Header file to include in order to have access to the library APIs. | ||
112 | *-ltraceevent* | ||
113 | Linker switch to add when building a program that uses the library. | ||
114 | -- | ||
115 | |||
116 | SEE ALSO | ||
117 | -------- | ||
118 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
119 | |||
120 | AUTHOR | ||
121 | ------ | ||
122 | [verse] | ||
123 | -- | ||
124 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
125 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
126 | -- | ||
127 | REPORTING BUGS | ||
128 | -------------- | ||
129 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
130 | |||
131 | LICENSE | ||
132 | ------- | ||
133 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
134 | |||
135 | RESOURCES | ||
136 | --------- | ||
137 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-reg_event_handler.txt b/tools/lib/traceevent/Documentation/libtraceevent-reg_event_handler.txt new file mode 100644 index 000000000000..53d37d72a1c1 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-reg_event_handler.txt | |||
@@ -0,0 +1,156 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_register_event_handler, tep_unregister_event_handler - Register / | ||
7 | unregisters a callback function to parse an event information. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | enum *tep_reg_handler* { | ||
16 | _TEP_REGISTER_SUCCESS_, | ||
17 | _TEP_REGISTER_SUCCESS_OVERWRITE_, | ||
18 | }; | ||
19 | |||
20 | int *tep_register_event_handler*(struct tep_handle pass:[*]_tep_, int _id_, const char pass:[*]_sys_name_, const char pass:[*]_event_name_, tep_event_handler_func _func_, void pass:[*]_context_); | ||
21 | int *tep_unregister_event_handler*(struct tep_handle pass:[*]tep, int id, const char pass:[*]sys_name, const char pass:[*]event_name, tep_event_handler_func func, void pass:[*]_context_); | ||
22 | |||
23 | typedef int (*pass:[*]tep_event_handler_func*)(struct trace_seq pass:[*]s, struct tep_record pass:[*]record, struct tep_event pass:[*]event, void pass:[*]context); | ||
24 | -- | ||
25 | |||
26 | DESCRIPTION | ||
27 | ----------- | ||
28 | The _tep_register_event_handler()_ function registers a handler function, | ||
29 | which is going to be called to parse the information for a given event. | ||
30 | The _tep_ argument is the trace event parser context. The _id_ argument is | ||
31 | the id of the event. The _sys_name_ argument is the name of the system, | ||
32 | the event belongs to. The _event_name_ argument is the name of the event. | ||
33 | If _id_ is >= 0, it is used to find the event, otherwise _sys_name_ and | ||
34 | _event_name_ are used. The _func_ is a pointer to the function, which is going | ||
35 | to be called to parse the event information. The _context_ argument is a pointer | ||
36 | to the context data, which will be passed to the _func_. If a handler function | ||
37 | for the same event is already registered, it will be overridden with the new | ||
38 | one. This mechanism allows a developer to override the parsing of a given event. | ||
39 | If for some reason the default print format is not sufficient, the developer | ||
40 | can register a function for an event to be used to parse the data instead. | ||
41 | |||
42 | The _tep_unregister_event_handler()_ function unregisters the handler function, | ||
43 | previously registered with _tep_register_event_handler()_. The _tep_ argument | ||
44 | is the trace event parser context. The _id_, _sys_name_, _event_name_, _func_, | ||
45 | and _context_ are the same arguments, as when the callback function _func_ was | ||
46 | registered. | ||
47 | |||
48 | The _tep_event_handler_func_ is the type of the custom event handler | ||
49 | function. The _s_ argument is the trace sequence, it can be used to create a | ||
50 | custom string, describing the event. A _record_ to get the event from is passed | ||
51 | as input parameter and also the _event_ - the handle to the record's event. The | ||
52 | _context_ is custom context, set when the custom event handler is registered. | ||
53 | |||
54 | RETURN VALUE | ||
55 | ------------ | ||
56 | The _tep_register_event_handler()_ function returns _TEP_REGISTER_SUCCESS_ | ||
57 | if the new handler is registered successfully or | ||
58 | _TEP_REGISTER_SUCCESS_OVERWRITE_ if an existing handler is overwritten. | ||
59 | If there is not enough memory to complete the registration, | ||
60 | TEP_ERRNO__MEM_ALLOC_FAILED is returned. | ||
61 | |||
62 | The _tep_unregister_event_handler()_ function returns 0 if _func_ was removed | ||
63 | successful or, -1 if the event was not found. | ||
64 | |||
65 | The _tep_event_handler_func_ should return -1 in case of an error, | ||
66 | or 0 otherwise. | ||
67 | |||
68 | EXAMPLE | ||
69 | ------- | ||
70 | [source,c] | ||
71 | -- | ||
72 | #include <event-parse.h> | ||
73 | #include <trace-seq.h> | ||
74 | ... | ||
75 | struct tep_handle *tep = tep_alloc(); | ||
76 | ... | ||
77 | int timer_expire_handler(struct trace_seq *s, struct tep_record *record, | ||
78 | struct tep_event *event, void *context) | ||
79 | { | ||
80 | trace_seq_printf(s, "hrtimer="); | ||
81 | |||
82 | if (tep_print_num_field(s, "0x%llx", event, "timer", record, 0) == -1) | ||
83 | tep_print_num_field(s, "0x%llx", event, "hrtimer", record, 1); | ||
84 | |||
85 | trace_seq_printf(s, " now="); | ||
86 | |||
87 | tep_print_num_field(s, "%llu", event, "now", record, 1); | ||
88 | |||
89 | tep_print_func_field(s, " function=%s", event, "function", record, 0); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | ... | ||
94 | int ret; | ||
95 | |||
96 | ret = tep_register_event_handler(tep, -1, "timer", "hrtimer_expire_entry", | ||
97 | timer_expire_handler, NULL); | ||
98 | if (ret < 0) { | ||
99 | char buf[32]; | ||
100 | |||
101 | tep_strerror(tep, ret, buf, 32) | ||
102 | printf("Failed to register handler for hrtimer_expire_entry: %s\n", buf); | ||
103 | } else { | ||
104 | switch (ret) { | ||
105 | case TEP_REGISTER_SUCCESS: | ||
106 | printf ("Registered handler for hrtimer_expire_entry\n"); | ||
107 | break; | ||
108 | case TEP_REGISTER_SUCCESS_OVERWRITE: | ||
109 | printf ("Overwrote handler for hrtimer_expire_entry\n"); | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | ... | ||
114 | ret = tep_unregister_event_handler(tep, -1, "timer", "hrtimer_expire_entry", | ||
115 | timer_expire_handler, NULL); | ||
116 | if ( ret ) | ||
117 | printf ("Failed to unregister handler for hrtimer_expire_entry\n"); | ||
118 | |||
119 | -- | ||
120 | |||
121 | FILES | ||
122 | ----- | ||
123 | [verse] | ||
124 | -- | ||
125 | *event-parse.h* | ||
126 | Header file to include in order to have access to the library APIs. | ||
127 | *trace-seq.h* | ||
128 | Header file to include in order to have access to trace sequences | ||
129 | related APIs. Trace sequences are used to allow a function to call | ||
130 | several other functions to create a string of data to use. | ||
131 | *-ltraceevent* | ||
132 | Linker switch to add when building a program that uses the library. | ||
133 | -- | ||
134 | |||
135 | SEE ALSO | ||
136 | -------- | ||
137 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
138 | |||
139 | AUTHOR | ||
140 | ------ | ||
141 | [verse] | ||
142 | -- | ||
143 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
144 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
145 | -- | ||
146 | REPORTING BUGS | ||
147 | -------------- | ||
148 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
149 | |||
150 | LICENSE | ||
151 | ------- | ||
152 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
153 | |||
154 | RESOURCES | ||
155 | --------- | ||
156 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-reg_print_func.txt b/tools/lib/traceevent/Documentation/libtraceevent-reg_print_func.txt new file mode 100644 index 000000000000..708dce91ebd8 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-reg_print_func.txt | |||
@@ -0,0 +1,155 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_register_print_function,tep_unregister_print_function - | ||
7 | Registers / Unregisters a helper function. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | enum *tep_func_arg_type* { | ||
16 | TEP_FUNC_ARG_VOID, | ||
17 | TEP_FUNC_ARG_INT, | ||
18 | TEP_FUNC_ARG_LONG, | ||
19 | TEP_FUNC_ARG_STRING, | ||
20 | TEP_FUNC_ARG_PTR, | ||
21 | TEP_FUNC_ARG_MAX_TYPES | ||
22 | }; | ||
23 | |||
24 | typedef unsigned long long (*pass:[*]tep_func_handler*)(struct trace_seq pass:[*]s, unsigned long long pass:[*]args); | ||
25 | |||
26 | int *tep_register_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, enum tep_func_arg_type _ret_type_, char pass:[*]_name_, _..._); | ||
27 | int *tep_unregister_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, char pass:[*]_name_); | ||
28 | -- | ||
29 | |||
30 | DESCRIPTION | ||
31 | ----------- | ||
32 | Some events may have helper functions in the print format arguments. | ||
33 | This allows a plugin to dynamically create a way to process one of | ||
34 | these functions. | ||
35 | |||
36 | The _tep_register_print_function()_ registers such helper function. The _tep_ | ||
37 | argument is the trace event parser context. The _func_ argument is a pointer | ||
38 | to the helper function. The _ret_type_ argument is the return type of the | ||
39 | helper function, value from the _tep_func_arg_type_ enum. The _name_ is the name | ||
40 | of the helper function, as seen in the print format arguments. The _..._ is a | ||
41 | variable list of _tep_func_arg_type_ enums, the _func_ function arguments. | ||
42 | This list must end with _TEP_FUNC_ARG_VOID_. See 'EXAMPLE' section. | ||
43 | |||
44 | The _tep_unregister_print_function()_ unregisters a helper function, previously | ||
45 | registered with _tep_register_print_function()_. The _tep_ argument is the | ||
46 | trace event parser context. The _func_ and _name_ arguments are the same, used | ||
47 | when the helper function was registered. | ||
48 | |||
49 | The _tep_func_handler_ is the type of the helper function. The _s_ argument is | ||
50 | the trace sequence, it can be used to create a custom string. | ||
51 | The _args_ is a list of arguments, defined when the helper function was | ||
52 | registered. | ||
53 | |||
54 | RETURN VALUE | ||
55 | ------------ | ||
56 | The _tep_register_print_function()_ function returns 0 in case of success. | ||
57 | In case of an error, TEP_ERRNO_... code is returned. | ||
58 | |||
59 | The _tep_unregister_print_function()_ returns 0 in case of success, or -1 in | ||
60 | case of an error. | ||
61 | |||
62 | EXAMPLE | ||
63 | ------- | ||
64 | Some events have internal functions calls, that appear in the print format | ||
65 | output. For example "tracefs/events/i915/g4x_wm/format" has: | ||
66 | [source,c] | ||
67 | -- | ||
68 | print fmt: "pipe %c, frame=%u, scanline=%u, wm %d/%d/%d, sr %s/%d/%d/%d, hpll %s/%d/%d/%d, fbc %s", | ||
69 | ((REC->pipe) + 'A'), REC->frame, REC->scanline, REC->primary, | ||
70 | REC->sprite, REC->cursor, yesno(REC->cxsr), REC->sr_plane, | ||
71 | REC->sr_cursor, REC->sr_fbc, yesno(REC->hpll), REC->hpll_plane, | ||
72 | REC->hpll_cursor, REC->hpll_fbc, yesno(REC->fbc) | ||
73 | -- | ||
74 | Notice the call to function _yesno()_ in the print arguments. In the kernel | ||
75 | context, this function has the following implementation: | ||
76 | [source,c] | ||
77 | -- | ||
78 | static const char *yesno(int x) | ||
79 | { | ||
80 | static const char *yes = "yes"; | ||
81 | static const char *no = "no"; | ||
82 | |||
83 | return x ? yes : no; | ||
84 | } | ||
85 | -- | ||
86 | The user space event parser has no idea how to handle this _yesno()_ function. | ||
87 | The _tep_register_print_function()_ API can be used to register a user space | ||
88 | helper function, mapped to the kernel's _yesno()_: | ||
89 | [source,c] | ||
90 | -- | ||
91 | #include <event-parse.h> | ||
92 | #include <trace-seq.h> | ||
93 | ... | ||
94 | struct tep_handle *tep = tep_alloc(); | ||
95 | ... | ||
96 | static const char *yes_no_helper(int x) | ||
97 | { | ||
98 | return x ? "yes" : "no"; | ||
99 | } | ||
100 | ... | ||
101 | if ( tep_register_print_function(tep, | ||
102 | yes_no_helper, | ||
103 | TEP_FUNC_ARG_STRING, | ||
104 | "yesno", | ||
105 | TEP_FUNC_ARG_INT, | ||
106 | TEP_FUNC_ARG_VOID) != 0) { | ||
107 | /* Failed to register yes_no_helper function */ | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | Now, when the event parser encounters this yesno() function, it will know | ||
112 | how to handle it. | ||
113 | */ | ||
114 | ... | ||
115 | if (tep_unregister_print_function(tep, yes_no_helper, "yesno") != 0) { | ||
116 | /* Failed to unregister yes_no_helper function */ | ||
117 | } | ||
118 | -- | ||
119 | |||
120 | FILES | ||
121 | ----- | ||
122 | [verse] | ||
123 | -- | ||
124 | *event-parse.h* | ||
125 | Header file to include in order to have access to the library APIs. | ||
126 | *trace-seq.h* | ||
127 | Header file to include in order to have access to trace sequences | ||
128 | related APIs. Trace sequences are used to allow a function to call | ||
129 | several other functions to create a string of data to use. | ||
130 | *-ltraceevent* | ||
131 | Linker switch to add when building a program that uses the library. | ||
132 | -- | ||
133 | |||
134 | SEE ALSO | ||
135 | -------- | ||
136 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
137 | |||
138 | AUTHOR | ||
139 | ------ | ||
140 | [verse] | ||
141 | -- | ||
142 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
143 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
144 | -- | ||
145 | REPORTING BUGS | ||
146 | -------------- | ||
147 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
148 | |||
149 | LICENSE | ||
150 | ------- | ||
151 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
152 | |||
153 | RESOURCES | ||
154 | --------- | ||
155 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-set_flag.txt b/tools/lib/traceevent/Documentation/libtraceevent-set_flag.txt new file mode 100644 index 000000000000..b0599780b9a6 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-set_flag.txt | |||
@@ -0,0 +1,104 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_set_flag, tep_clear_flag, tep_test_flag - | ||
7 | Manage flags of trace event parser context. | ||
8 | |||
9 | SYNOPSIS | ||
10 | -------- | ||
11 | [verse] | ||
12 | -- | ||
13 | *#include <event-parse.h>* | ||
14 | |||
15 | enum *tep_flag* { | ||
16 | _TEP_NSEC_OUTPUT_, | ||
17 | _TEP_DISABLE_SYS_PLUGINS_, | ||
18 | _TEP_DISABLE_PLUGINS_ | ||
19 | }; | ||
20 | void *tep_set_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_); | ||
21 | void *tep_clear_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_); | ||
22 | bool *tep_test_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_); | ||
23 | -- | ||
24 | |||
25 | DESCRIPTION | ||
26 | ----------- | ||
27 | Trace event parser context flags are defined in *enum tep_flag*: | ||
28 | [verse] | ||
29 | -- | ||
30 | _TEP_NSEC_OUTPUT_ - print event's timestamp in nano seconds, instead of micro seconds. | ||
31 | _TEP_DISABLE_SYS_PLUGINS_ - disable plugins, located in system's plugin | ||
32 | directory. This directory is defined at library compile | ||
33 | time, and usually depends on library installation | ||
34 | prefix: (install_preffix)/lib/traceevent/plugins | ||
35 | _TEP_DISABLE_PLUGINS_ - disable all library plugins: | ||
36 | - in system's plugin directory | ||
37 | - in directory, defined by the environment variable _TRACEEVENT_PLUGIN_DIR_ | ||
38 | - in user's home directory, _~/.traceevent/plugins_ | ||
39 | -- | ||
40 | Note: plugin related flags must me set before calling _tep_load_plugins()_ API. | ||
41 | |||
42 | The _tep_set_flag()_ function sets _flag_ to _tep_ context. | ||
43 | |||
44 | The _tep_clear_flag()_ function clears _flag_ from _tep_ context. | ||
45 | |||
46 | The _tep_test_flag()_ function tests if _flag_ is set to _tep_ context. | ||
47 | |||
48 | RETURN VALUE | ||
49 | ------------ | ||
50 | _tep_test_flag()_ function returns true if _flag_ is set, false otherwise. | ||
51 | |||
52 | EXAMPLE | ||
53 | ------- | ||
54 | [source,c] | ||
55 | -- | ||
56 | #include <event-parse.h> | ||
57 | ... | ||
58 | struct tep_handle *tep = tep_alloc(); | ||
59 | ... | ||
60 | /* Print timestamps in nanoseconds */ | ||
61 | tep_set_flag(tep, TEP_NSEC_OUTPUT); | ||
62 | ... | ||
63 | if (tep_test_flag(tep, TEP_NSEC_OUTPUT)) { | ||
64 | /* print timestamps in nanoseconds */ | ||
65 | } else { | ||
66 | /* print timestamps in microseconds */ | ||
67 | } | ||
68 | ... | ||
69 | /* Print timestamps in microseconds */ | ||
70 | tep_clear_flag(tep, TEP_NSEC_OUTPUT); | ||
71 | ... | ||
72 | -- | ||
73 | FILES | ||
74 | ----- | ||
75 | [verse] | ||
76 | -- | ||
77 | *event-parse.h* | ||
78 | Header file to include in order to have access to the library APIs. | ||
79 | *-ltraceevent* | ||
80 | Linker switch to add when building a program that uses the library. | ||
81 | -- | ||
82 | |||
83 | SEE ALSO | ||
84 | -------- | ||
85 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
86 | |||
87 | AUTHOR | ||
88 | ------ | ||
89 | [verse] | ||
90 | -- | ||
91 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
92 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
93 | -- | ||
94 | REPORTING BUGS | ||
95 | -------------- | ||
96 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
97 | |||
98 | LICENSE | ||
99 | ------- | ||
100 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
101 | |||
102 | RESOURCES | ||
103 | --------- | ||
104 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-strerror.txt b/tools/lib/traceevent/Documentation/libtraceevent-strerror.txt new file mode 100644 index 000000000000..ee4062a00c9f --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-strerror.txt | |||
@@ -0,0 +1,85 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | tep_strerror - Returns a string describing regular errno and tep error number. | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | -- | ||
12 | *#include <event-parse.h>* | ||
13 | |||
14 | int *tep_strerror*(struct tep_handle pass:[*]_tep_, enum tep_errno _errnum_, char pass:[*]_buf_, size_t _buflen_); | ||
15 | |||
16 | -- | ||
17 | DESCRIPTION | ||
18 | ----------- | ||
19 | The _tep_strerror()_ function converts tep error number into a human | ||
20 | readable string. | ||
21 | The _tep_ argument is trace event parser context. The _errnum_ is a regular | ||
22 | errno, defined in errno.h, or a tep error number. The string, describing this | ||
23 | error number is copied in the _buf_ argument. The _buflen_ argument is | ||
24 | the size of the _buf_. | ||
25 | |||
26 | It as a thread safe wrapper around strerror_r(). The library function has two | ||
27 | different behaviors - POSIX and GNU specific. The _tep_strerror()_ API always | ||
28 | behaves as the POSIX version - the error string is copied in the user supplied | ||
29 | buffer. | ||
30 | |||
31 | RETURN VALUE | ||
32 | ------------ | ||
33 | The _tep_strerror()_ function returns 0, if a valid _errnum_ is passed and the | ||
34 | string is copied into _buf_. If _errnum_ is not a valid error number, | ||
35 | -1 is returned and _buf_ is not modified. | ||
36 | |||
37 | EXAMPLE | ||
38 | ------- | ||
39 | [source,c] | ||
40 | -- | ||
41 | #include <event-parse.h> | ||
42 | ... | ||
43 | struct tep_handle *tep = tep_alloc(); | ||
44 | ... | ||
45 | char buf[32]; | ||
46 | char *pool = calloc(1, 128); | ||
47 | if (tep == NULL) { | ||
48 | tep_strerror(tep, TEP_ERRNO__MEM_ALLOC_FAILED, buf, 32); | ||
49 | printf ("The pool is not initialized, %s", buf); | ||
50 | } | ||
51 | ... | ||
52 | -- | ||
53 | |||
54 | FILES | ||
55 | ----- | ||
56 | [verse] | ||
57 | -- | ||
58 | *event-parse.h* | ||
59 | Header file to include in order to have access to the library APIs. | ||
60 | *-ltraceevent* | ||
61 | Linker switch to add when building a program that uses the library. | ||
62 | -- | ||
63 | |||
64 | SEE ALSO | ||
65 | -------- | ||
66 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
67 | |||
68 | AUTHOR | ||
69 | ------ | ||
70 | [verse] | ||
71 | -- | ||
72 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
73 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
74 | -- | ||
75 | REPORTING BUGS | ||
76 | -------------- | ||
77 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
78 | |||
79 | LICENSE | ||
80 | ------- | ||
81 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
82 | |||
83 | RESOURCES | ||
84 | --------- | ||
85 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent-tseq.txt b/tools/lib/traceevent/Documentation/libtraceevent-tseq.txt new file mode 100644 index 000000000000..8ac6aa174e12 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-tseq.txt | |||
@@ -0,0 +1,158 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | trace_seq_init, trace_seq_destroy, trace_seq_reset, trace_seq_terminate, | ||
7 | trace_seq_putc, trace_seq_puts, trace_seq_printf, trace_seq_vprintf, | ||
8 | trace_seq_do_fprintf, trace_seq_do_printf - | ||
9 | Initialize / destroy a trace sequence. | ||
10 | |||
11 | SYNOPSIS | ||
12 | -------- | ||
13 | [verse] | ||
14 | -- | ||
15 | *#include <event-parse.h>* | ||
16 | *#include <trace-seq.h>* | ||
17 | |||
18 | void *trace_seq_init*(struct trace_seq pass:[*]_s_); | ||
19 | void *trace_seq_destroy*(struct trace_seq pass:[*]_s_); | ||
20 | void *trace_seq_reset*(struct trace_seq pass:[*]_s_); | ||
21 | void *trace_seq_terminate*(struct trace_seq pass:[*]_s_); | ||
22 | int *trace_seq_putc*(struct trace_seq pass:[*]_s_, unsigned char _c_); | ||
23 | int *trace_seq_puts*(struct trace_seq pass:[*]_s_, const char pass:[*]_str_); | ||
24 | int *trace_seq_printf*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, _..._); | ||
25 | int *trace_seq_vprintf*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, va_list _args_); | ||
26 | int *trace_seq_do_printf*(struct trace_seq pass:[*]_s_); | ||
27 | int *trace_seq_do_fprintf*(struct trace_seq pass:[*]_s_, FILE pass:[*]_fp_); | ||
28 | -- | ||
29 | |||
30 | DESCRIPTION | ||
31 | ----------- | ||
32 | Trace sequences are used to allow a function to call several other functions | ||
33 | to create a string of data to use. | ||
34 | |||
35 | The _trace_seq_init()_ function initializes the trace sequence _s_. | ||
36 | |||
37 | The _trace_seq_destroy()_ function destroys the trace sequence _s_ and frees | ||
38 | all its resources that it had used. | ||
39 | |||
40 | The _trace_seq_reset()_ function re-initializes the trace sequence _s_. All | ||
41 | characters already written in _s_ will be deleted. | ||
42 | |||
43 | The _trace_seq_terminate()_ function terminates the trace sequence _s_. It puts | ||
44 | the null character pass:['\0'] at the end of the buffer. | ||
45 | |||
46 | The _trace_seq_putc()_ function puts a single character _c_ in the trace | ||
47 | sequence _s_. | ||
48 | |||
49 | The _trace_seq_puts()_ function puts a NULL terminated string _str_ in the | ||
50 | trace sequence _s_. | ||
51 | |||
52 | The _trace_seq_printf()_ function puts a formated string _fmt _with | ||
53 | variable arguments _..._ in the trace sequence _s_. | ||
54 | |||
55 | The _trace_seq_vprintf()_ function puts a formated string _fmt _with | ||
56 | list of arguments _args_ in the trace sequence _s_. | ||
57 | |||
58 | The _trace_seq_do_printf()_ function prints the buffer of trace sequence _s_ to | ||
59 | the standard output stdout. | ||
60 | |||
61 | The _trace_seq_do_fprintf()_ function prints the buffer of trace sequence _s_ | ||
62 | to the given file _fp_. | ||
63 | |||
64 | RETURN VALUE | ||
65 | ------------ | ||
66 | Both _trace_seq_putc()_ and _trace_seq_puts()_ functions return the number of | ||
67 | characters put in the trace sequence, or 0 in case of an error | ||
68 | |||
69 | Both _trace_seq_printf()_ and _trace_seq_vprintf()_ functions return 0 if the | ||
70 | trace oversizes the buffer's free space, the number of characters printed, or | ||
71 | a negative value in case of an error. | ||
72 | |||
73 | Both _trace_seq_do_printf()_ and _trace_seq_do_fprintf()_ functions return the | ||
74 | number of printed characters, or -1 in case of an error. | ||
75 | |||
76 | EXAMPLE | ||
77 | ------- | ||
78 | [source,c] | ||
79 | -- | ||
80 | #include <event-parse.h> | ||
81 | #include <trace-seq.h> | ||
82 | ... | ||
83 | struct trace_seq seq; | ||
84 | trace_seq_init(&seq); | ||
85 | ... | ||
86 | void foo_seq_print(struct trace_seq *tseq, char *format, ...) | ||
87 | { | ||
88 | va_list ap; | ||
89 | va_start(ap, format); | ||
90 | if (trace_seq_vprintf(tseq, format, ap) <= 0) { | ||
91 | /* Failed to print in the trace sequence */ | ||
92 | } | ||
93 | va_end(ap); | ||
94 | } | ||
95 | |||
96 | trace_seq_reset(&seq); | ||
97 | |||
98 | char *str = " MAN page example"; | ||
99 | if (trace_seq_puts(&seq, str) != strlen(str)) { | ||
100 | /* Failed to put str in the trace sequence */ | ||
101 | } | ||
102 | if (trace_seq_putc(&seq, ':') != 1) { | ||
103 | /* Failed to put ':' in the trace sequence */ | ||
104 | } | ||
105 | if (trace_seq_printf(&seq, " trace sequence: %d", 1) <= 0) { | ||
106 | /* Failed to print in the trace sequence */ | ||
107 | } | ||
108 | foo_seq_print( &seq, " %d\n", 2); | ||
109 | |||
110 | trace_seq_terminate(&seq); | ||
111 | ... | ||
112 | |||
113 | if (trace_seq_do_printf(&seq) < 0 ) { | ||
114 | /* Failed to print the sequence buffer to the standard output */ | ||
115 | } | ||
116 | FILE *fp = fopen("trace.txt", "w"); | ||
117 | if (trace_seq_do_fprintf(&seq, fp) < 0 ) [ | ||
118 | /* Failed to print the sequence buffer to the trace.txt file */ | ||
119 | } | ||
120 | |||
121 | trace_seq_destroy(&seq); | ||
122 | ... | ||
123 | -- | ||
124 | |||
125 | FILES | ||
126 | ----- | ||
127 | [verse] | ||
128 | -- | ||
129 | *event-parse.h* | ||
130 | Header file to include in order to have access to the library APIs. | ||
131 | *trace-seq.h* | ||
132 | Header file to include in order to have access to trace sequences related APIs. | ||
133 | *-ltraceevent* | ||
134 | Linker switch to add when building a program that uses the library. | ||
135 | -- | ||
136 | |||
137 | SEE ALSO | ||
138 | -------- | ||
139 | _libtraceevent(3)_, _trace-cmd(1)_ | ||
140 | |||
141 | AUTHOR | ||
142 | ------ | ||
143 | [verse] | ||
144 | -- | ||
145 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
146 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
147 | -- | ||
148 | REPORTING BUGS | ||
149 | -------------- | ||
150 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
151 | |||
152 | LICENSE | ||
153 | ------- | ||
154 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
155 | |||
156 | RESOURCES | ||
157 | --------- | ||
158 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/libtraceevent.txt b/tools/lib/traceevent/Documentation/libtraceevent.txt new file mode 100644 index 000000000000..fbd977b47de1 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent.txt | |||
@@ -0,0 +1,203 @@ | |||
1 | libtraceevent(3) | ||
2 | ================ | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | libtraceevent - Linux kernel trace event library | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | -- | ||
12 | *#include <event-parse.h>* | ||
13 | |||
14 | Management of tep handler data structure and access of its members: | ||
15 | struct tep_handle pass:[*]*tep_alloc*(void); | ||
16 | void *tep_free*(struct tep_handle pass:[*]_tep_); | ||
17 | void *tep_ref*(struct tep_handle pass:[*]_tep_); | ||
18 | void *tep_unref*(struct tep_handle pass:[*]_tep_); | ||
19 | int *tep_ref_get*(struct tep_handle pass:[*]_tep_); | ||
20 | void *tep_set_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_); | ||
21 | void *tep_clear_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_); | ||
22 | bool *tep_test_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flags_); | ||
23 | int *tep_get_cpus*(struct tep_handle pass:[*]_tep_); | ||
24 | void *tep_set_cpus*(struct tep_handle pass:[*]_tep_, int _cpus_); | ||
25 | int *tep_get_long_size*(strucqt tep_handle pass:[*]_tep_); | ||
26 | void *tep_set_long_size*(struct tep_handle pass:[*]_tep_, int _long_size_); | ||
27 | int *tep_get_page_size*(struct tep_handle pass:[*]_tep_); | ||
28 | void *tep_set_page_size*(struct tep_handle pass:[*]_tep_, int _page_size_); | ||
29 | bool *tep_is_latency_format*(struct tep_handle pass:[*]_tep_); | ||
30 | void *tep_set_latency_format*(struct tep_handle pass:[*]_tep_, int _lat_); | ||
31 | int *tep_get_header_page_size*(struct tep_handle pass:[*]_tep_); | ||
32 | int *tep_get_header_timestamp_size*(struct tep_handle pass:[*]_tep_); | ||
33 | bool *tep_is_old_format*(struct tep_handle pass:[*]_tep_); | ||
34 | int *tep_strerror*(struct tep_handle pass:[*]_tep_, enum tep_errno _errnum_, char pass:[*]_buf_, size_t _buflen_); | ||
35 | |||
36 | Register / unregister APIs: | ||
37 | int *tep_register_trace_clock*(struct tep_handle pass:[*]_tep_, const char pass:[*]_trace_clock_); | ||
38 | int *tep_register_function*(struct tep_handle pass:[*]_tep_, char pass:[*]_name_, unsigned long long _addr_, char pass:[*]_mod_); | ||
39 | int *tep_register_event_handler*(struct tep_handle pass:[*]_tep_, int _id_, const char pass:[*]_sys_name_, const char pass:[*]_event_name_, tep_event_handler_func _func_, void pass:[*]_context_); | ||
40 | int *tep_unregister_event_handler*(struct tep_handle pass:[*]tep, int id, const char pass:[*]sys_name, const char pass:[*]event_name, tep_event_handler_func func, void pass:[*]_context_); | ||
41 | int *tep_register_print_string*(struct tep_handle pass:[*]_tep_, const char pass:[*]_fmt_, unsigned long long _addr_); | ||
42 | int *tep_register_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, enum tep_func_arg_type _ret_type_, char pass:[*]_name_, _..._); | ||
43 | int *tep_unregister_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, char pass:[*]_name_); | ||
44 | |||
45 | Plugins management: | ||
46 | struct tep_plugin_list pass:[*]*tep_load_plugins*(struct tep_handle pass:[*]_tep_); | ||
47 | void *tep_unload_plugins*(struct tep_plugin_list pass:[*]_plugin_list_, struct tep_handle pass:[*]_tep_); | ||
48 | char pass:[*]pass:[*]*tep_plugin_list_options*(void); | ||
49 | void *tep_plugin_free_options_list*(char pass:[*]pass:[*]_list_); | ||
50 | int *tep_plugin_add_options*(const char pass:[*]_name_, struct tep_plugin_option pass:[*]_options_); | ||
51 | void *tep_plugin_remove_options*(struct tep_plugin_option pass:[*]_options_); | ||
52 | void *tep_print_plugins*(struct trace_seq pass:[*]_s_, const char pass:[*]_prefix_, const char pass:[*]_suffix_, const struct tep_plugin_list pass:[*]_list_); | ||
53 | |||
54 | Event related APIs: | ||
55 | struct tep_event pass:[*]*tep_get_event*(struct tep_handle pass:[*]_tep_, int _index_); | ||
56 | struct tep_event pass:[*]*tep_get_first_event*(struct tep_handle pass:[*]_tep_); | ||
57 | int *tep_get_events_count*(struct tep_handle pass:[*]_tep_); | ||
58 | struct tep_event pass:[*]pass:[*]*tep_list_events*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_); | ||
59 | struct tep_event pass:[*]pass:[*]*tep_list_events_copy*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_); | ||
60 | |||
61 | Event printing: | ||
62 | void *tep_print_event*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_record pass:[*]_record_, bool _use_trace_clock_); | ||
63 | void *tep_print_event_data*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]_record_); | ||
64 | void *tep_event_info*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]_record_); | ||
65 | void *tep_print_event_task*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]_record_); | ||
66 | void *tep_print_event_time*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]record, bool _use_trace_clock_); | ||
67 | void *tep_set_print_raw*(struct tep_handle pass:[*]_tep_, int _print_raw_); | ||
68 | |||
69 | Event finding: | ||
70 | struct tep_event pass:[*]*tep_find_event*(struct tep_handle pass:[*]_tep_, int _id_); | ||
71 | struct tep_event pass:[*]*tep_find_event_by_name*(struct tep_handle pass:[*]_tep_, const char pass:[*]_sys_, const char pass:[*]_name_); | ||
72 | struct tep_event pass:[*]*tep_find_event_by_record*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_record_); | ||
73 | |||
74 | Parsing of event files: | ||
75 | int *tep_parse_header_page*(struct tep_handle pass:[*]_tep_, char pass:[*]_buf_, unsigned long _size_, int _long_size_); | ||
76 | enum tep_errno *tep_parse_event*(struct tep_handle pass:[*]_tep_, const char pass:[*]_buf_, unsigned long _size_, const char pass:[*]_sys_); | ||
77 | enum tep_errno *tep_parse_format*(struct tep_handle pass:[*]_tep_, struct tep_event pass:[*]pass:[*]_eventp_, const char pass:[*]_buf_, unsigned long _size_, const char pass:[*]_sys_); | ||
78 | |||
79 | APIs related to fields from event's format files: | ||
80 | struct tep_format_field pass:[*]pass:[*]*tep_event_common_fields*(struct tep_event pass:[*]_event_); | ||
81 | struct tep_format_field pass:[*]pass:[*]*tep_event_fields*(struct tep_event pass:[*]_event_); | ||
82 | void pass:[*]*tep_get_field_raw*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int pass:[*]_len_, int _err_); | ||
83 | int *tep_get_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_); | ||
84 | int *tep_get_common_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_); | ||
85 | int *tep_get_any_field_val*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, unsigned long long pass:[*]_val_, int _err_); | ||
86 | int *tep_read_number_field*(struct tep_format_field pass:[*]_field_, const void pass:[*]_data_, unsigned long long pass:[*]_value_); | ||
87 | |||
88 | Event fields printing: | ||
89 | void *tep_print_field*(struct trace_seq pass:[*]_s_, void pass:[*]_data_, struct tep_format_field pass:[*]_field_); | ||
90 | void *tep_print_fields*(struct trace_seq pass:[*]_s_, void pass:[*]_data_, int _size_, struct tep_event pass:[*]_event_); | ||
91 | int *tep_print_num_field*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int _err_); | ||
92 | int *tep_print_func_field*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, struct tep_event pass:[*]_event_, const char pass:[*]_name_, struct tep_record pass:[*]_record_, int _err_); | ||
93 | |||
94 | Event fields finding: | ||
95 | struct tep_format_field pass:[*]*tep_find_common_field*(struct tep_event pass:[*]_event_, const char pass:[*]_name_); | ||
96 | struct tep_format_field pass:[*]*tep_find_field*(struct tep_event_ormat pass:[*]_event_, const char pass:[*]_name_); | ||
97 | struct tep_format_field pass:[*]*tep_find_any_field*(struct tep_event pass:[*]_event_, const char pass:[*]_name_); | ||
98 | |||
99 | Functions resolver: | ||
100 | int *tep_set_function_resolver*(struct tep_handle pass:[*]_tep_, tep_func_resolver_t pass:[*]_func_, void pass:[*]_priv_); | ||
101 | void *tep_reset_function_resolver*(struct tep_handle pass:[*]_tep_); | ||
102 | const char pass:[*]*tep_find_function*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_); | ||
103 | unsigned long long *tep_find_function_address*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_); | ||
104 | |||
105 | Filter management: | ||
106 | struct tep_event_filter pass:[*]*tep_filter_alloc*(struct tep_handle pass:[*]_tep_); | ||
107 | enum tep_errno *tep_filter_add_filter_str*(struct tep_event_filter pass:[*]_filter_, const char pass:[*]_filter_str_); | ||
108 | enum tep_errno *tep_filter_match*(struct tep_event_filter pass:[*]_filter_, struct tep_record pass:[*]_record_); | ||
109 | int *tep_filter_strerror*(struct tep_event_filter pass:[*]_filter_, enum tep_errno _err_, char pass:[*]buf, size_t _buflen_); | ||
110 | int *tep_event_filtered*(struct tep_event_filter pass:[*]_filter_, int _event_id_); | ||
111 | void *tep_filter_reset*(struct tep_event_filter pass:[*]_filter_); | ||
112 | void *tep_filter_free*(struct tep_event_filter pass:[*]_filter_); | ||
113 | char pass:[*]*tep_filter_make_string*(struct tep_event_filter pass:[*]_filter_, int _event_id_); | ||
114 | int *tep_filter_remove_event*(struct tep_event_filter pass:[*]_filter_, int _event_id_); | ||
115 | int *tep_filter_copy*(struct tep_event_filter pass:[*]_dest_, struct tep_event_filter pass:[*]_source_); | ||
116 | int *tep_filter_compare*(struct tep_event_filter pass:[*]_filter1_, struct tep_event_filter pass:[*]_filter2_); | ||
117 | |||
118 | Parsing various data from the records: | ||
119 | void *tep_data_latency_format*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_record pass:[*]_record_); | ||
120 | int *tep_data_type*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); | ||
121 | int *tep_data_pid*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); | ||
122 | int *tep_data_preempt_count*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); | ||
123 | int *tep_data_flags*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); | ||
124 | |||
125 | Command and task related APIs: | ||
126 | const char pass:[*]*tep_data_comm_from_pid*(struct tep_handle pass:[*]_tep_, int _pid_); | ||
127 | struct cmdline pass:[*]*tep_data_pid_from_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, struct cmdline pass:[*]_next_); | ||
128 | int *tep_register_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, int _pid_); | ||
129 | int *tep_override_comm*(struct tep_handle pass:[*]_tep_, const char pass:[*]_comm_, int _pid_); | ||
130 | bool *tep_is_pid_registered*(struct tep_handle pass:[*]_tep_, int _pid_); | ||
131 | int *tep_cmdline_pid*(struct tep_handle pass:[*]_tep_, struct cmdline pass:[*]_cmdline_); | ||
132 | |||
133 | Endian related APIs: | ||
134 | int *tep_is_bigendian*(void); | ||
135 | unsigned long long *tep_read_number*(struct tep_handle pass:[*]_tep_, const void pass:[*]_ptr_, int _size_); | ||
136 | bool *tep_is_file_bigendian*(struct tep_handle pass:[*]_tep_); | ||
137 | void *tep_set_file_bigendian*(struct tep_handle pass:[*]_tep_, enum tep_endian _endian_); | ||
138 | bool *tep_is_local_bigendian*(struct tep_handle pass:[*]_tep_); | ||
139 | void *tep_set_local_bigendian*(struct tep_handle pass:[*]_tep_, enum tep_endian _endian_); | ||
140 | |||
141 | Trace sequences: | ||
142 | *#include <trace-seq.h>* | ||
143 | void *trace_seq_init*(struct trace_seq pass:[*]_s_); | ||
144 | void *trace_seq_reset*(struct trace_seq pass:[*]_s_); | ||
145 | void *trace_seq_destroy*(struct trace_seq pass:[*]_s_); | ||
146 | int *trace_seq_printf*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, ...); | ||
147 | int *trace_seq_vprintf*(struct trace_seq pass:[*]_s_, const char pass:[*]_fmt_, va_list _args_); | ||
148 | int *trace_seq_puts*(struct trace_seq pass:[*]_s_, const char pass:[*]_str_); | ||
149 | int *trace_seq_putc*(struct trace_seq pass:[*]_s_, unsigned char _c_); | ||
150 | void *trace_seq_terminate*(struct trace_seq pass:[*]_s_); | ||
151 | int *trace_seq_do_fprintf*(struct trace_seq pass:[*]_s_, FILE pass:[*]_fp_); | ||
152 | int *trace_seq_do_printf*(struct trace_seq pass:[*]_s_); | ||
153 | -- | ||
154 | |||
155 | DESCRIPTION | ||
156 | ----------- | ||
157 | The libtraceevent(3) library provides APIs to access kernel tracepoint events, | ||
158 | located in the tracefs file system under the events directory. | ||
159 | |||
160 | ENVIRONMENT | ||
161 | ----------- | ||
162 | [verse] | ||
163 | -- | ||
164 | TRACEEVENT_PLUGIN_DIR | ||
165 | Additional plugin directory. All shared object files, located in this directory will be loaded as traceevent plugins. | ||
166 | -- | ||
167 | |||
168 | FILES | ||
169 | ----- | ||
170 | [verse] | ||
171 | -- | ||
172 | *event-parse.h* | ||
173 | Header file to include in order to have access to the library APIs. | ||
174 | *trace-seq.h* | ||
175 | Header file to include in order to have access to trace sequences related APIs. | ||
176 | Trace sequences are used to allow a function to call several other functions | ||
177 | to create a string of data to use. | ||
178 | *-ltraceevent* | ||
179 | Linker switch to add when building a program that uses the library. | ||
180 | -- | ||
181 | |||
182 | SEE ALSO | ||
183 | -------- | ||
184 | _trace-cmd(1)_ | ||
185 | |||
186 | AUTHOR | ||
187 | ------ | ||
188 | [verse] | ||
189 | -- | ||
190 | *Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. | ||
191 | *Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. | ||
192 | -- | ||
193 | REPORTING BUGS | ||
194 | -------------- | ||
195 | Report bugs to <linux-trace-devel@vger.kernel.org> | ||
196 | |||
197 | LICENSE | ||
198 | ------- | ||
199 | libtraceevent is Free Software licensed under the GNU LGPL 2.1 | ||
200 | |||
201 | RESOURCES | ||
202 | --------- | ||
203 | https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
diff --git a/tools/lib/traceevent/Documentation/manpage-1.72.xsl b/tools/lib/traceevent/Documentation/manpage-1.72.xsl new file mode 100644 index 000000000000..b4d315cb8c47 --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-1.72.xsl | |||
@@ -0,0 +1,14 @@ | |||
1 | <!-- manpage-1.72.xsl: | ||
2 | special settings for manpages rendered from asciidoc+docbook | ||
3 | handles peculiarities in docbook-xsl 1.72.0 --> | ||
4 | <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | ||
5 | version="1.0"> | ||
6 | |||
7 | <xsl:import href="manpage-base.xsl"/> | ||
8 | |||
9 | <!-- these are the special values for the roff control characters | ||
10 | needed for docbook-xsl 1.72.0 --> | ||
11 | <xsl:param name="git.docbook.backslash">▓</xsl:param> | ||
12 | <xsl:param name="git.docbook.dot" >⌂</xsl:param> | ||
13 | |||
14 | </xsl:stylesheet> | ||
diff --git a/tools/lib/traceevent/Documentation/manpage-base.xsl b/tools/lib/traceevent/Documentation/manpage-base.xsl new file mode 100644 index 000000000000..a264fa616093 --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-base.xsl | |||
@@ -0,0 +1,35 @@ | |||
1 | <!-- manpage-base.xsl: | ||
2 | special formatting for manpages rendered from asciidoc+docbook --> | ||
3 | <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | ||
4 | version="1.0"> | ||
5 | |||
6 | <!-- these params silence some output from xmlto --> | ||
7 | <xsl:param name="man.output.quietly" select="1"/> | ||
8 | <xsl:param name="refentry.meta.get.quietly" select="1"/> | ||
9 | |||
10 | <!-- convert asciidoc callouts to man page format; | ||
11 | git.docbook.backslash and git.docbook.dot params | ||
12 | must be supplied by another XSL file or other means --> | ||
13 | <xsl:template match="co"> | ||
14 | <xsl:value-of select="concat( | ||
15 | $git.docbook.backslash,'fB(', | ||
16 | substring-after(@id,'-'),')', | ||
17 | $git.docbook.backslash,'fR')"/> | ||
18 | </xsl:template> | ||
19 | <xsl:template match="calloutlist"> | ||
20 | <xsl:value-of select="$git.docbook.dot"/> | ||
21 | <xsl:text>sp </xsl:text> | ||
22 | <xsl:apply-templates/> | ||
23 | <xsl:text> </xsl:text> | ||
24 | </xsl:template> | ||
25 | <xsl:template match="callout"> | ||
26 | <xsl:value-of select="concat( | ||
27 | $git.docbook.backslash,'fB', | ||
28 | substring-after(@arearefs,'-'), | ||
29 | '. ',$git.docbook.backslash,'fR')"/> | ||
30 | <xsl:apply-templates/> | ||
31 | <xsl:value-of select="$git.docbook.dot"/> | ||
32 | <xsl:text>br </xsl:text> | ||
33 | </xsl:template> | ||
34 | |||
35 | </xsl:stylesheet> | ||
diff --git a/tools/lib/traceevent/Documentation/manpage-bold-literal.xsl b/tools/lib/traceevent/Documentation/manpage-bold-literal.xsl new file mode 100644 index 000000000000..608eb5df6281 --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-bold-literal.xsl | |||
@@ -0,0 +1,17 @@ | |||
1 | <!-- manpage-bold-literal.xsl: | ||
2 | special formatting for manpages rendered from asciidoc+docbook --> | ||
3 | <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | ||
4 | version="1.0"> | ||
5 | |||
6 | <!-- render literal text as bold (instead of plain or monospace); | ||
7 | this makes literal text easier to distinguish in manpages | ||
8 | viewed on a tty --> | ||
9 | <xsl:template match="literal"> | ||
10 | <xsl:value-of select="$git.docbook.backslash"/> | ||
11 | <xsl:text>fB</xsl:text> | ||
12 | <xsl:apply-templates/> | ||
13 | <xsl:value-of select="$git.docbook.backslash"/> | ||
14 | <xsl:text>fR</xsl:text> | ||
15 | </xsl:template> | ||
16 | |||
17 | </xsl:stylesheet> | ||
diff --git a/tools/lib/traceevent/Documentation/manpage-normal.xsl b/tools/lib/traceevent/Documentation/manpage-normal.xsl new file mode 100644 index 000000000000..a48f5b11f3dc --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-normal.xsl | |||
@@ -0,0 +1,13 @@ | |||
1 | <!-- manpage-normal.xsl: | ||
2 | special settings for manpages rendered from asciidoc+docbook | ||
3 | handles anything we want to keep away from docbook-xsl 1.72.0 --> | ||
4 | <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | ||
5 | version="1.0"> | ||
6 | |||
7 | <xsl:import href="manpage-base.xsl"/> | ||
8 | |||
9 | <!-- these are the normal values for the roff control characters --> | ||
10 | <xsl:param name="git.docbook.backslash">\</xsl:param> | ||
11 | <xsl:param name="git.docbook.dot" >.</xsl:param> | ||
12 | |||
13 | </xsl:stylesheet> | ||
diff --git a/tools/lib/traceevent/Documentation/manpage-suppress-sp.xsl b/tools/lib/traceevent/Documentation/manpage-suppress-sp.xsl new file mode 100644 index 000000000000..a63c7632a87d --- /dev/null +++ b/tools/lib/traceevent/Documentation/manpage-suppress-sp.xsl | |||
@@ -0,0 +1,21 @@ | |||
1 | <!-- manpage-suppress-sp.xsl: | ||
2 | special settings for manpages rendered from asciidoc+docbook | ||
3 | handles erroneous, inline .sp in manpage output of some | ||
4 | versions of docbook-xsl --> | ||
5 | <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | ||
6 | version="1.0"> | ||
7 | |||
8 | <!-- attempt to work around spurious .sp at the tail of the line | ||
9 | that some versions of docbook stylesheets seem to add --> | ||
10 | <xsl:template match="simpara"> | ||
11 | <xsl:variable name="content"> | ||
12 | <xsl:apply-templates/> | ||
13 | </xsl:variable> | ||
14 | <xsl:value-of select="normalize-space($content)"/> | ||
15 | <xsl:if test="not(ancestor::authorblurb) and | ||
16 | not(ancestor::personblurb)"> | ||
17 | <xsl:text> </xsl:text> | ||
18 | </xsl:if> | ||
19 | </xsl:template> | ||
20 | |||
21 | </xsl:stylesheet> | ||
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 941761d9923d..3292c290654f 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
@@ -50,9 +50,13 @@ man_dir = $(prefix)/share/man | |||
50 | man_dir_SQ = '$(subst ','\'',$(man_dir))' | 50 | man_dir_SQ = '$(subst ','\'',$(man_dir))' |
51 | pkgconfig_dir ?= $(word 1,$(shell $(PKG_CONFIG) \ | 51 | pkgconfig_dir ?= $(word 1,$(shell $(PKG_CONFIG) \ |
52 | --variable pc_path pkg-config | tr ":" " ")) | 52 | --variable pc_path pkg-config | tr ":" " ")) |
53 | includedir_relative = traceevent | ||
54 | includedir = $(prefix)/include/$(includedir_relative) | ||
55 | includedir_SQ = '$(subst ','\'',$(includedir))' | ||
53 | 56 | ||
54 | export man_dir man_dir_SQ INSTALL | 57 | export man_dir man_dir_SQ INSTALL |
55 | export DESTDIR DESTDIR_SQ | 58 | export DESTDIR DESTDIR_SQ |
59 | export EVENT_PARSE_VERSION | ||
56 | 60 | ||
57 | set_plugin_dir := 1 | 61 | set_plugin_dir := 1 |
58 | 62 | ||
@@ -279,6 +283,8 @@ define do_install_pkgconfig_file | |||
279 | cp -f ${PKG_CONFIG_FILE}.template ${PKG_CONFIG_FILE}; \ | 283 | cp -f ${PKG_CONFIG_FILE}.template ${PKG_CONFIG_FILE}; \ |
280 | sed -i "s|INSTALL_PREFIX|${1}|g" ${PKG_CONFIG_FILE}; \ | 284 | sed -i "s|INSTALL_PREFIX|${1}|g" ${PKG_CONFIG_FILE}; \ |
281 | sed -i "s|LIB_VERSION|${EVENT_PARSE_VERSION}|g" ${PKG_CONFIG_FILE}; \ | 285 | sed -i "s|LIB_VERSION|${EVENT_PARSE_VERSION}|g" ${PKG_CONFIG_FILE}; \ |
286 | sed -i "s|LIB_DIR|${libdir}|g" ${PKG_CONFIG_FILE}; \ | ||
287 | sed -i "s|HEADER_DIR|$(includedir)|g" ${PKG_CONFIG_FILE}; \ | ||
282 | $(call do_install,$(PKG_CONFIG_FILE),$(pkgconfig_dir),644); \ | 288 | $(call do_install,$(PKG_CONFIG_FILE),$(pkgconfig_dir),644); \ |
283 | else \ | 289 | else \ |
284 | (echo Failed to locate pkg-config directory) 1>&2; \ | 290 | (echo Failed to locate pkg-config directory) 1>&2; \ |
@@ -300,10 +306,10 @@ install_pkgconfig: | |||
300 | 306 | ||
301 | install_headers: | 307 | install_headers: |
302 | $(call QUIET_INSTALL, headers) \ | 308 | $(call QUIET_INSTALL, headers) \ |
303 | $(call do_install,event-parse.h,$(prefix)/include/traceevent,644); \ | 309 | $(call do_install,event-parse.h,$(DESTDIR)$(includedir_SQ),644); \ |
304 | $(call do_install,event-utils.h,$(prefix)/include/traceevent,644); \ | 310 | $(call do_install,event-utils.h,$(DESTDIR)$(includedir_SQ),644); \ |
305 | $(call do_install,trace-seq.h,$(prefix)/include/traceevent,644); \ | 311 | $(call do_install,trace-seq.h,$(DESTDIR)$(includedir_SQ),644); \ |
306 | $(call do_install,kbuffer.h,$(prefix)/include/traceevent,644) | 312 | $(call do_install,kbuffer.h,$(DESTDIR)$(includedir_SQ),644) |
307 | 313 | ||
308 | install: install_lib | 314 | install: install_lib |
309 | 315 | ||
@@ -313,6 +319,38 @@ clean: | |||
313 | $(RM) TRACEEVENT-CFLAGS tags TAGS; \ | 319 | $(RM) TRACEEVENT-CFLAGS tags TAGS; \ |
314 | $(RM) $(PKG_CONFIG_FILE) | 320 | $(RM) $(PKG_CONFIG_FILE) |
315 | 321 | ||
322 | PHONY += doc | ||
323 | doc: | ||
324 | $(call descend,Documentation) | ||
325 | |||
326 | PHONY += doc-clean | ||
327 | doc-clean: | ||
328 | $(call descend,Documentation,clean) | ||
329 | |||
330 | PHONY += doc-install | ||
331 | doc-install: | ||
332 | $(call descend,Documentation,install) | ||
333 | |||
334 | PHONY += doc-uninstall | ||
335 | doc-uninstall: | ||
336 | $(call descend,Documentation,uninstall) | ||
337 | |||
338 | PHONY += help | ||
339 | help: | ||
340 | @echo 'Possible targets:' | ||
341 | @echo'' | ||
342 | @echo ' all - default, compile the library and the'\ | ||
343 | 'plugins' | ||
344 | @echo ' plugins - compile the plugins' | ||
345 | @echo ' install - install the library, the plugins,'\ | ||
346 | 'the header and pkgconfig files' | ||
347 | @echo ' clean - clean the library and the plugins object files' | ||
348 | @echo ' doc - compile the documentation files - man'\ | ||
349 | 'and html pages, in the Documentation directory' | ||
350 | @echo ' doc-clean - clean the documentation files' | ||
351 | @echo ' doc-install - install the man pages' | ||
352 | @echo ' doc-uninstall - uninstall the man pages' | ||
353 | @echo'' | ||
316 | PHONY += force plugins | 354 | PHONY += force plugins |
317 | force: | 355 | force: |
318 | 356 | ||
diff --git a/tools/lib/traceevent/libtraceevent.pc.template b/tools/lib/traceevent/libtraceevent.pc.template index 42e4d6cb6b9e..86384fcd57f1 100644 --- a/tools/lib/traceevent/libtraceevent.pc.template +++ b/tools/lib/traceevent/libtraceevent.pc.template | |||
@@ -1,6 +1,6 @@ | |||
1 | prefix=INSTALL_PREFIX | 1 | prefix=INSTALL_PREFIX |
2 | libdir=${prefix}/lib64 | 2 | libdir=LIB_DIR |
3 | includedir=${prefix}/include/traceevent | 3 | includedir=HEADER_DIR |
4 | 4 | ||
5 | Name: libtraceevent | 5 | Name: libtraceevent |
6 | URL: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | 6 | URL: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git |
diff --git a/tools/pci/Makefile b/tools/pci/Makefile index 9b7534457060..6876ee4bd78c 100644 --- a/tools/pci/Makefile +++ b/tools/pci/Makefile | |||
@@ -47,7 +47,7 @@ clean: | |||
47 | 47 | ||
48 | install: $(ALL_PROGRAMS) | 48 | install: $(ALL_PROGRAMS) |
49 | install -d -m 755 $(DESTDIR)$(bindir); \ | 49 | install -d -m 755 $(DESTDIR)$(bindir); \ |
50 | for program in $(ALL_PROGRAMS); do \ | 50 | for program in $(ALL_PROGRAMS) pcitest.sh; do \ |
51 | install $$program $(DESTDIR)$(bindir); \ | 51 | install $$program $(DESTDIR)$(bindir); \ |
52 | done; \ | 52 | done; \ |
53 | for script in $(ALL_SCRIPTS); do \ | 53 | for script in $(ALL_SCRIPTS); do \ |
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 138fb6e94b3c..18ed1b0fceb3 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt | |||
@@ -199,6 +199,18 @@ also be supplied. For example: | |||
199 | 199 | ||
200 | perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ... | 200 | perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ... |
201 | 201 | ||
202 | EVENT QUALIFIERS: | ||
203 | |||
204 | It is also possible to add extra qualifiers to an event: | ||
205 | |||
206 | percore: | ||
207 | |||
208 | Sums up the event counts for all hardware threads in a core, e.g.: | ||
209 | |||
210 | |||
211 | perf stat -e cpu/event=0,umask=0x3,percore=1/ | ||
212 | |||
213 | |||
202 | EVENT GROUPS | 214 | EVENT GROUPS |
203 | ------------ | 215 | ------------ |
204 | 216 | ||
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 58986f4cc190..de269430720a 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -406,7 +406,8 @@ symbolic names, e.g. on x86, ax, si. To list the available registers use | |||
406 | --intr-regs=ax,bx. The list of register is architecture dependent. | 406 | --intr-regs=ax,bx. The list of register is architecture dependent. |
407 | 407 | ||
408 | --user-regs:: | 408 | --user-regs:: |
409 | Capture user registers at sample time. Same arguments as -I. | 409 | Similar to -I, but capture user registers at sample time. To list the available |
410 | user registers use --user-regs=\?. | ||
410 | 411 | ||
411 | --running-time:: | 412 | --running-time:: |
412 | Record running and enabled time for read events (:S) | 413 | Record running and enabled time for read events (:S) |
@@ -478,6 +479,11 @@ Also at some cases executing less output write syscalls with bigger data size | |||
478 | can take less time than executing more output write syscalls with smaller data | 479 | can take less time than executing more output write syscalls with smaller data |
479 | size thus lowering runtime profiling overhead. | 480 | size thus lowering runtime profiling overhead. |
480 | 481 | ||
482 | -z:: | ||
483 | --compression-level[=n]:: | ||
484 | Produce compressed trace using specified level n (default: 1 - fastest compression, | ||
485 | 22 - smallest trace) | ||
486 | |||
481 | --all-kernel:: | 487 | --all-kernel:: |
482 | Configure all used events to run in kernel space. | 488 | Configure all used events to run in kernel space. |
483 | 489 | ||
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 39c05f89104e..1e312c2672e4 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -43,6 +43,10 @@ report:: | |||
43 | param1 and param2 are defined as formats for the PMU in | 43 | param1 and param2 are defined as formats for the PMU in |
44 | /sys/bus/event_source/devices/<pmu>/format/* | 44 | /sys/bus/event_source/devices/<pmu>/format/* |
45 | 45 | ||
46 | 'percore' is a event qualifier that sums up the event counts for both | ||
47 | hardware threads in a core. For example: | ||
48 | perf stat -A -a -e cpu/event,percore=1/,otherevent ... | ||
49 | |||
46 | - a symbolically formed event like 'pmu/config=M,config1=N,config2=K/' | 50 | - a symbolically formed event like 'pmu/config=M,config1=N,config2=K/' |
47 | where M, N, K are numbers (in decimal, hex, octal format). | 51 | where M, N, K are numbers (in decimal, hex, octal format). |
48 | Acceptable values for each of 'config', 'config1' and 'config2' | 52 | Acceptable values for each of 'config', 'config1' and 'config2' |
diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt index 593ef49b273c..6967e9b02be5 100644 --- a/tools/perf/Documentation/perf.data-file-format.txt +++ b/tools/perf/Documentation/perf.data-file-format.txt | |||
@@ -272,6 +272,19 @@ struct { | |||
272 | 272 | ||
273 | Two uint64_t for the time of first sample and the time of last sample. | 273 | Two uint64_t for the time of first sample and the time of last sample. |
274 | 274 | ||
275 | HEADER_COMPRESSED = 27, | ||
276 | |||
277 | struct { | ||
278 | u32 version; | ||
279 | u32 type; | ||
280 | u32 level; | ||
281 | u32 ratio; | ||
282 | u32 mmap_len; | ||
283 | }; | ||
284 | |||
285 | Indicates that trace contains records of PERF_RECORD_COMPRESSED type | ||
286 | that have perf_events records in compressed form. | ||
287 | |||
275 | other bits are reserved and should ignored for now | 288 | other bits are reserved and should ignored for now |
276 | HEADER_FEAT_BITS = 256, | 289 | HEADER_FEAT_BITS = 256, |
277 | 290 | ||
@@ -437,6 +450,17 @@ struct auxtrace_error_event { | |||
437 | Describes a header feature. These are records used in pipe-mode that | 450 | Describes a header feature. These are records used in pipe-mode that |
438 | contain information that otherwise would be in perf.data file's header. | 451 | contain information that otherwise would be in perf.data file's header. |
439 | 452 | ||
453 | PERF_RECORD_COMPRESSED = 81, | ||
454 | |||
455 | struct compressed_event { | ||
456 | struct perf_event_header header; | ||
457 | char data[]; | ||
458 | }; | ||
459 | |||
460 | The header is followed by compressed data frame that can be decompressed | ||
461 | into array of perf trace records. The size of the entire compressed event | ||
462 | record including the header is limited by the max value of header.size. | ||
463 | |||
440 | Event types | 464 | Event types |
441 | 465 | ||
442 | Define the event attributes with their IDs. | 466 | Define the event attributes with their IDs. |
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt index 864e37597252..401f0ed67439 100644 --- a/tools/perf/Documentation/perf.txt +++ b/tools/perf/Documentation/perf.txt | |||
@@ -22,6 +22,8 @@ OPTIONS | |||
22 | verbose - general debug messages | 22 | verbose - general debug messages |
23 | ordered-events - ordered events object debug messages | 23 | ordered-events - ordered events object debug messages |
24 | data-convert - data convert command debug messages | 24 | data-convert - data convert command debug messages |
25 | stderr - write debug output (option -v) to stderr | ||
26 | in browser mode | ||
25 | 27 | ||
26 | --buildid-dir:: | 28 | --buildid-dir:: |
27 | Setup buildid cache directory. It has higher priority than | 29 | Setup buildid cache directory. It has higher priority than |
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h index 7f6d538f8a89..b7cd91a9014f 100644 --- a/tools/perf/arch/x86/include/perf_regs.h +++ b/tools/perf/arch/x86/include/perf_regs.h | |||
@@ -8,9 +8,10 @@ | |||
8 | 8 | ||
9 | void perf_regs_load(u64 *regs); | 9 | void perf_regs_load(u64 *regs); |
10 | 10 | ||
11 | #define PERF_REGS_MAX PERF_REG_X86_XMM_MAX | ||
12 | #define PERF_XMM_REGS_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1)) | ||
11 | #ifndef HAVE_ARCH_X86_64_SUPPORT | 13 | #ifndef HAVE_ARCH_X86_64_SUPPORT |
12 | #define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1) | 14 | #define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1) |
13 | #define PERF_REGS_MAX PERF_REG_X86_32_MAX | ||
14 | #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32 | 15 | #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32 |
15 | #else | 16 | #else |
16 | #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \ | 17 | #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \ |
@@ -18,7 +19,6 @@ void perf_regs_load(u64 *regs); | |||
18 | (1ULL << PERF_REG_X86_FS) | \ | 19 | (1ULL << PERF_REG_X86_FS) | \ |
19 | (1ULL << PERF_REG_X86_GS)) | 20 | (1ULL << PERF_REG_X86_GS)) |
20 | #define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT) | 21 | #define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT) |
21 | #define PERF_REGS_MAX PERF_REG_X86_64_MAX | ||
22 | #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64 | 22 | #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64 |
23 | #endif | 23 | #endif |
24 | #define PERF_REG_IP PERF_REG_X86_IP | 24 | #define PERF_REG_IP PERF_REG_X86_IP |
@@ -77,6 +77,28 @@ static inline const char *perf_reg_name(int id) | |||
77 | case PERF_REG_X86_R15: | 77 | case PERF_REG_X86_R15: |
78 | return "R15"; | 78 | return "R15"; |
79 | #endif /* HAVE_ARCH_X86_64_SUPPORT */ | 79 | #endif /* HAVE_ARCH_X86_64_SUPPORT */ |
80 | |||
81 | #define XMM(x) \ | ||
82 | case PERF_REG_X86_XMM ## x: \ | ||
83 | case PERF_REG_X86_XMM ## x + 1: \ | ||
84 | return "XMM" #x; | ||
85 | XMM(0) | ||
86 | XMM(1) | ||
87 | XMM(2) | ||
88 | XMM(3) | ||
89 | XMM(4) | ||
90 | XMM(5) | ||
91 | XMM(6) | ||
92 | XMM(7) | ||
93 | XMM(8) | ||
94 | XMM(9) | ||
95 | XMM(10) | ||
96 | XMM(11) | ||
97 | XMM(12) | ||
98 | XMM(13) | ||
99 | XMM(14) | ||
100 | XMM(15) | ||
101 | #undef XMM | ||
80 | default: | 102 | default: |
81 | return NULL; | 103 | return NULL; |
82 | } | 104 | } |
diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c index fead6b3b4206..7886ca5263e3 100644 --- a/tools/perf/arch/x86/util/perf_regs.c +++ b/tools/perf/arch/x86/util/perf_regs.c | |||
@@ -31,6 +31,22 @@ const struct sample_reg sample_reg_masks[] = { | |||
31 | SMPL_REG(R14, PERF_REG_X86_R14), | 31 | SMPL_REG(R14, PERF_REG_X86_R14), |
32 | SMPL_REG(R15, PERF_REG_X86_R15), | 32 | SMPL_REG(R15, PERF_REG_X86_R15), |
33 | #endif | 33 | #endif |
34 | SMPL_REG2(XMM0, PERF_REG_X86_XMM0), | ||
35 | SMPL_REG2(XMM1, PERF_REG_X86_XMM1), | ||
36 | SMPL_REG2(XMM2, PERF_REG_X86_XMM2), | ||
37 | SMPL_REG2(XMM3, PERF_REG_X86_XMM3), | ||
38 | SMPL_REG2(XMM4, PERF_REG_X86_XMM4), | ||
39 | SMPL_REG2(XMM5, PERF_REG_X86_XMM5), | ||
40 | SMPL_REG2(XMM6, PERF_REG_X86_XMM6), | ||
41 | SMPL_REG2(XMM7, PERF_REG_X86_XMM7), | ||
42 | SMPL_REG2(XMM8, PERF_REG_X86_XMM8), | ||
43 | SMPL_REG2(XMM9, PERF_REG_X86_XMM9), | ||
44 | SMPL_REG2(XMM10, PERF_REG_X86_XMM10), | ||
45 | SMPL_REG2(XMM11, PERF_REG_X86_XMM11), | ||
46 | SMPL_REG2(XMM12, PERF_REG_X86_XMM12), | ||
47 | SMPL_REG2(XMM13, PERF_REG_X86_XMM13), | ||
48 | SMPL_REG2(XMM14, PERF_REG_X86_XMM14), | ||
49 | SMPL_REG2(XMM15, PERF_REG_X86_XMM15), | ||
34 | SMPL_REG_END | 50 | SMPL_REG_END |
35 | }; | 51 | }; |
36 | 52 | ||
@@ -254,3 +270,31 @@ int arch_sdt_arg_parse_op(char *old_op, char **new_op) | |||
254 | 270 | ||
255 | return SDT_ARG_VALID; | 271 | return SDT_ARG_VALID; |
256 | } | 272 | } |
273 | |||
274 | uint64_t arch__intr_reg_mask(void) | ||
275 | { | ||
276 | struct perf_event_attr attr = { | ||
277 | .type = PERF_TYPE_HARDWARE, | ||
278 | .config = PERF_COUNT_HW_CPU_CYCLES, | ||
279 | .sample_type = PERF_SAMPLE_REGS_INTR, | ||
280 | .sample_regs_intr = PERF_XMM_REGS_MASK, | ||
281 | .precise_ip = 1, | ||
282 | .disabled = 1, | ||
283 | .exclude_kernel = 1, | ||
284 | }; | ||
285 | int fd; | ||
286 | /* | ||
287 | * In an unnamed union, init it here to build on older gcc versions | ||
288 | */ | ||
289 | attr.sample_period = 1; | ||
290 | |||
291 | event_attr_init(&attr); | ||
292 | |||
293 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | ||
294 | if (fd != -1) { | ||
295 | close(fd); | ||
296 | return (PERF_XMM_REGS_MASK | PERF_REGS_MASK); | ||
297 | } | ||
298 | |||
299 | return PERF_REGS_MASK; | ||
300 | } | ||
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 67f9d9ffacfb..77deb3a40596 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -159,8 +159,6 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, | |||
159 | struct perf_evsel *evsel = iter->evsel; | 159 | struct perf_evsel *evsel = iter->evsel; |
160 | int err; | 160 | int err; |
161 | 161 | ||
162 | hist__account_cycles(sample->branch_stack, al, sample, false); | ||
163 | |||
164 | bi = he->branch_info; | 162 | bi = he->branch_info; |
165 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); | 163 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); |
166 | 164 | ||
@@ -199,6 +197,8 @@ static int process_branch_callback(struct perf_evsel *evsel, | |||
199 | if (a.map != NULL) | 197 | if (a.map != NULL) |
200 | a.map->dso->hit = 1; | 198 | a.map->dso->hit = 1; |
201 | 199 | ||
200 | hist__account_cycles(sample->branch_stack, al, sample, false); | ||
201 | |||
202 | ret = hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann); | 202 | ret = hist_entry_iter__add(&iter, &a, PERF_MAX_STACK_DEPTH, ann); |
203 | return ret; | 203 | return ret; |
204 | } | 204 | } |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 24086b7f1b14..8e0e06d3edfc 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -837,6 +837,9 @@ int cmd_inject(int argc, const char **argv) | |||
837 | if (inject.session == NULL) | 837 | if (inject.session == NULL) |
838 | return -1; | 838 | return -1; |
839 | 839 | ||
840 | if (zstd_init(&(inject.session->zstd_data), 0) < 0) | ||
841 | pr_warning("Decompression initialization failed.\n"); | ||
842 | |||
840 | if (inject.build_ids) { | 843 | if (inject.build_ids) { |
841 | /* | 844 | /* |
842 | * to make sure the mmap records are ordered correctly | 845 | * to make sure the mmap records are ordered correctly |
@@ -867,6 +870,7 @@ int cmd_inject(int argc, const char **argv) | |||
867 | ret = __cmd_inject(&inject); | 870 | ret = __cmd_inject(&inject); |
868 | 871 | ||
869 | out_delete: | 872 | out_delete: |
873 | zstd_fini(&(inject.session->zstd_data)); | ||
870 | perf_session__delete(inject.session); | 874 | perf_session__delete(inject.session); |
871 | return ret; | 875 | return ret; |
872 | } | 876 | } |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index c5e10552776a..e2c3a585a61e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -133,6 +133,11 @@ static int record__write(struct record *rec, struct perf_mmap *map __maybe_unuse | |||
133 | return 0; | 133 | return 0; |
134 | } | 134 | } |
135 | 135 | ||
136 | static int record__aio_enabled(struct record *rec); | ||
137 | static int record__comp_enabled(struct record *rec); | ||
138 | static size_t zstd_compress(struct perf_session *session, void *dst, size_t dst_size, | ||
139 | void *src, size_t src_size); | ||
140 | |||
136 | #ifdef HAVE_AIO_SUPPORT | 141 | #ifdef HAVE_AIO_SUPPORT |
137 | static int record__aio_write(struct aiocb *cblock, int trace_fd, | 142 | static int record__aio_write(struct aiocb *cblock, int trace_fd, |
138 | void *buf, size_t size, off_t off) | 143 | void *buf, size_t size, off_t off) |
@@ -183,9 +188,9 @@ static int record__aio_complete(struct perf_mmap *md, struct aiocb *cblock) | |||
183 | if (rem_size == 0) { | 188 | if (rem_size == 0) { |
184 | cblock->aio_fildes = -1; | 189 | cblock->aio_fildes = -1; |
185 | /* | 190 | /* |
186 | * md->refcount is incremented in perf_mmap__push() for | 191 | * md->refcount is incremented in record__aio_pushfn() for |
187 | * every enqueued aio write request so decrement it because | 192 | * every aio write request started in record__aio_push() so |
188 | * the request is now complete. | 193 | * decrement it because the request is now complete. |
189 | */ | 194 | */ |
190 | perf_mmap__put(md); | 195 | perf_mmap__put(md); |
191 | rc = 1; | 196 | rc = 1; |
@@ -240,18 +245,89 @@ static int record__aio_sync(struct perf_mmap *md, bool sync_all) | |||
240 | } while (1); | 245 | } while (1); |
241 | } | 246 | } |
242 | 247 | ||
243 | static int record__aio_pushfn(void *to, struct aiocb *cblock, void *bf, size_t size, off_t off) | 248 | struct record_aio { |
249 | struct record *rec; | ||
250 | void *data; | ||
251 | size_t size; | ||
252 | }; | ||
253 | |||
254 | static int record__aio_pushfn(struct perf_mmap *map, void *to, void *buf, size_t size) | ||
244 | { | 255 | { |
245 | struct record *rec = to; | 256 | struct record_aio *aio = to; |
246 | int ret, trace_fd = rec->session->data->file.fd; | ||
247 | 257 | ||
248 | rec->samples++; | 258 | /* |
259 | * map->base data pointed by buf is copied into free map->aio.data[] buffer | ||
260 | * to release space in the kernel buffer as fast as possible, calling | ||
261 | * perf_mmap__consume() from perf_mmap__push() function. | ||
262 | * | ||
263 | * That lets the kernel to proceed with storing more profiling data into | ||
264 | * the kernel buffer earlier than other per-cpu kernel buffers are handled. | ||
265 | * | ||
266 | * Coping can be done in two steps in case the chunk of profiling data | ||
267 | * crosses the upper bound of the kernel buffer. In this case we first move | ||
268 | * part of data from map->start till the upper bound and then the reminder | ||
269 | * from the beginning of the kernel buffer till the end of the data chunk. | ||
270 | */ | ||
271 | |||
272 | if (record__comp_enabled(aio->rec)) { | ||
273 | size = zstd_compress(aio->rec->session, aio->data + aio->size, | ||
274 | perf_mmap__mmap_len(map) - aio->size, | ||
275 | buf, size); | ||
276 | } else { | ||
277 | memcpy(aio->data + aio->size, buf, size); | ||
278 | } | ||
279 | |||
280 | if (!aio->size) { | ||
281 | /* | ||
282 | * Increment map->refcount to guard map->aio.data[] buffer | ||
283 | * from premature deallocation because map object can be | ||
284 | * released earlier than aio write request started on | ||
285 | * map->aio.data[] buffer is complete. | ||
286 | * | ||
287 | * perf_mmap__put() is done at record__aio_complete() | ||
288 | * after started aio request completion or at record__aio_push() | ||
289 | * if the request failed to start. | ||
290 | */ | ||
291 | perf_mmap__get(map); | ||
292 | } | ||
293 | |||
294 | aio->size += size; | ||
295 | |||
296 | return size; | ||
297 | } | ||
249 | 298 | ||
250 | ret = record__aio_write(cblock, trace_fd, bf, size, off); | 299 | static int record__aio_push(struct record *rec, struct perf_mmap *map, off_t *off) |
300 | { | ||
301 | int ret, idx; | ||
302 | int trace_fd = rec->session->data->file.fd; | ||
303 | struct record_aio aio = { .rec = rec, .size = 0 }; | ||
304 | |||
305 | /* | ||
306 | * Call record__aio_sync() to wait till map->aio.data[] buffer | ||
307 | * becomes available after previous aio write operation. | ||
308 | */ | ||
309 | |||
310 | idx = record__aio_sync(map, false); | ||
311 | aio.data = map->aio.data[idx]; | ||
312 | ret = perf_mmap__push(map, &aio, record__aio_pushfn); | ||
313 | if (ret != 0) /* ret > 0 - no data, ret < 0 - error */ | ||
314 | return ret; | ||
315 | |||
316 | rec->samples++; | ||
317 | ret = record__aio_write(&(map->aio.cblocks[idx]), trace_fd, aio.data, aio.size, *off); | ||
251 | if (!ret) { | 318 | if (!ret) { |
252 | rec->bytes_written += size; | 319 | *off += aio.size; |
320 | rec->bytes_written += aio.size; | ||
253 | if (switch_output_size(rec)) | 321 | if (switch_output_size(rec)) |
254 | trigger_hit(&switch_output_trigger); | 322 | trigger_hit(&switch_output_trigger); |
323 | } else { | ||
324 | /* | ||
325 | * Decrement map->refcount incremented in record__aio_pushfn() | ||
326 | * back if record__aio_write() operation failed to start, otherwise | ||
327 | * map->refcount is decremented in record__aio_complete() after | ||
328 | * aio write operation finishes successfully. | ||
329 | */ | ||
330 | perf_mmap__put(map); | ||
255 | } | 331 | } |
256 | 332 | ||
257 | return ret; | 333 | return ret; |
@@ -273,7 +349,7 @@ static void record__aio_mmap_read_sync(struct record *rec) | |||
273 | struct perf_evlist *evlist = rec->evlist; | 349 | struct perf_evlist *evlist = rec->evlist; |
274 | struct perf_mmap *maps = evlist->mmap; | 350 | struct perf_mmap *maps = evlist->mmap; |
275 | 351 | ||
276 | if (!rec->opts.nr_cblocks) | 352 | if (!record__aio_enabled(rec)) |
277 | return; | 353 | return; |
278 | 354 | ||
279 | for (i = 0; i < evlist->nr_mmaps; i++) { | 355 | for (i = 0; i < evlist->nr_mmaps; i++) { |
@@ -307,13 +383,8 @@ static int record__aio_parse(const struct option *opt, | |||
307 | #else /* HAVE_AIO_SUPPORT */ | 383 | #else /* HAVE_AIO_SUPPORT */ |
308 | static int nr_cblocks_max = 0; | 384 | static int nr_cblocks_max = 0; |
309 | 385 | ||
310 | static int record__aio_sync(struct perf_mmap *md __maybe_unused, bool sync_all __maybe_unused) | 386 | static int record__aio_push(struct record *rec __maybe_unused, struct perf_mmap *map __maybe_unused, |
311 | { | 387 | off_t *off __maybe_unused) |
312 | return -1; | ||
313 | } | ||
314 | |||
315 | static int record__aio_pushfn(void *to __maybe_unused, struct aiocb *cblock __maybe_unused, | ||
316 | void *bf __maybe_unused, size_t size __maybe_unused, off_t off __maybe_unused) | ||
317 | { | 388 | { |
318 | return -1; | 389 | return -1; |
319 | } | 390 | } |
@@ -372,6 +443,32 @@ static int record__mmap_flush_parse(const struct option *opt, | |||
372 | return 0; | 443 | return 0; |
373 | } | 444 | } |
374 | 445 | ||
446 | #ifdef HAVE_ZSTD_SUPPORT | ||
447 | static unsigned int comp_level_default = 1; | ||
448 | |||
449 | static int record__parse_comp_level(const struct option *opt, const char *str, int unset) | ||
450 | { | ||
451 | struct record_opts *opts = opt->value; | ||
452 | |||
453 | if (unset) { | ||
454 | opts->comp_level = 0; | ||
455 | } else { | ||
456 | if (str) | ||
457 | opts->comp_level = strtol(str, NULL, 0); | ||
458 | if (!opts->comp_level) | ||
459 | opts->comp_level = comp_level_default; | ||
460 | } | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | #endif | ||
465 | static unsigned int comp_level_max = 22; | ||
466 | |||
467 | static int record__comp_enabled(struct record *rec) | ||
468 | { | ||
469 | return rec->opts.comp_level > 0; | ||
470 | } | ||
471 | |||
375 | static int process_synthesized_event(struct perf_tool *tool, | 472 | static int process_synthesized_event(struct perf_tool *tool, |
376 | union perf_event *event, | 473 | union perf_event *event, |
377 | struct perf_sample *sample __maybe_unused, | 474 | struct perf_sample *sample __maybe_unused, |
@@ -385,6 +482,11 @@ static int record__pushfn(struct perf_mmap *map, void *to, void *bf, size_t size | |||
385 | { | 482 | { |
386 | struct record *rec = to; | 483 | struct record *rec = to; |
387 | 484 | ||
485 | if (record__comp_enabled(rec)) { | ||
486 | size = zstd_compress(rec->session, map->data, perf_mmap__mmap_len(map), bf, size); | ||
487 | bf = map->data; | ||
488 | } | ||
489 | |||
388 | rec->samples++; | 490 | rec->samples++; |
389 | return record__write(rec, map, bf, size); | 491 | return record__write(rec, map, bf, size); |
390 | } | 492 | } |
@@ -582,7 +684,7 @@ static int record__mmap_evlist(struct record *rec, | |||
582 | opts->auxtrace_mmap_pages, | 684 | opts->auxtrace_mmap_pages, |
583 | opts->auxtrace_snapshot_mode, | 685 | opts->auxtrace_snapshot_mode, |
584 | opts->nr_cblocks, opts->affinity, | 686 | opts->nr_cblocks, opts->affinity, |
585 | opts->mmap_flush) < 0) { | 687 | opts->mmap_flush, opts->comp_level) < 0) { |
586 | if (errno == EPERM) { | 688 | if (errno == EPERM) { |
587 | pr_err("Permission error mapping pages.\n" | 689 | pr_err("Permission error mapping pages.\n" |
588 | "Consider increasing " | 690 | "Consider increasing " |
@@ -771,6 +873,37 @@ static void record__adjust_affinity(struct record *rec, struct perf_mmap *map) | |||
771 | } | 873 | } |
772 | } | 874 | } |
773 | 875 | ||
876 | static size_t process_comp_header(void *record, size_t increment) | ||
877 | { | ||
878 | struct compressed_event *event = record; | ||
879 | size_t size = sizeof(*event); | ||
880 | |||
881 | if (increment) { | ||
882 | event->header.size += increment; | ||
883 | return increment; | ||
884 | } | ||
885 | |||
886 | event->header.type = PERF_RECORD_COMPRESSED; | ||
887 | event->header.size = size; | ||
888 | |||
889 | return size; | ||
890 | } | ||
891 | |||
892 | static size_t zstd_compress(struct perf_session *session, void *dst, size_t dst_size, | ||
893 | void *src, size_t src_size) | ||
894 | { | ||
895 | size_t compressed; | ||
896 | size_t max_record_size = PERF_SAMPLE_MAX_SIZE - sizeof(struct compressed_event) - 1; | ||
897 | |||
898 | compressed = zstd_compress_stream_to_records(&session->zstd_data, dst, dst_size, src, src_size, | ||
899 | max_record_size, process_comp_header); | ||
900 | |||
901 | session->bytes_transferred += src_size; | ||
902 | session->bytes_compressed += compressed; | ||
903 | |||
904 | return compressed; | ||
905 | } | ||
906 | |||
774 | static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist, | 907 | static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist, |
775 | bool overwrite, bool synch) | 908 | bool overwrite, bool synch) |
776 | { | 909 | { |
@@ -779,7 +912,7 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli | |||
779 | int rc = 0; | 912 | int rc = 0; |
780 | struct perf_mmap *maps; | 913 | struct perf_mmap *maps; |
781 | int trace_fd = rec->data.file.fd; | 914 | int trace_fd = rec->data.file.fd; |
782 | off_t off; | 915 | off_t off = 0; |
783 | 916 | ||
784 | if (!evlist) | 917 | if (!evlist) |
785 | return 0; | 918 | return 0; |
@@ -805,20 +938,14 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli | |||
805 | map->flush = 1; | 938 | map->flush = 1; |
806 | } | 939 | } |
807 | if (!record__aio_enabled(rec)) { | 940 | if (!record__aio_enabled(rec)) { |
808 | if (perf_mmap__push(map, rec, record__pushfn) != 0) { | 941 | if (perf_mmap__push(map, rec, record__pushfn) < 0) { |
809 | if (synch) | 942 | if (synch) |
810 | map->flush = flush; | 943 | map->flush = flush; |
811 | rc = -1; | 944 | rc = -1; |
812 | goto out; | 945 | goto out; |
813 | } | 946 | } |
814 | } else { | 947 | } else { |
815 | int idx; | 948 | if (record__aio_push(rec, map, &off) < 0) { |
816 | /* | ||
817 | * Call record__aio_sync() to wait till map->data buffer | ||
818 | * becomes available after previous aio write request. | ||
819 | */ | ||
820 | idx = record__aio_sync(map, false); | ||
821 | if (perf_mmap__aio_push(map, rec, idx, record__aio_pushfn, &off) != 0) { | ||
822 | record__aio_set_pos(trace_fd, off); | 949 | record__aio_set_pos(trace_fd, off); |
823 | if (synch) | 950 | if (synch) |
824 | map->flush = flush; | 951 | map->flush = flush; |
@@ -888,6 +1015,8 @@ static void record__init_features(struct record *rec) | |||
888 | perf_header__clear_feat(&session->header, HEADER_CLOCKID); | 1015 | perf_header__clear_feat(&session->header, HEADER_CLOCKID); |
889 | 1016 | ||
890 | perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT); | 1017 | perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT); |
1018 | if (!record__comp_enabled(rec)) | ||
1019 | perf_header__clear_feat(&session->header, HEADER_COMPRESSED); | ||
891 | 1020 | ||
892 | perf_header__clear_feat(&session->header, HEADER_STAT); | 1021 | perf_header__clear_feat(&session->header, HEADER_STAT); |
893 | } | 1022 | } |
@@ -1186,6 +1315,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
1186 | bool disabled = false, draining = false; | 1315 | bool disabled = false, draining = false; |
1187 | struct perf_evlist *sb_evlist = NULL; | 1316 | struct perf_evlist *sb_evlist = NULL; |
1188 | int fd; | 1317 | int fd; |
1318 | float ratio = 0; | ||
1189 | 1319 | ||
1190 | atexit(record__sig_exit); | 1320 | atexit(record__sig_exit); |
1191 | signal(SIGCHLD, sig_handler); | 1321 | signal(SIGCHLD, sig_handler); |
@@ -1215,6 +1345,14 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
1215 | fd = perf_data__fd(data); | 1345 | fd = perf_data__fd(data); |
1216 | rec->session = session; | 1346 | rec->session = session; |
1217 | 1347 | ||
1348 | if (zstd_init(&session->zstd_data, rec->opts.comp_level) < 0) { | ||
1349 | pr_err("Compression initialization failed.\n"); | ||
1350 | return -1; | ||
1351 | } | ||
1352 | |||
1353 | session->header.env.comp_type = PERF_COMP_ZSTD; | ||
1354 | session->header.env.comp_level = rec->opts.comp_level; | ||
1355 | |||
1218 | record__init_features(rec); | 1356 | record__init_features(rec); |
1219 | 1357 | ||
1220 | if (rec->opts.use_clockid && rec->opts.clockid_res_ns) | 1358 | if (rec->opts.use_clockid && rec->opts.clockid_res_ns) |
@@ -1244,6 +1382,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
1244 | err = -1; | 1382 | err = -1; |
1245 | goto out_child; | 1383 | goto out_child; |
1246 | } | 1384 | } |
1385 | session->header.env.comp_mmap_len = session->evlist->mmap_len; | ||
1247 | 1386 | ||
1248 | err = bpf__apply_obj_config(); | 1387 | err = bpf__apply_obj_config(); |
1249 | if (err) { | 1388 | if (err) { |
@@ -1491,6 +1630,11 @@ out_child: | |||
1491 | record__mmap_read_all(rec, true); | 1630 | record__mmap_read_all(rec, true); |
1492 | record__aio_mmap_read_sync(rec); | 1631 | record__aio_mmap_read_sync(rec); |
1493 | 1632 | ||
1633 | if (rec->session->bytes_transferred && rec->session->bytes_compressed) { | ||
1634 | ratio = (float)rec->session->bytes_transferred/(float)rec->session->bytes_compressed; | ||
1635 | session->header.env.comp_ratio = ratio + 0.5; | ||
1636 | } | ||
1637 | |||
1494 | if (forks) { | 1638 | if (forks) { |
1495 | int exit_status; | 1639 | int exit_status; |
1496 | 1640 | ||
@@ -1537,12 +1681,19 @@ out_child: | |||
1537 | else | 1681 | else |
1538 | samples[0] = '\0'; | 1682 | samples[0] = '\0'; |
1539 | 1683 | ||
1540 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n", | 1684 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s", |
1541 | perf_data__size(data) / 1024.0 / 1024.0, | 1685 | perf_data__size(data) / 1024.0 / 1024.0, |
1542 | data->path, postfix, samples); | 1686 | data->path, postfix, samples); |
1687 | if (ratio) { | ||
1688 | fprintf(stderr, ", compressed (original %.3f MB, ratio is %.3f)", | ||
1689 | rec->session->bytes_transferred / 1024.0 / 1024.0, | ||
1690 | ratio); | ||
1691 | } | ||
1692 | fprintf(stderr, " ]\n"); | ||
1543 | } | 1693 | } |
1544 | 1694 | ||
1545 | out_delete_session: | 1695 | out_delete_session: |
1696 | zstd_fini(&session->zstd_data); | ||
1546 | perf_session__delete(session); | 1697 | perf_session__delete(session); |
1547 | 1698 | ||
1548 | if (!opts->no_bpf_event) | 1699 | if (!opts->no_bpf_event) |
@@ -2017,10 +2168,10 @@ static struct option __record_options[] = { | |||
2017 | "use per-thread mmaps"), | 2168 | "use per-thread mmaps"), |
2018 | OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register", | 2169 | OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register", |
2019 | "sample selected machine registers on interrupt," | 2170 | "sample selected machine registers on interrupt," |
2020 | " use -I ? to list register names", parse_regs), | 2171 | " use '-I?' to list register names", parse_intr_regs), |
2021 | OPT_CALLBACK_OPTARG(0, "user-regs", &record.opts.sample_user_regs, NULL, "any register", | 2172 | OPT_CALLBACK_OPTARG(0, "user-regs", &record.opts.sample_user_regs, NULL, "any register", |
2022 | "sample selected machine registers on interrupt," | 2173 | "sample selected machine registers on interrupt," |
2023 | " use -I ? to list register names", parse_regs), | 2174 | " use '--user-regs=?' to list register names", parse_user_regs), |
2024 | OPT_BOOLEAN(0, "running-time", &record.opts.running_time, | 2175 | OPT_BOOLEAN(0, "running-time", &record.opts.running_time, |
2025 | "Record running/enabled time of read (:S) events"), | 2176 | "Record running/enabled time of read (:S) events"), |
2026 | OPT_CALLBACK('k', "clockid", &record.opts, | 2177 | OPT_CALLBACK('k', "clockid", &record.opts, |
@@ -2068,6 +2219,11 @@ static struct option __record_options[] = { | |||
2068 | OPT_CALLBACK(0, "affinity", &record.opts, "node|cpu", | 2219 | OPT_CALLBACK(0, "affinity", &record.opts, "node|cpu", |
2069 | "Set affinity mask of trace reading thread to NUMA node cpu mask or cpu of processed mmap buffer", | 2220 | "Set affinity mask of trace reading thread to NUMA node cpu mask or cpu of processed mmap buffer", |
2070 | record__parse_affinity), | 2221 | record__parse_affinity), |
2222 | #ifdef HAVE_ZSTD_SUPPORT | ||
2223 | OPT_CALLBACK_OPTARG('z', "compression-level", &record.opts, &comp_level_default, | ||
2224 | "n", "Compressed records using specified level (default: 1 - fastest compression, 22 - greatest compression)", | ||
2225 | record__parse_comp_level), | ||
2226 | #endif | ||
2071 | OPT_END() | 2227 | OPT_END() |
2072 | }; | 2228 | }; |
2073 | 2229 | ||
@@ -2127,6 +2283,12 @@ int cmd_record(int argc, const char **argv) | |||
2127 | "cgroup monitoring only available in system-wide mode"); | 2283 | "cgroup monitoring only available in system-wide mode"); |
2128 | 2284 | ||
2129 | } | 2285 | } |
2286 | |||
2287 | if (rec->opts.comp_level != 0) { | ||
2288 | pr_debug("Compression enabled, disabling build id collection at the end of the session.\n"); | ||
2289 | rec->no_buildid = true; | ||
2290 | } | ||
2291 | |||
2130 | if (rec->opts.record_switch_events && | 2292 | if (rec->opts.record_switch_events && |
2131 | !perf_can_record_switch_events()) { | 2293 | !perf_can_record_switch_events()) { |
2132 | ui__error("kernel does not support recording context switch events\n"); | 2294 | ui__error("kernel does not support recording context switch events\n"); |
@@ -2272,12 +2434,15 @@ int cmd_record(int argc, const char **argv) | |||
2272 | 2434 | ||
2273 | if (rec->opts.nr_cblocks > nr_cblocks_max) | 2435 | if (rec->opts.nr_cblocks > nr_cblocks_max) |
2274 | rec->opts.nr_cblocks = nr_cblocks_max; | 2436 | rec->opts.nr_cblocks = nr_cblocks_max; |
2275 | if (verbose > 0) | 2437 | pr_debug("nr_cblocks: %d\n", rec->opts.nr_cblocks); |
2276 | pr_info("nr_cblocks: %d\n", rec->opts.nr_cblocks); | ||
2277 | 2438 | ||
2278 | pr_debug("affinity: %s\n", affinity_tags[rec->opts.affinity]); | 2439 | pr_debug("affinity: %s\n", affinity_tags[rec->opts.affinity]); |
2279 | pr_debug("mmap flush: %d\n", rec->opts.mmap_flush); | 2440 | pr_debug("mmap flush: %d\n", rec->opts.mmap_flush); |
2280 | 2441 | ||
2442 | if (rec->opts.comp_level > comp_level_max) | ||
2443 | rec->opts.comp_level = comp_level_max; | ||
2444 | pr_debug("comp level: %d\n", rec->opts.comp_level); | ||
2445 | |||
2281 | err = __cmd_record(&record, argc, argv); | 2446 | err = __cmd_record(&record, argc, argv); |
2282 | out: | 2447 | out: |
2283 | perf_evlist__delete(rec->evlist); | 2448 | perf_evlist__delete(rec->evlist); |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 4054eb1f98ac..1ca533f06a4c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -136,9 +136,6 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, | |||
136 | if (!ui__has_annotation() && !rep->symbol_ipc) | 136 | if (!ui__has_annotation() && !rep->symbol_ipc) |
137 | return 0; | 137 | return 0; |
138 | 138 | ||
139 | hist__account_cycles(sample->branch_stack, al, sample, | ||
140 | rep->nonany_branch_mode); | ||
141 | |||
142 | if (sort__mode == SORT_MODE__BRANCH) { | 139 | if (sort__mode == SORT_MODE__BRANCH) { |
143 | bi = he->branch_info; | 140 | bi = he->branch_info; |
144 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); | 141 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); |
@@ -181,9 +178,6 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, | |||
181 | if (!ui__has_annotation() && !rep->symbol_ipc) | 178 | if (!ui__has_annotation() && !rep->symbol_ipc) |
182 | return 0; | 179 | return 0; |
183 | 180 | ||
184 | hist__account_cycles(sample->branch_stack, al, sample, | ||
185 | rep->nonany_branch_mode); | ||
186 | |||
187 | bi = he->branch_info; | 181 | bi = he->branch_info; |
188 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); | 182 | err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); |
189 | if (err) | 183 | if (err) |
@@ -282,6 +276,11 @@ static int process_sample_event(struct perf_tool *tool, | |||
282 | if (al.map != NULL) | 276 | if (al.map != NULL) |
283 | al.map->dso->hit = 1; | 277 | al.map->dso->hit = 1; |
284 | 278 | ||
279 | if (ui__has_annotation() || rep->symbol_ipc) { | ||
280 | hist__account_cycles(sample->branch_stack, &al, sample, | ||
281 | rep->nonany_branch_mode); | ||
282 | } | ||
283 | |||
285 | ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep); | 284 | ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep); |
286 | if (ret < 0) | 285 | if (ret < 0) |
287 | pr_debug("problem adding hist entry, skipping event\n"); | 286 | pr_debug("problem adding hist entry, skipping event\n"); |
@@ -1259,6 +1258,9 @@ repeat: | |||
1259 | if (session == NULL) | 1258 | if (session == NULL) |
1260 | return -1; | 1259 | return -1; |
1261 | 1260 | ||
1261 | if (zstd_init(&(session->zstd_data), 0) < 0) | ||
1262 | pr_warning("Decompression initialization failed. Reported data may be incomplete.\n"); | ||
1263 | |||
1262 | if (report.queue_size) { | 1264 | if (report.queue_size) { |
1263 | ordered_events__set_alloc_size(&session->ordered_events, | 1265 | ordered_events__set_alloc_size(&session->ordered_events, |
1264 | report.queue_size); | 1266 | report.queue_size); |
@@ -1449,7 +1451,7 @@ repeat: | |||
1449 | error: | 1451 | error: |
1450 | if (report.ptime_range) | 1452 | if (report.ptime_range) |
1451 | zfree(&report.ptime_range); | 1453 | zfree(&report.ptime_range); |
1452 | 1454 | zstd_fini(&(session->zstd_data)); | |
1453 | perf_session__delete(session); | 1455 | perf_session__delete(session); |
1454 | return ret; | 1456 | return ret; |
1455 | } | 1457 | } |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a3c060878faa..24b8e690fb69 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -847,6 +847,18 @@ static int perf_stat__get_core_cached(struct perf_stat_config *config, | |||
847 | return perf_stat__get_aggr(config, perf_stat__get_core, map, idx); | 847 | return perf_stat__get_aggr(config, perf_stat__get_core, map, idx); |
848 | } | 848 | } |
849 | 849 | ||
850 | static bool term_percore_set(void) | ||
851 | { | ||
852 | struct perf_evsel *counter; | ||
853 | |||
854 | evlist__for_each_entry(evsel_list, counter) { | ||
855 | if (counter->percore) | ||
856 | return true; | ||
857 | } | ||
858 | |||
859 | return false; | ||
860 | } | ||
861 | |||
850 | static int perf_stat_init_aggr_mode(void) | 862 | static int perf_stat_init_aggr_mode(void) |
851 | { | 863 | { |
852 | int nr; | 864 | int nr; |
@@ -867,6 +879,15 @@ static int perf_stat_init_aggr_mode(void) | |||
867 | stat_config.aggr_get_id = perf_stat__get_core_cached; | 879 | stat_config.aggr_get_id = perf_stat__get_core_cached; |
868 | break; | 880 | break; |
869 | case AGGR_NONE: | 881 | case AGGR_NONE: |
882 | if (term_percore_set()) { | ||
883 | if (cpu_map__build_core_map(evsel_list->cpus, | ||
884 | &stat_config.aggr_map)) { | ||
885 | perror("cannot build core map"); | ||
886 | return -1; | ||
887 | } | ||
888 | stat_config.aggr_get_id = perf_stat__get_core_cached; | ||
889 | } | ||
890 | break; | ||
870 | case AGGR_GLOBAL: | 891 | case AGGR_GLOBAL: |
871 | case AGGR_THREAD: | 892 | case AGGR_THREAD: |
872 | case AGGR_UNSET: | 893 | case AGGR_UNSET: |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 369eae61068d..d59dee61b64d 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -86,6 +86,7 @@ struct record_opts { | |||
86 | int nr_cblocks; | 86 | int nr_cblocks; |
87 | int affinity; | 87 | int affinity; |
88 | int mmap_flush; | 88 | int mmap_flush; |
89 | unsigned int comp_level; | ||
89 | }; | 90 | }; |
90 | 91 | ||
91 | enum perf_affinity { | 92 | enum perf_affinity { |
diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a57-a72/core-imp-def.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a57-a72/core-imp-def.json new file mode 100644 index 000000000000..0ac9b7927450 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/arm/cortex-a57-a72/core-imp-def.json | |||
@@ -0,0 +1,179 @@ | |||
1 | [ | ||
2 | { | ||
3 | "ArchStdEvent": "L1D_CACHE_RD", | ||
4 | }, | ||
5 | { | ||
6 | "ArchStdEvent": "L1D_CACHE_WR", | ||
7 | }, | ||
8 | { | ||
9 | "ArchStdEvent": "L1D_CACHE_REFILL_RD", | ||
10 | }, | ||
11 | { | ||
12 | "ArchStdEvent": "L1D_CACHE_REFILL_WR", | ||
13 | }, | ||
14 | { | ||
15 | "ArchStdEvent": "L1D_CACHE_WB_VICTIM", | ||
16 | }, | ||
17 | { | ||
18 | "ArchStdEvent": "L1D_CACHE_WB_CLEAN", | ||
19 | }, | ||
20 | { | ||
21 | "ArchStdEvent": "L1D_CACHE_INVAL", | ||
22 | }, | ||
23 | { | ||
24 | "ArchStdEvent": "L1D_TLB_REFILL_RD", | ||
25 | }, | ||
26 | { | ||
27 | "ArchStdEvent": "L1D_TLB_REFILL_WR", | ||
28 | }, | ||
29 | { | ||
30 | "ArchStdEvent": "L2D_CACHE_RD", | ||
31 | }, | ||
32 | { | ||
33 | "ArchStdEvent": "L2D_CACHE_WR", | ||
34 | }, | ||
35 | { | ||
36 | "ArchStdEvent": "L2D_CACHE_REFILL_RD", | ||
37 | }, | ||
38 | { | ||
39 | "ArchStdEvent": "L2D_CACHE_REFILL_WR", | ||
40 | }, | ||
41 | { | ||
42 | "ArchStdEvent": "L2D_CACHE_WB_VICTIM", | ||
43 | }, | ||
44 | { | ||
45 | "ArchStdEvent": "L2D_CACHE_WB_CLEAN", | ||
46 | }, | ||
47 | { | ||
48 | "ArchStdEvent": "L2D_CACHE_INVAL", | ||
49 | }, | ||
50 | { | ||
51 | "ArchStdEvent": "BUS_ACCESS_RD", | ||
52 | }, | ||
53 | { | ||
54 | "ArchStdEvent": "BUS_ACCESS_WR", | ||
55 | }, | ||
56 | { | ||
57 | "ArchStdEvent": "BUS_ACCESS_SHARED", | ||
58 | }, | ||
59 | { | ||
60 | "ArchStdEvent": "BUS_ACCESS_NOT_SHARED", | ||
61 | }, | ||
62 | { | ||
63 | "ArchStdEvent": "BUS_ACCESS_NORMAL", | ||
64 | }, | ||
65 | { | ||
66 | "ArchStdEvent": "BUS_ACCESS_PERIPH", | ||
67 | }, | ||
68 | { | ||
69 | "ArchStdEvent": "MEM_ACCESS_RD", | ||
70 | }, | ||
71 | { | ||
72 | "ArchStdEvent": "MEM_ACCESS_WR", | ||
73 | }, | ||
74 | { | ||
75 | "ArchStdEvent": "UNALIGNED_LD_SPEC", | ||
76 | }, | ||
77 | { | ||
78 | "ArchStdEvent": "UNALIGNED_ST_SPEC", | ||
79 | }, | ||
80 | { | ||
81 | "ArchStdEvent": "UNALIGNED_LDST_SPEC", | ||
82 | }, | ||
83 | { | ||
84 | "ArchStdEvent": "LDREX_SPEC", | ||
85 | }, | ||
86 | { | ||
87 | "ArchStdEvent": "STREX_PASS_SPEC", | ||
88 | }, | ||
89 | { | ||
90 | "ArchStdEvent": "STREX_FAIL_SPEC", | ||
91 | }, | ||
92 | { | ||
93 | "ArchStdEvent": "LD_SPEC", | ||
94 | }, | ||
95 | { | ||
96 | "ArchStdEvent": "ST_SPEC", | ||
97 | }, | ||
98 | { | ||
99 | "ArchStdEvent": "LDST_SPEC", | ||
100 | }, | ||
101 | { | ||
102 | "ArchStdEvent": "DP_SPEC", | ||
103 | }, | ||
104 | { | ||
105 | "ArchStdEvent": "ASE_SPEC", | ||
106 | }, | ||
107 | { | ||
108 | "ArchStdEvent": "VFP_SPEC", | ||
109 | }, | ||
110 | { | ||
111 | "ArchStdEvent": "PC_WRITE_SPEC", | ||
112 | }, | ||
113 | { | ||
114 | "ArchStdEvent": "CRYPTO_SPEC", | ||
115 | }, | ||
116 | { | ||
117 | "ArchStdEvent": "BR_IMMED_SPEC", | ||
118 | }, | ||
119 | { | ||
120 | "ArchStdEvent": "BR_RETURN_SPEC", | ||
121 | }, | ||
122 | { | ||
123 | "ArchStdEvent": "BR_INDIRECT_SPEC", | ||
124 | }, | ||
125 | { | ||
126 | "ArchStdEvent": "ISB_SPEC", | ||
127 | }, | ||
128 | { | ||
129 | "ArchStdEvent": "DSB_SPEC", | ||
130 | }, | ||
131 | { | ||
132 | "ArchStdEvent": "DMB_SPEC", | ||
133 | }, | ||
134 | { | ||
135 | "ArchStdEvent": "EXC_UNDEF", | ||
136 | }, | ||
137 | { | ||
138 | "ArchStdEvent": "EXC_SVC", | ||
139 | }, | ||
140 | { | ||
141 | "ArchStdEvent": "EXC_PABORT", | ||
142 | }, | ||
143 | { | ||
144 | "ArchStdEvent": "EXC_DABORT", | ||
145 | }, | ||
146 | { | ||
147 | "ArchStdEvent": "EXC_IRQ", | ||
148 | }, | ||
149 | { | ||
150 | "ArchStdEvent": "EXC_FIQ", | ||
151 | }, | ||
152 | { | ||
153 | "ArchStdEvent": "EXC_SMC", | ||
154 | }, | ||
155 | { | ||
156 | "ArchStdEvent": "EXC_HVC", | ||
157 | }, | ||
158 | { | ||
159 | "ArchStdEvent": "EXC_TRAP_PABORT", | ||
160 | }, | ||
161 | { | ||
162 | "ArchStdEvent": "EXC_TRAP_DABORT", | ||
163 | }, | ||
164 | { | ||
165 | "ArchStdEvent": "EXC_TRAP_OTHER", | ||
166 | }, | ||
167 | { | ||
168 | "ArchStdEvent": "EXC_TRAP_IRQ", | ||
169 | }, | ||
170 | { | ||
171 | "ArchStdEvent": "EXC_TRAP_FIQ", | ||
172 | }, | ||
173 | { | ||
174 | "ArchStdEvent": "RC_LD_SPEC", | ||
175 | }, | ||
176 | { | ||
177 | "ArchStdEvent": "RC_ST_SPEC", | ||
178 | }, | ||
179 | ] | ||
diff --git a/tools/perf/pmu-events/arch/arm64/mapfile.csv b/tools/perf/pmu-events/arch/arm64/mapfile.csv index 59cd8604b0bd..927fcddcb4aa 100644 --- a/tools/perf/pmu-events/arch/arm64/mapfile.csv +++ b/tools/perf/pmu-events/arch/arm64/mapfile.csv | |||
@@ -12,7 +12,10 @@ | |||
12 | # | 12 | # |
13 | # | 13 | # |
14 | #Family-model,Version,Filename,EventType | 14 | #Family-model,Version,Filename,EventType |
15 | 0x00000000410fd03[[:xdigit:]],v1,arm/cortex-a53,core | 15 | 0x00000000410fd030,v1,arm/cortex-a53,core |
16 | 0x00000000420f1000,v1,arm/cortex-a53,core | ||
17 | 0x00000000410fd070,v1,arm/cortex-a57-a72,core | ||
18 | 0x00000000410fd080,v1,arm/cortex-a57-a72,core | ||
16 | 0x00000000420f5160,v1,cavium/thunderx2,core | 19 | 0x00000000420f5160,v1,cavium/thunderx2,core |
17 | 0x00000000430f0af0,v1,cavium/thunderx2,core | 20 | 0x00000000430f0af0,v1,cavium/thunderx2,core |
18 | 0x00000000480fd010,v1,hisilicon/hip08,core | 21 | 0x00000000480fd010,v1,hisilicon/hip08,core |
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index 68c92bb599ee..58f77fd0f59f 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c | |||
@@ -235,6 +235,7 @@ static struct map { | |||
235 | { "iMPH-U", "uncore_arb" }, | 235 | { "iMPH-U", "uncore_arb" }, |
236 | { "CPU-M-CF", "cpum_cf" }, | 236 | { "CPU-M-CF", "cpum_cf" }, |
237 | { "CPU-M-SF", "cpum_sf" }, | 237 | { "CPU-M-SF", "cpum_sf" }, |
238 | { "UPI LL", "uncore_upi" }, | ||
238 | {} | 239 | {} |
239 | }; | 240 | }; |
240 | 241 | ||
@@ -414,7 +415,6 @@ static int save_arch_std_events(void *data, char *name, char *event, | |||
414 | char *metric_name, char *metric_group) | 415 | char *metric_name, char *metric_group) |
415 | { | 416 | { |
416 | struct event_struct *es; | 417 | struct event_struct *es; |
417 | struct stat *sb = data; | ||
418 | 418 | ||
419 | es = malloc(sizeof(*es)); | 419 | es = malloc(sizeof(*es)); |
420 | if (!es) | 420 | if (!es) |
diff --git a/tools/perf/scripts/python/exported-sql-viewer.py b/tools/perf/scripts/python/exported-sql-viewer.py index 74ef92f1d19a..affed7d149be 100755 --- a/tools/perf/scripts/python/exported-sql-viewer.py +++ b/tools/perf/scripts/python/exported-sql-viewer.py | |||
@@ -456,6 +456,10 @@ class CallGraphLevelItemBase(object): | |||
456 | self.query_done = False; | 456 | self.query_done = False; |
457 | self.child_count = 0 | 457 | self.child_count = 0 |
458 | self.child_items = [] | 458 | self.child_items = [] |
459 | if parent_item: | ||
460 | self.level = parent_item.level + 1 | ||
461 | else: | ||
462 | self.level = 0 | ||
459 | 463 | ||
460 | def getChildItem(self, row): | 464 | def getChildItem(self, row): |
461 | return self.child_items[row] | 465 | return self.child_items[row] |
@@ -877,9 +881,14 @@ class TreeWindowBase(QMdiSubWindow): | |||
877 | super(TreeWindowBase, self).__init__(parent) | 881 | super(TreeWindowBase, self).__init__(parent) |
878 | 882 | ||
879 | self.model = None | 883 | self.model = None |
880 | self.view = None | ||
881 | self.find_bar = None | 884 | self.find_bar = None |
882 | 885 | ||
886 | self.view = QTreeView() | ||
887 | self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) | ||
888 | self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard | ||
889 | |||
890 | self.context_menu = TreeContextMenu(self.view) | ||
891 | |||
883 | def DisplayFound(self, ids): | 892 | def DisplayFound(self, ids): |
884 | if not len(ids): | 893 | if not len(ids): |
885 | return False | 894 | return False |
@@ -921,7 +930,6 @@ class CallGraphWindow(TreeWindowBase): | |||
921 | 930 | ||
922 | self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x)) | 931 | self.model = LookupCreateModel("Context-Sensitive Call Graph", lambda x=glb: CallGraphModel(x)) |
923 | 932 | ||
924 | self.view = QTreeView() | ||
925 | self.view.setModel(self.model) | 933 | self.view.setModel(self.model) |
926 | 934 | ||
927 | for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)): | 935 | for c, w in ((0, 250), (1, 100), (2, 60), (3, 70), (4, 70), (5, 100)): |
@@ -944,7 +952,6 @@ class CallTreeWindow(TreeWindowBase): | |||
944 | 952 | ||
945 | self.model = LookupCreateModel("Call Tree", lambda x=glb: CallTreeModel(x)) | 953 | self.model = LookupCreateModel("Call Tree", lambda x=glb: CallTreeModel(x)) |
946 | 954 | ||
947 | self.view = QTreeView() | ||
948 | self.view.setModel(self.model) | 955 | self.view.setModel(self.model) |
949 | 956 | ||
950 | for c, w in ((0, 230), (1, 100), (2, 100), (3, 70), (4, 70), (5, 100)): | 957 | for c, w in ((0, 230), (1, 100), (2, 100), (3, 70), (4, 70), (5, 100)): |
@@ -1649,10 +1656,14 @@ class BranchWindow(QMdiSubWindow): | |||
1649 | 1656 | ||
1650 | self.view = QTreeView() | 1657 | self.view = QTreeView() |
1651 | self.view.setUniformRowHeights(True) | 1658 | self.view.setUniformRowHeights(True) |
1659 | self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) | ||
1660 | self.view.CopyCellsToClipboard = CopyTreeCellsToClipboard | ||
1652 | self.view.setModel(self.model) | 1661 | self.view.setModel(self.model) |
1653 | 1662 | ||
1654 | self.ResizeColumnsToContents() | 1663 | self.ResizeColumnsToContents() |
1655 | 1664 | ||
1665 | self.context_menu = TreeContextMenu(self.view) | ||
1666 | |||
1656 | self.find_bar = FindBar(self, self, True) | 1667 | self.find_bar = FindBar(self, self, True) |
1657 | 1668 | ||
1658 | self.finder = ChildDataItemFinder(self.model.root) | 1669 | self.finder = ChildDataItemFinder(self.model.root) |
@@ -2261,6 +2272,240 @@ class ResizeColumnsToContentsBase(QObject): | |||
2261 | self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths) | 2272 | self.data_model.rowsInserted.disconnect(self.UpdateColumnWidths) |
2262 | self.ResizeColumnsToContents() | 2273 | self.ResizeColumnsToContents() |
2263 | 2274 | ||
2275 | # Convert value to CSV | ||
2276 | |||
2277 | def ToCSValue(val): | ||
2278 | if '"' in val: | ||
2279 | val = val.replace('"', '""') | ||
2280 | if "," in val or '"' in val: | ||
2281 | val = '"' + val + '"' | ||
2282 | return val | ||
2283 | |||
2284 | # Key to sort table model indexes by row / column, assuming fewer than 1000 columns | ||
2285 | |||
2286 | glb_max_cols = 1000 | ||
2287 | |||
2288 | def RowColumnKey(a): | ||
2289 | return a.row() * glb_max_cols + a.column() | ||
2290 | |||
2291 | # Copy selected table cells to clipboard | ||
2292 | |||
2293 | def CopyTableCellsToClipboard(view, as_csv=False, with_hdr=False): | ||
2294 | indexes = sorted(view.selectedIndexes(), key=RowColumnKey) | ||
2295 | idx_cnt = len(indexes) | ||
2296 | if not idx_cnt: | ||
2297 | return | ||
2298 | if idx_cnt == 1: | ||
2299 | with_hdr=False | ||
2300 | min_row = indexes[0].row() | ||
2301 | max_row = indexes[0].row() | ||
2302 | min_col = indexes[0].column() | ||
2303 | max_col = indexes[0].column() | ||
2304 | for i in indexes: | ||
2305 | min_row = min(min_row, i.row()) | ||
2306 | max_row = max(max_row, i.row()) | ||
2307 | min_col = min(min_col, i.column()) | ||
2308 | max_col = max(max_col, i.column()) | ||
2309 | if max_col > glb_max_cols: | ||
2310 | raise RuntimeError("glb_max_cols is too low") | ||
2311 | max_width = [0] * (1 + max_col - min_col) | ||
2312 | for i in indexes: | ||
2313 | c = i.column() - min_col | ||
2314 | max_width[c] = max(max_width[c], len(str(i.data()))) | ||
2315 | text = "" | ||
2316 | pad = "" | ||
2317 | sep = "" | ||
2318 | if with_hdr: | ||
2319 | model = indexes[0].model() | ||
2320 | for col in range(min_col, max_col + 1): | ||
2321 | val = model.headerData(col, Qt.Horizontal) | ||
2322 | if as_csv: | ||
2323 | text += sep + ToCSValue(val) | ||
2324 | sep = "," | ||
2325 | else: | ||
2326 | c = col - min_col | ||
2327 | max_width[c] = max(max_width[c], len(val)) | ||
2328 | width = max_width[c] | ||
2329 | align = model.headerData(col, Qt.Horizontal, Qt.TextAlignmentRole) | ||
2330 | if align & Qt.AlignRight: | ||
2331 | val = val.rjust(width) | ||
2332 | text += pad + sep + val | ||
2333 | pad = " " * (width - len(val)) | ||
2334 | sep = " " | ||
2335 | text += "\n" | ||
2336 | pad = "" | ||
2337 | sep = "" | ||
2338 | last_row = min_row | ||
2339 | for i in indexes: | ||
2340 | if i.row() > last_row: | ||
2341 | last_row = i.row() | ||
2342 | text += "\n" | ||
2343 | pad = "" | ||
2344 | sep = "" | ||
2345 | if as_csv: | ||
2346 | text += sep + ToCSValue(str(i.data())) | ||
2347 | sep = "," | ||
2348 | else: | ||
2349 | width = max_width[i.column() - min_col] | ||
2350 | if i.data(Qt.TextAlignmentRole) & Qt.AlignRight: | ||
2351 | val = str(i.data()).rjust(width) | ||
2352 | else: | ||
2353 | val = str(i.data()) | ||
2354 | text += pad + sep + val | ||
2355 | pad = " " * (width - len(val)) | ||
2356 | sep = " " | ||
2357 | QApplication.clipboard().setText(text) | ||
2358 | |||
2359 | def CopyTreeCellsToClipboard(view, as_csv=False, with_hdr=False): | ||
2360 | indexes = view.selectedIndexes() | ||
2361 | if not len(indexes): | ||
2362 | return | ||
2363 | |||
2364 | selection = view.selectionModel() | ||
2365 | |||
2366 | first = None | ||
2367 | for i in indexes: | ||
2368 | above = view.indexAbove(i) | ||
2369 | if not selection.isSelected(above): | ||
2370 | first = i | ||
2371 | break | ||
2372 | |||
2373 | if first is None: | ||
2374 | raise RuntimeError("CopyTreeCellsToClipboard internal error") | ||
2375 | |||
2376 | model = first.model() | ||
2377 | row_cnt = 0 | ||
2378 | col_cnt = model.columnCount(first) | ||
2379 | max_width = [0] * col_cnt | ||
2380 | |||
2381 | indent_sz = 2 | ||
2382 | indent_str = " " * indent_sz | ||
2383 | |||
2384 | expanded_mark_sz = 2 | ||
2385 | if sys.version_info[0] == 3: | ||
2386 | expanded_mark = "\u25BC " | ||
2387 | not_expanded_mark = "\u25B6 " | ||
2388 | else: | ||
2389 | expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xBC) + " ", "utf-8") | ||
2390 | not_expanded_mark = unicode(chr(0xE2) + chr(0x96) + chr(0xB6) + " ", "utf-8") | ||
2391 | leaf_mark = " " | ||
2392 | |||
2393 | if not as_csv: | ||
2394 | pos = first | ||
2395 | while True: | ||
2396 | row_cnt += 1 | ||
2397 | row = pos.row() | ||
2398 | for c in range(col_cnt): | ||
2399 | i = pos.sibling(row, c) | ||
2400 | if c: | ||
2401 | n = len(str(i.data())) | ||
2402 | else: | ||
2403 | n = len(str(i.data()).strip()) | ||
2404 | n += (i.internalPointer().level - 1) * indent_sz | ||
2405 | n += expanded_mark_sz | ||
2406 | max_width[c] = max(max_width[c], n) | ||
2407 | pos = view.indexBelow(pos) | ||
2408 | if not selection.isSelected(pos): | ||
2409 | break | ||
2410 | |||
2411 | text = "" | ||
2412 | pad = "" | ||
2413 | sep = "" | ||
2414 | if with_hdr: | ||
2415 | for c in range(col_cnt): | ||
2416 | val = model.headerData(c, Qt.Horizontal, Qt.DisplayRole).strip() | ||
2417 | if as_csv: | ||
2418 | text += sep + ToCSValue(val) | ||
2419 | sep = "," | ||
2420 | else: | ||
2421 | max_width[c] = max(max_width[c], len(val)) | ||
2422 | width = max_width[c] | ||
2423 | align = model.headerData(c, Qt.Horizontal, Qt.TextAlignmentRole) | ||
2424 | if align & Qt.AlignRight: | ||
2425 | val = val.rjust(width) | ||
2426 | text += pad + sep + val | ||
2427 | pad = " " * (width - len(val)) | ||
2428 | sep = " " | ||
2429 | text += "\n" | ||
2430 | pad = "" | ||
2431 | sep = "" | ||
2432 | |||
2433 | pos = first | ||
2434 | while True: | ||
2435 | row = pos.row() | ||
2436 | for c in range(col_cnt): | ||
2437 | i = pos.sibling(row, c) | ||
2438 | val = str(i.data()) | ||
2439 | if not c: | ||
2440 | if model.hasChildren(i): | ||
2441 | if view.isExpanded(i): | ||
2442 | mark = expanded_mark | ||
2443 | else: | ||
2444 | mark = not_expanded_mark | ||
2445 | else: | ||
2446 | mark = leaf_mark | ||
2447 | val = indent_str * (i.internalPointer().level - 1) + mark + val.strip() | ||
2448 | if as_csv: | ||
2449 | text += sep + ToCSValue(val) | ||
2450 | sep = "," | ||
2451 | else: | ||
2452 | width = max_width[c] | ||
2453 | if c and i.data(Qt.TextAlignmentRole) & Qt.AlignRight: | ||
2454 | val = val.rjust(width) | ||
2455 | text += pad + sep + val | ||
2456 | pad = " " * (width - len(val)) | ||
2457 | sep = " " | ||
2458 | pos = view.indexBelow(pos) | ||
2459 | if not selection.isSelected(pos): | ||
2460 | break | ||
2461 | text = text.rstrip() + "\n" | ||
2462 | pad = "" | ||
2463 | sep = "" | ||
2464 | |||
2465 | QApplication.clipboard().setText(text) | ||
2466 | |||
2467 | def CopyCellsToClipboard(view, as_csv=False, with_hdr=False): | ||
2468 | view.CopyCellsToClipboard(view, as_csv, with_hdr) | ||
2469 | |||
2470 | def CopyCellsToClipboardHdr(view): | ||
2471 | CopyCellsToClipboard(view, False, True) | ||
2472 | |||
2473 | def CopyCellsToClipboardCSV(view): | ||
2474 | CopyCellsToClipboard(view, True, True) | ||
2475 | |||
2476 | # Context menu | ||
2477 | |||
2478 | class ContextMenu(object): | ||
2479 | |||
2480 | def __init__(self, view): | ||
2481 | self.view = view | ||
2482 | self.view.setContextMenuPolicy(Qt.CustomContextMenu) | ||
2483 | self.view.customContextMenuRequested.connect(self.ShowContextMenu) | ||
2484 | |||
2485 | def ShowContextMenu(self, pos): | ||
2486 | menu = QMenu(self.view) | ||
2487 | self.AddActions(menu) | ||
2488 | menu.exec_(self.view.mapToGlobal(pos)) | ||
2489 | |||
2490 | def AddCopy(self, menu): | ||
2491 | menu.addAction(CreateAction("&Copy selection", "Copy to clipboard", lambda: CopyCellsToClipboardHdr(self.view), self.view)) | ||
2492 | menu.addAction(CreateAction("Copy selection as CS&V", "Copy to clipboard as CSV", lambda: CopyCellsToClipboardCSV(self.view), self.view)) | ||
2493 | |||
2494 | def AddActions(self, menu): | ||
2495 | self.AddCopy(menu) | ||
2496 | |||
2497 | class TreeContextMenu(ContextMenu): | ||
2498 | |||
2499 | def __init__(self, view): | ||
2500 | super(TreeContextMenu, self).__init__(view) | ||
2501 | |||
2502 | def AddActions(self, menu): | ||
2503 | i = self.view.currentIndex() | ||
2504 | text = str(i.data()).strip() | ||
2505 | if len(text): | ||
2506 | menu.addAction(CreateAction('Copy "' + text + '"', "Copy to clipboard", lambda: QApplication.clipboard().setText(text), self.view)) | ||
2507 | self.AddCopy(menu) | ||
2508 | |||
2264 | # Table window | 2509 | # Table window |
2265 | 2510 | ||
2266 | class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): | 2511 | class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): |
@@ -2279,9 +2524,13 @@ class TableWindow(QMdiSubWindow, ResizeColumnsToContentsBase): | |||
2279 | self.view.verticalHeader().setVisible(False) | 2524 | self.view.verticalHeader().setVisible(False) |
2280 | self.view.sortByColumn(-1, Qt.AscendingOrder) | 2525 | self.view.sortByColumn(-1, Qt.AscendingOrder) |
2281 | self.view.setSortingEnabled(True) | 2526 | self.view.setSortingEnabled(True) |
2527 | self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) | ||
2528 | self.view.CopyCellsToClipboard = CopyTableCellsToClipboard | ||
2282 | 2529 | ||
2283 | self.ResizeColumnsToContents() | 2530 | self.ResizeColumnsToContents() |
2284 | 2531 | ||
2532 | self.context_menu = ContextMenu(self.view) | ||
2533 | |||
2285 | self.find_bar = FindBar(self, self, True) | 2534 | self.find_bar = FindBar(self, self, True) |
2286 | 2535 | ||
2287 | self.finder = ChildDataItemFinder(self.data_model) | 2536 | self.finder = ChildDataItemFinder(self.data_model) |
@@ -2395,6 +2644,10 @@ class TopCallsWindow(QMdiSubWindow, ResizeColumnsToContentsBase): | |||
2395 | self.view.setModel(self.model) | 2644 | self.view.setModel(self.model) |
2396 | self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) | 2645 | self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) |
2397 | self.view.verticalHeader().setVisible(False) | 2646 | self.view.verticalHeader().setVisible(False) |
2647 | self.view.setSelectionMode(QAbstractItemView.ContiguousSelection) | ||
2648 | self.view.CopyCellsToClipboard = CopyTableCellsToClipboard | ||
2649 | |||
2650 | self.context_menu = ContextMenu(self.view) | ||
2398 | 2651 | ||
2399 | self.ResizeColumnsToContents() | 2652 | self.ResizeColumnsToContents() |
2400 | 2653 | ||
@@ -2660,6 +2913,60 @@ class HelpOnlyWindow(QMainWindow): | |||
2660 | 2913 | ||
2661 | self.setCentralWidget(self.text) | 2914 | self.setCentralWidget(self.text) |
2662 | 2915 | ||
2916 | # PostqreSQL server version | ||
2917 | |||
2918 | def PostqreSQLServerVersion(db): | ||
2919 | query = QSqlQuery(db) | ||
2920 | QueryExec(query, "SELECT VERSION()") | ||
2921 | if query.next(): | ||
2922 | v_str = query.value(0) | ||
2923 | v_list = v_str.strip().split(" ") | ||
2924 | if v_list[0] == "PostgreSQL" and v_list[2] == "on": | ||
2925 | return v_list[1] | ||
2926 | return v_str | ||
2927 | return "Unknown" | ||
2928 | |||
2929 | # SQLite version | ||
2930 | |||
2931 | def SQLiteVersion(db): | ||
2932 | query = QSqlQuery(db) | ||
2933 | QueryExec(query, "SELECT sqlite_version()") | ||
2934 | if query.next(): | ||
2935 | return query.value(0) | ||
2936 | return "Unknown" | ||
2937 | |||
2938 | # About dialog | ||
2939 | |||
2940 | class AboutDialog(QDialog): | ||
2941 | |||
2942 | def __init__(self, glb, parent=None): | ||
2943 | super(AboutDialog, self).__init__(parent) | ||
2944 | |||
2945 | self.setWindowTitle("About Exported SQL Viewer") | ||
2946 | self.setMinimumWidth(300) | ||
2947 | |||
2948 | pyside_version = "1" if pyside_version_1 else "2" | ||
2949 | |||
2950 | text = "<pre>" | ||
2951 | text += "Python version: " + sys.version.split(" ")[0] + "\n" | ||
2952 | text += "PySide version: " + pyside_version + "\n" | ||
2953 | text += "Qt version: " + qVersion() + "\n" | ||
2954 | if glb.dbref.is_sqlite3: | ||
2955 | text += "SQLite version: " + SQLiteVersion(glb.db) + "\n" | ||
2956 | else: | ||
2957 | text += "PostqreSQL version: " + PostqreSQLServerVersion(glb.db) + "\n" | ||
2958 | text += "</pre>" | ||
2959 | |||
2960 | self.text = QTextBrowser() | ||
2961 | self.text.setHtml(text) | ||
2962 | self.text.setReadOnly(True) | ||
2963 | self.text.setOpenExternalLinks(True) | ||
2964 | |||
2965 | self.vbox = QVBoxLayout() | ||
2966 | self.vbox.addWidget(self.text) | ||
2967 | |||
2968 | self.setLayout(self.vbox); | ||
2969 | |||
2663 | # Font resize | 2970 | # Font resize |
2664 | 2971 | ||
2665 | def ResizeFont(widget, diff): | 2972 | def ResizeFont(widget, diff): |
@@ -2732,6 +3039,8 @@ class MainWindow(QMainWindow): | |||
2732 | file_menu.addAction(CreateExitAction(glb.app, self)) | 3039 | file_menu.addAction(CreateExitAction(glb.app, self)) |
2733 | 3040 | ||
2734 | edit_menu = menu.addMenu("&Edit") | 3041 | edit_menu = menu.addMenu("&Edit") |
3042 | edit_menu.addAction(CreateAction("&Copy", "Copy to clipboard", self.CopyToClipboard, self, QKeySequence.Copy)) | ||
3043 | edit_menu.addAction(CreateAction("Copy as CS&V", "Copy to clipboard as CSV", self.CopyToClipboardCSV, self)) | ||
2735 | edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find)) | 3044 | edit_menu.addAction(CreateAction("&Find...", "Find items", self.Find, self, QKeySequence.Find)) |
2736 | edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)])) | 3045 | edit_menu.addAction(CreateAction("Fetch &more records...", "Fetch more records", self.FetchMoreRecords, self, [QKeySequence(Qt.Key_F8)])) |
2737 | edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")])) | 3046 | edit_menu.addAction(CreateAction("&Shrink Font", "Make text smaller", self.ShrinkFont, self, [QKeySequence("Ctrl+-")])) |
@@ -2755,6 +3064,21 @@ class MainWindow(QMainWindow): | |||
2755 | 3064 | ||
2756 | help_menu = menu.addMenu("&Help") | 3065 | help_menu = menu.addMenu("&Help") |
2757 | help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents)) | 3066 | help_menu.addAction(CreateAction("&Exported SQL Viewer Help", "Helpful information", self.Help, self, QKeySequence.HelpContents)) |
3067 | help_menu.addAction(CreateAction("&About Exported SQL Viewer", "About this application", self.About, self)) | ||
3068 | |||
3069 | def Try(self, fn): | ||
3070 | win = self.mdi_area.activeSubWindow() | ||
3071 | if win: | ||
3072 | try: | ||
3073 | fn(win.view) | ||
3074 | except: | ||
3075 | pass | ||
3076 | |||
3077 | def CopyToClipboard(self): | ||
3078 | self.Try(CopyCellsToClipboardHdr) | ||
3079 | |||
3080 | def CopyToClipboardCSV(self): | ||
3081 | self.Try(CopyCellsToClipboardCSV) | ||
2758 | 3082 | ||
2759 | def Find(self): | 3083 | def Find(self): |
2760 | win = self.mdi_area.activeSubWindow() | 3084 | win = self.mdi_area.activeSubWindow() |
@@ -2773,12 +3097,10 @@ class MainWindow(QMainWindow): | |||
2773 | pass | 3097 | pass |
2774 | 3098 | ||
2775 | def ShrinkFont(self): | 3099 | def ShrinkFont(self): |
2776 | win = self.mdi_area.activeSubWindow() | 3100 | self.Try(ShrinkFont) |
2777 | ShrinkFont(win.view) | ||
2778 | 3101 | ||
2779 | def EnlargeFont(self): | 3102 | def EnlargeFont(self): |
2780 | win = self.mdi_area.activeSubWindow() | 3103 | self.Try(EnlargeFont) |
2781 | EnlargeFont(win.view) | ||
2782 | 3104 | ||
2783 | def EventMenu(self, events, reports_menu): | 3105 | def EventMenu(self, events, reports_menu): |
2784 | branches_events = 0 | 3106 | branches_events = 0 |
@@ -2828,6 +3150,10 @@ class MainWindow(QMainWindow): | |||
2828 | def Help(self): | 3150 | def Help(self): |
2829 | HelpWindow(self.glb, self) | 3151 | HelpWindow(self.glb, self) |
2830 | 3152 | ||
3153 | def About(self): | ||
3154 | dialog = AboutDialog(self.glb, self) | ||
3155 | dialog.exec_() | ||
3156 | |||
2831 | # XED Disassembler | 3157 | # XED Disassembler |
2832 | 3158 | ||
2833 | class xed_state_t(Structure): | 3159 | class xed_state_t(Structure): |
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 7f6c52021e41..946ab4b63acd 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c | |||
@@ -304,7 +304,7 @@ int test__dso_data_cache(struct test *test __maybe_unused, int subtest __maybe_u | |||
304 | /* Make sure we did not leak any file descriptor. */ | 304 | /* Make sure we did not leak any file descriptor. */ |
305 | nr_end = open_files_cnt(); | 305 | nr_end = open_files_cnt(); |
306 | pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end); | 306 | pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end); |
307 | TEST_ASSERT_VAL("failed leadking files", nr == nr_end); | 307 | TEST_ASSERT_VAL("failed leaking files", nr == nr_end); |
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
@@ -380,6 +380,6 @@ int test__dso_data_reopen(struct test *test __maybe_unused, int subtest __maybe_ | |||
380 | /* Make sure we did not leak any file descriptor. */ | 380 | /* Make sure we did not leak any file descriptor. */ |
381 | nr_end = open_files_cnt(); | 381 | nr_end = open_files_cnt(); |
382 | pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end); | 382 | pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end); |
383 | TEST_ASSERT_VAL("failed leadking files", nr == nr_end); | 383 | TEST_ASSERT_VAL("failed leaking files", nr == nr_end); |
384 | return 0; | 384 | return 0; |
385 | } | 385 | } |
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index e46723568516..5363a12a8b9b 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -107,7 +107,7 @@ make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 | |||
107 | make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 | 107 | make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 |
108 | make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 | 108 | make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 |
109 | make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 | 109 | make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 |
110 | make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 NO_JVMTI=1 | 110 | make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 NO_JVMTI=1 NO_LIBZSTD=1 |
111 | 111 | ||
112 | # $(run) contains all available tests | 112 | # $(run) contains all available tests |
113 | run := make_pure | 113 | run := make_pure |
diff --git a/tools/perf/tests/shell/record+zstd_comp_decomp.sh b/tools/perf/tests/shell/record+zstd_comp_decomp.sh new file mode 100755 index 000000000000..5dcba800109f --- /dev/null +++ b/tools/perf/tests/shell/record+zstd_comp_decomp.sh | |||
@@ -0,0 +1,34 @@ | |||
1 | #!/bin/sh | ||
2 | # Zstd perf.data compression/decompression | ||
3 | |||
4 | trace_file=$(mktemp /tmp/perf.data.XXX) | ||
5 | perf_tool=perf | ||
6 | |||
7 | skip_if_no_z_record() { | ||
8 | $perf_tool record -h 2>&1 | grep -q '\-z, \-\-compression\-level' | ||
9 | } | ||
10 | |||
11 | collect_z_record() { | ||
12 | echo "Collecting compressed record file:" | ||
13 | $perf_tool record -o $trace_file -g -z -F 5000 -- \ | ||
14 | dd count=500 if=/dev/random of=/dev/null | ||
15 | } | ||
16 | |||
17 | check_compressed_stats() { | ||
18 | echo "Checking compressed events stats:" | ||
19 | $perf_tool report -i $trace_file --header --stats | \ | ||
20 | grep -E "(# compressed : Zstd,)|(COMPRESSED events:)" | ||
21 | } | ||
22 | |||
23 | check_compressed_output() { | ||
24 | $perf_tool inject -i $trace_file -o $trace_file.decomp && | ||
25 | $perf_tool report -i $trace_file --stdio | head -n -3 > $trace_file.comp.output && | ||
26 | $perf_tool report -i $trace_file.decomp --stdio | head -n -3 > $trace_file.decomp.output && | ||
27 | diff $trace_file.comp.output $trace_file.decomp.output | ||
28 | } | ||
29 | |||
30 | skip_if_no_z_record || exit 2 | ||
31 | collect_z_record && check_compressed_stats && check_compressed_output | ||
32 | err=$? | ||
33 | rm -f $trace_file* | ||
34 | exit $err | ||
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 8dd3102301ea..6d5bbc8b589b 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -145,6 +145,8 @@ perf-y += scripting-engines/ | |||
145 | 145 | ||
146 | perf-$(CONFIG_ZLIB) += zlib.o | 146 | perf-$(CONFIG_ZLIB) += zlib.o |
147 | perf-$(CONFIG_LZMA) += lzma.o | 147 | perf-$(CONFIG_LZMA) += lzma.o |
148 | perf-$(CONFIG_ZSTD) += zstd.o | ||
149 | |||
148 | perf-y += demangle-java.o | 150 | perf-y += demangle-java.o |
149 | perf-y += demangle-rust.o | 151 | perf-y += demangle-rust.o |
150 | 152 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 09762985c713..0b8573fd9b05 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -1021,7 +1021,7 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 | |||
1021 | float ipc = n_insn / ((double)ch->cycles / (double)ch->num); | 1021 | float ipc = n_insn / ((double)ch->cycles / (double)ch->num); |
1022 | 1022 | ||
1023 | /* Hide data when there are too many overlaps. */ | 1023 | /* Hide data when there are too many overlaps. */ |
1024 | if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2) | 1024 | if (ch->reset >= 0x7fff) |
1025 | return; | 1025 | return; |
1026 | 1026 | ||
1027 | for (offset = start; offset <= end; offset++) { | 1027 | for (offset = start; offset <= end; offset++) { |
diff --git a/tools/perf/util/compress.h b/tools/perf/util/compress.h index 892e92e7e7fc..0cd3369af2a4 100644 --- a/tools/perf/util/compress.h +++ b/tools/perf/util/compress.h | |||
@@ -2,6 +2,11 @@ | |||
2 | #ifndef PERF_COMPRESS_H | 2 | #ifndef PERF_COMPRESS_H |
3 | #define PERF_COMPRESS_H | 3 | #define PERF_COMPRESS_H |
4 | 4 | ||
5 | #include <stdbool.h> | ||
6 | #ifdef HAVE_ZSTD_SUPPORT | ||
7 | #include <zstd.h> | ||
8 | #endif | ||
9 | |||
5 | #ifdef HAVE_ZLIB_SUPPORT | 10 | #ifdef HAVE_ZLIB_SUPPORT |
6 | int gzip_decompress_to_file(const char *input, int output_fd); | 11 | int gzip_decompress_to_file(const char *input, int output_fd); |
7 | bool gzip_is_compressed(const char *input); | 12 | bool gzip_is_compressed(const char *input); |
@@ -12,4 +17,52 @@ int lzma_decompress_to_file(const char *input, int output_fd); | |||
12 | bool lzma_is_compressed(const char *input); | 17 | bool lzma_is_compressed(const char *input); |
13 | #endif | 18 | #endif |
14 | 19 | ||
20 | struct zstd_data { | ||
21 | #ifdef HAVE_ZSTD_SUPPORT | ||
22 | ZSTD_CStream *cstream; | ||
23 | ZSTD_DStream *dstream; | ||
24 | #endif | ||
25 | }; | ||
26 | |||
27 | #ifdef HAVE_ZSTD_SUPPORT | ||
28 | |||
29 | int zstd_init(struct zstd_data *data, int level); | ||
30 | int zstd_fini(struct zstd_data *data); | ||
31 | |||
32 | size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size, | ||
33 | void *src, size_t src_size, size_t max_record_size, | ||
34 | size_t process_header(void *record, size_t increment)); | ||
35 | |||
36 | size_t zstd_decompress_stream(struct zstd_data *data, void *src, size_t src_size, | ||
37 | void *dst, size_t dst_size); | ||
38 | #else /* !HAVE_ZSTD_SUPPORT */ | ||
39 | |||
40 | static inline int zstd_init(struct zstd_data *data __maybe_unused, int level __maybe_unused) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static inline int zstd_fini(struct zstd_data *data __maybe_unused) | ||
46 | { | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static inline | ||
51 | size_t zstd_compress_stream_to_records(struct zstd_data *data __maybe_unused, | ||
52 | void *dst __maybe_unused, size_t dst_size __maybe_unused, | ||
53 | void *src __maybe_unused, size_t src_size __maybe_unused, | ||
54 | size_t max_record_size __maybe_unused, | ||
55 | size_t process_header(void *record, size_t increment) __maybe_unused) | ||
56 | { | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static inline size_t zstd_decompress_stream(struct zstd_data *data __maybe_unused, void *src __maybe_unused, | ||
61 | size_t src_size __maybe_unused, void *dst __maybe_unused, | ||
62 | size_t dst_size __maybe_unused) | ||
63 | { | ||
64 | return 0; | ||
65 | } | ||
66 | #endif | ||
67 | |||
15 | #endif /* PERF_COMPRESS_H */ | 68 | #endif /* PERF_COMPRESS_H */ |
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 4f8e2b485c01..271a90b326c4 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h | |||
@@ -62,6 +62,11 @@ struct perf_env { | |||
62 | struct cpu_topology_map *cpu; | 62 | struct cpu_topology_map *cpu; |
63 | struct cpu_cache_level *caches; | 63 | struct cpu_cache_level *caches; |
64 | int caches_cnt; | 64 | int caches_cnt; |
65 | u32 comp_ratio; | ||
66 | u32 comp_ver; | ||
67 | u32 comp_type; | ||
68 | u32 comp_level; | ||
69 | u32 comp_mmap_len; | ||
65 | struct numa_node *numa_nodes; | 70 | struct numa_node *numa_nodes; |
66 | struct memory_node *memory_nodes; | 71 | struct memory_node *memory_nodes; |
67 | unsigned long long memory_bsize; | 72 | unsigned long long memory_bsize; |
@@ -80,6 +85,12 @@ struct perf_env { | |||
80 | } bpf_progs; | 85 | } bpf_progs; |
81 | }; | 86 | }; |
82 | 87 | ||
88 | enum perf_compress_type { | ||
89 | PERF_COMP_NONE = 0, | ||
90 | PERF_COMP_ZSTD, | ||
91 | PERF_COMP_MAX | ||
92 | }; | ||
93 | |||
83 | struct bpf_prog_info_node; | 94 | struct bpf_prog_info_node; |
84 | struct btf_node; | 95 | struct btf_node; |
85 | 96 | ||
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index ba7be74fad6e..d1ad6c419724 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -68,6 +68,7 @@ static const char *perf_event__names[] = { | |||
68 | [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", | 68 | [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", |
69 | [PERF_RECORD_TIME_CONV] = "TIME_CONV", | 69 | [PERF_RECORD_TIME_CONV] = "TIME_CONV", |
70 | [PERF_RECORD_HEADER_FEATURE] = "FEATURE", | 70 | [PERF_RECORD_HEADER_FEATURE] = "FEATURE", |
71 | [PERF_RECORD_COMPRESSED] = "COMPRESSED", | ||
71 | }; | 72 | }; |
72 | 73 | ||
73 | static const char *perf_ns__names[] = { | 74 | static const char *perf_ns__names[] = { |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 4e908ec1ef64..9e999550f247 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -255,6 +255,7 @@ enum perf_user_event_type { /* above any possible kernel type */ | |||
255 | PERF_RECORD_EVENT_UPDATE = 78, | 255 | PERF_RECORD_EVENT_UPDATE = 78, |
256 | PERF_RECORD_TIME_CONV = 79, | 256 | PERF_RECORD_TIME_CONV = 79, |
257 | PERF_RECORD_HEADER_FEATURE = 80, | 257 | PERF_RECORD_HEADER_FEATURE = 80, |
258 | PERF_RECORD_COMPRESSED = 81, | ||
258 | PERF_RECORD_HEADER_MAX | 259 | PERF_RECORD_HEADER_MAX |
259 | }; | 260 | }; |
260 | 261 | ||
@@ -627,6 +628,11 @@ struct feature_event { | |||
627 | char data[]; | 628 | char data[]; |
628 | }; | 629 | }; |
629 | 630 | ||
631 | struct compressed_event { | ||
632 | struct perf_event_header header; | ||
633 | char data[]; | ||
634 | }; | ||
635 | |||
630 | union perf_event { | 636 | union perf_event { |
631 | struct perf_event_header header; | 637 | struct perf_event_header header; |
632 | struct mmap_event mmap; | 638 | struct mmap_event mmap; |
@@ -660,6 +666,7 @@ union perf_event { | |||
660 | struct feature_event feat; | 666 | struct feature_event feat; |
661 | struct ksymbol_event ksymbol_event; | 667 | struct ksymbol_event ksymbol_event; |
662 | struct bpf_event bpf_event; | 668 | struct bpf_event bpf_event; |
669 | struct compressed_event pack; | ||
663 | }; | 670 | }; |
664 | 671 | ||
665 | void perf_event__print_totals(void); | 672 | void perf_event__print_totals(void); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 4b6783ff5813..69d0fa8ab16f 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -1009,7 +1009,8 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, | |||
1009 | */ | 1009 | */ |
1010 | int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, | 1010 | int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, |
1011 | unsigned int auxtrace_pages, | 1011 | unsigned int auxtrace_pages, |
1012 | bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush) | 1012 | bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush, |
1013 | int comp_level) | ||
1013 | { | 1014 | { |
1014 | struct perf_evsel *evsel; | 1015 | struct perf_evsel *evsel; |
1015 | const struct cpu_map *cpus = evlist->cpus; | 1016 | const struct cpu_map *cpus = evlist->cpus; |
@@ -1019,7 +1020,8 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, | |||
1019 | * Its value is decided by evsel's write_backward. | 1020 | * Its value is decided by evsel's write_backward. |
1020 | * So &mp should not be passed through const pointer. | 1021 | * So &mp should not be passed through const pointer. |
1021 | */ | 1022 | */ |
1022 | struct mmap_params mp = { .nr_cblocks = nr_cblocks, .affinity = affinity, .flush = flush }; | 1023 | struct mmap_params mp = { .nr_cblocks = nr_cblocks, .affinity = affinity, .flush = flush, |
1024 | .comp_level = comp_level }; | ||
1023 | 1025 | ||
1024 | if (!evlist->mmap) | 1026 | if (!evlist->mmap) |
1025 | evlist->mmap = perf_evlist__alloc_mmap(evlist, false); | 1027 | evlist->mmap = perf_evlist__alloc_mmap(evlist, false); |
@@ -1051,7 +1053,7 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, | |||
1051 | 1053 | ||
1052 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages) | 1054 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages) |
1053 | { | 1055 | { |
1054 | return perf_evlist__mmap_ex(evlist, pages, 0, false, 0, PERF_AFFINITY_SYS, 1); | 1056 | return perf_evlist__mmap_ex(evlist, pages, 0, false, 0, PERF_AFFINITY_SYS, 1, 0); |
1055 | } | 1057 | } |
1056 | 1058 | ||
1057 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) | 1059 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index c9a0f72677fd..49354fe24d5f 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -178,7 +178,7 @@ unsigned long perf_event_mlock_kb_in_pages(void); | |||
178 | int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, | 178 | int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, |
179 | unsigned int auxtrace_pages, | 179 | unsigned int auxtrace_pages, |
180 | bool auxtrace_overwrite, int nr_cblocks, | 180 | bool auxtrace_overwrite, int nr_cblocks, |
181 | int affinity, int flush); | 181 | int affinity, int flush, int comp_level); |
182 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages); | 182 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages); |
183 | void perf_evlist__munmap(struct perf_evlist *evlist); | 183 | void perf_evlist__munmap(struct perf_evlist *evlist); |
184 | 184 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a10cf4cde920..a6f572a40deb 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -813,6 +813,8 @@ static void apply_config_terms(struct perf_evsel *evsel, | |||
813 | break; | 813 | break; |
814 | case PERF_EVSEL__CONFIG_TERM_DRV_CFG: | 814 | case PERF_EVSEL__CONFIG_TERM_DRV_CFG: |
815 | break; | 815 | break; |
816 | case PERF_EVSEL__CONFIG_TERM_PERCORE: | ||
817 | break; | ||
816 | default: | 818 | default: |
817 | break; | 819 | break; |
818 | } | 820 | } |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6d190cbf1070..cad54e8ba522 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -50,6 +50,7 @@ enum term_type { | |||
50 | PERF_EVSEL__CONFIG_TERM_OVERWRITE, | 50 | PERF_EVSEL__CONFIG_TERM_OVERWRITE, |
51 | PERF_EVSEL__CONFIG_TERM_DRV_CFG, | 51 | PERF_EVSEL__CONFIG_TERM_DRV_CFG, |
52 | PERF_EVSEL__CONFIG_TERM_BRANCH, | 52 | PERF_EVSEL__CONFIG_TERM_BRANCH, |
53 | PERF_EVSEL__CONFIG_TERM_PERCORE, | ||
53 | }; | 54 | }; |
54 | 55 | ||
55 | struct perf_evsel_config_term { | 56 | struct perf_evsel_config_term { |
@@ -67,6 +68,7 @@ struct perf_evsel_config_term { | |||
67 | bool overwrite; | 68 | bool overwrite; |
68 | char *branch; | 69 | char *branch; |
69 | unsigned long max_events; | 70 | unsigned long max_events; |
71 | bool percore; | ||
70 | } val; | 72 | } val; |
71 | bool weak; | 73 | bool weak; |
72 | }; | 74 | }; |
@@ -158,6 +160,7 @@ struct perf_evsel { | |||
158 | struct perf_evsel **metric_events; | 160 | struct perf_evsel **metric_events; |
159 | bool collect_stat; | 161 | bool collect_stat; |
160 | bool weak_group; | 162 | bool weak_group; |
163 | bool percore; | ||
161 | const char *pmu_name; | 164 | const char *pmu_name; |
162 | struct { | 165 | struct { |
163 | perf_evsel__sb_cb_t *cb; | 166 | perf_evsel__sb_cb_t *cb; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 2d2af2ac2b1e..847ae51a524b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1344,6 +1344,30 @@ out: | |||
1344 | return ret; | 1344 | return ret; |
1345 | } | 1345 | } |
1346 | 1346 | ||
1347 | static int write_compressed(struct feat_fd *ff __maybe_unused, | ||
1348 | struct perf_evlist *evlist __maybe_unused) | ||
1349 | { | ||
1350 | int ret; | ||
1351 | |||
1352 | ret = do_write(ff, &(ff->ph->env.comp_ver), sizeof(ff->ph->env.comp_ver)); | ||
1353 | if (ret) | ||
1354 | return ret; | ||
1355 | |||
1356 | ret = do_write(ff, &(ff->ph->env.comp_type), sizeof(ff->ph->env.comp_type)); | ||
1357 | if (ret) | ||
1358 | return ret; | ||
1359 | |||
1360 | ret = do_write(ff, &(ff->ph->env.comp_level), sizeof(ff->ph->env.comp_level)); | ||
1361 | if (ret) | ||
1362 | return ret; | ||
1363 | |||
1364 | ret = do_write(ff, &(ff->ph->env.comp_ratio), sizeof(ff->ph->env.comp_ratio)); | ||
1365 | if (ret) | ||
1366 | return ret; | ||
1367 | |||
1368 | return do_write(ff, &(ff->ph->env.comp_mmap_len), sizeof(ff->ph->env.comp_mmap_len)); | ||
1369 | } | ||
1370 | |||
1347 | static void print_hostname(struct feat_fd *ff, FILE *fp) | 1371 | static void print_hostname(struct feat_fd *ff, FILE *fp) |
1348 | { | 1372 | { |
1349 | fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname); | 1373 | fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname); |
@@ -1688,6 +1712,13 @@ static void print_cache(struct feat_fd *ff, FILE *fp __maybe_unused) | |||
1688 | } | 1712 | } |
1689 | } | 1713 | } |
1690 | 1714 | ||
1715 | static void print_compressed(struct feat_fd *ff, FILE *fp) | ||
1716 | { | ||
1717 | fprintf(fp, "# compressed : %s, level = %d, ratio = %d\n", | ||
1718 | ff->ph->env.comp_type == PERF_COMP_ZSTD ? "Zstd" : "Unknown", | ||
1719 | ff->ph->env.comp_level, ff->ph->env.comp_ratio); | ||
1720 | } | ||
1721 | |||
1691 | static void print_pmu_mappings(struct feat_fd *ff, FILE *fp) | 1722 | static void print_pmu_mappings(struct feat_fd *ff, FILE *fp) |
1692 | { | 1723 | { |
1693 | const char *delimiter = "# pmu mappings: "; | 1724 | const char *delimiter = "# pmu mappings: "; |
@@ -2667,6 +2698,27 @@ out: | |||
2667 | return err; | 2698 | return err; |
2668 | } | 2699 | } |
2669 | 2700 | ||
2701 | static int process_compressed(struct feat_fd *ff, | ||
2702 | void *data __maybe_unused) | ||
2703 | { | ||
2704 | if (do_read_u32(ff, &(ff->ph->env.comp_ver))) | ||
2705 | return -1; | ||
2706 | |||
2707 | if (do_read_u32(ff, &(ff->ph->env.comp_type))) | ||
2708 | return -1; | ||
2709 | |||
2710 | if (do_read_u32(ff, &(ff->ph->env.comp_level))) | ||
2711 | return -1; | ||
2712 | |||
2713 | if (do_read_u32(ff, &(ff->ph->env.comp_ratio))) | ||
2714 | return -1; | ||
2715 | |||
2716 | if (do_read_u32(ff, &(ff->ph->env.comp_mmap_len))) | ||
2717 | return -1; | ||
2718 | |||
2719 | return 0; | ||
2720 | } | ||
2721 | |||
2670 | struct feature_ops { | 2722 | struct feature_ops { |
2671 | int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); | 2723 | int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); |
2672 | void (*print)(struct feat_fd *ff, FILE *fp); | 2724 | void (*print)(struct feat_fd *ff, FILE *fp); |
@@ -2730,6 +2782,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { | |||
2730 | FEAT_OPN(DIR_FORMAT, dir_format, false), | 2782 | FEAT_OPN(DIR_FORMAT, dir_format, false), |
2731 | FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false), | 2783 | FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false), |
2732 | FEAT_OPR(BPF_BTF, bpf_btf, false), | 2784 | FEAT_OPR(BPF_BTF, bpf_btf, false), |
2785 | FEAT_OPR(COMPRESSED, compressed, false), | ||
2733 | }; | 2786 | }; |
2734 | 2787 | ||
2735 | struct header_print_data { | 2788 | struct header_print_data { |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 386da49e1bfa..5b3abe4172e2 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -42,6 +42,7 @@ enum { | |||
42 | HEADER_DIR_FORMAT, | 42 | HEADER_DIR_FORMAT, |
43 | HEADER_BPF_PROG_INFO, | 43 | HEADER_BPF_PROG_INFO, |
44 | HEADER_BPF_BTF, | 44 | HEADER_BPF_BTF, |
45 | HEADER_COMPRESSED, | ||
45 | HEADER_LAST_FEATURE, | 46 | HEADER_LAST_FEATURE, |
46 | HEADER_FEAT_BITS = 256, | 47 | HEADER_FEAT_BITS = 256, |
47 | }; | 48 | }; |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 872fab163585..f4c3c84b090f 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | |||
@@ -58,6 +58,7 @@ enum intel_pt_pkt_state { | |||
58 | INTEL_PT_STATE_NO_IP, | 58 | INTEL_PT_STATE_NO_IP, |
59 | INTEL_PT_STATE_ERR_RESYNC, | 59 | INTEL_PT_STATE_ERR_RESYNC, |
60 | INTEL_PT_STATE_IN_SYNC, | 60 | INTEL_PT_STATE_IN_SYNC, |
61 | INTEL_PT_STATE_TNT_CONT, | ||
61 | INTEL_PT_STATE_TNT, | 62 | INTEL_PT_STATE_TNT, |
62 | INTEL_PT_STATE_TIP, | 63 | INTEL_PT_STATE_TIP, |
63 | INTEL_PT_STATE_TIP_PGD, | 64 | INTEL_PT_STATE_TIP_PGD, |
@@ -72,8 +73,9 @@ static inline bool intel_pt_sample_time(enum intel_pt_pkt_state pkt_state) | |||
72 | case INTEL_PT_STATE_NO_IP: | 73 | case INTEL_PT_STATE_NO_IP: |
73 | case INTEL_PT_STATE_ERR_RESYNC: | 74 | case INTEL_PT_STATE_ERR_RESYNC: |
74 | case INTEL_PT_STATE_IN_SYNC: | 75 | case INTEL_PT_STATE_IN_SYNC: |
75 | case INTEL_PT_STATE_TNT: | 76 | case INTEL_PT_STATE_TNT_CONT: |
76 | return true; | 77 | return true; |
78 | case INTEL_PT_STATE_TNT: | ||
77 | case INTEL_PT_STATE_TIP: | 79 | case INTEL_PT_STATE_TIP: |
78 | case INTEL_PT_STATE_TIP_PGD: | 80 | case INTEL_PT_STATE_TIP_PGD: |
79 | case INTEL_PT_STATE_FUP: | 81 | case INTEL_PT_STATE_FUP: |
@@ -888,16 +890,20 @@ static uint64_t intel_pt_next_period(struct intel_pt_decoder *decoder) | |||
888 | timestamp = decoder->timestamp + decoder->timestamp_insn_cnt; | 890 | timestamp = decoder->timestamp + decoder->timestamp_insn_cnt; |
889 | masked_timestamp = timestamp & decoder->period_mask; | 891 | masked_timestamp = timestamp & decoder->period_mask; |
890 | if (decoder->continuous_period) { | 892 | if (decoder->continuous_period) { |
891 | if (masked_timestamp != decoder->last_masked_timestamp) | 893 | if (masked_timestamp > decoder->last_masked_timestamp) |
892 | return 1; | 894 | return 1; |
893 | } else { | 895 | } else { |
894 | timestamp += 1; | 896 | timestamp += 1; |
895 | masked_timestamp = timestamp & decoder->period_mask; | 897 | masked_timestamp = timestamp & decoder->period_mask; |
896 | if (masked_timestamp != decoder->last_masked_timestamp) { | 898 | if (masked_timestamp > decoder->last_masked_timestamp) { |
897 | decoder->last_masked_timestamp = masked_timestamp; | 899 | decoder->last_masked_timestamp = masked_timestamp; |
898 | decoder->continuous_period = true; | 900 | decoder->continuous_period = true; |
899 | } | 901 | } |
900 | } | 902 | } |
903 | |||
904 | if (masked_timestamp < decoder->last_masked_timestamp) | ||
905 | return decoder->period_ticks; | ||
906 | |||
901 | return decoder->period_ticks - (timestamp - masked_timestamp); | 907 | return decoder->period_ticks - (timestamp - masked_timestamp); |
902 | } | 908 | } |
903 | 909 | ||
@@ -926,7 +932,10 @@ static void intel_pt_sample_insn(struct intel_pt_decoder *decoder) | |||
926 | case INTEL_PT_PERIOD_TICKS: | 932 | case INTEL_PT_PERIOD_TICKS: |
927 | timestamp = decoder->timestamp + decoder->timestamp_insn_cnt; | 933 | timestamp = decoder->timestamp + decoder->timestamp_insn_cnt; |
928 | masked_timestamp = timestamp & decoder->period_mask; | 934 | masked_timestamp = timestamp & decoder->period_mask; |
929 | decoder->last_masked_timestamp = masked_timestamp; | 935 | if (masked_timestamp > decoder->last_masked_timestamp) |
936 | decoder->last_masked_timestamp = masked_timestamp; | ||
937 | else | ||
938 | decoder->last_masked_timestamp += decoder->period_ticks; | ||
930 | break; | 939 | break; |
931 | case INTEL_PT_PERIOD_NONE: | 940 | case INTEL_PT_PERIOD_NONE: |
932 | case INTEL_PT_PERIOD_MTC: | 941 | case INTEL_PT_PERIOD_MTC: |
@@ -1254,7 +1263,9 @@ static int intel_pt_walk_tnt(struct intel_pt_decoder *decoder) | |||
1254 | return -ENOENT; | 1263 | return -ENOENT; |
1255 | } | 1264 | } |
1256 | decoder->tnt.count -= 1; | 1265 | decoder->tnt.count -= 1; |
1257 | if (!decoder->tnt.count) | 1266 | if (decoder->tnt.count) |
1267 | decoder->pkt_state = INTEL_PT_STATE_TNT_CONT; | ||
1268 | else | ||
1258 | decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; | 1269 | decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; |
1259 | decoder->tnt.payload <<= 1; | 1270 | decoder->tnt.payload <<= 1; |
1260 | decoder->state.from_ip = decoder->ip; | 1271 | decoder->state.from_ip = decoder->ip; |
@@ -1285,7 +1296,9 @@ static int intel_pt_walk_tnt(struct intel_pt_decoder *decoder) | |||
1285 | 1296 | ||
1286 | if (intel_pt_insn.branch == INTEL_PT_BR_CONDITIONAL) { | 1297 | if (intel_pt_insn.branch == INTEL_PT_BR_CONDITIONAL) { |
1287 | decoder->tnt.count -= 1; | 1298 | decoder->tnt.count -= 1; |
1288 | if (!decoder->tnt.count) | 1299 | if (decoder->tnt.count) |
1300 | decoder->pkt_state = INTEL_PT_STATE_TNT_CONT; | ||
1301 | else | ||
1289 | decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; | 1302 | decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; |
1290 | if (decoder->tnt.payload & BIT63) { | 1303 | if (decoder->tnt.payload & BIT63) { |
1291 | decoder->tnt.payload <<= 1; | 1304 | decoder->tnt.payload <<= 1; |
@@ -1305,8 +1318,11 @@ static int intel_pt_walk_tnt(struct intel_pt_decoder *decoder) | |||
1305 | return 0; | 1318 | return 0; |
1306 | } | 1319 | } |
1307 | decoder->ip += intel_pt_insn.length; | 1320 | decoder->ip += intel_pt_insn.length; |
1308 | if (!decoder->tnt.count) | 1321 | if (!decoder->tnt.count) { |
1322 | decoder->sample_timestamp = decoder->timestamp; | ||
1323 | decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; | ||
1309 | return -EAGAIN; | 1324 | return -EAGAIN; |
1325 | } | ||
1310 | decoder->tnt.payload <<= 1; | 1326 | decoder->tnt.payload <<= 1; |
1311 | continue; | 1327 | continue; |
1312 | } | 1328 | } |
@@ -2365,6 +2381,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) | |||
2365 | err = intel_pt_walk_trace(decoder); | 2381 | err = intel_pt_walk_trace(decoder); |
2366 | break; | 2382 | break; |
2367 | case INTEL_PT_STATE_TNT: | 2383 | case INTEL_PT_STATE_TNT: |
2384 | case INTEL_PT_STATE_TNT_CONT: | ||
2368 | err = intel_pt_walk_tnt(decoder); | 2385 | err = intel_pt_walk_tnt(decoder); |
2369 | if (err == -EAGAIN) | 2386 | if (err == -EAGAIN) |
2370 | err = intel_pt_walk_trace(decoder); | 2387 | err = intel_pt_walk_trace(decoder); |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 3c520baa198c..28a9541c4835 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -1234,8 +1234,9 @@ static char *get_kernel_version(const char *root_dir) | |||
1234 | if (!file) | 1234 | if (!file) |
1235 | return NULL; | 1235 | return NULL; |
1236 | 1236 | ||
1237 | version[0] = '\0'; | ||
1238 | tmp = fgets(version, sizeof(version), file); | 1237 | tmp = fgets(version, sizeof(version), file); |
1238 | if (!tmp) | ||
1239 | *version = '\0'; | ||
1239 | fclose(file); | 1240 | fclose(file); |
1240 | 1241 | ||
1241 | name = strstr(version, prefix); | 1242 | name = strstr(version, prefix); |
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index ef3d79b2c90b..868c0b0e909c 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c | |||
@@ -157,6 +157,10 @@ void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __mayb | |||
157 | } | 157 | } |
158 | 158 | ||
159 | #ifdef HAVE_AIO_SUPPORT | 159 | #ifdef HAVE_AIO_SUPPORT |
160 | static int perf_mmap__aio_enabled(struct perf_mmap *map) | ||
161 | { | ||
162 | return map->aio.nr_cblocks > 0; | ||
163 | } | ||
160 | 164 | ||
161 | #ifdef HAVE_LIBNUMA_SUPPORT | 165 | #ifdef HAVE_LIBNUMA_SUPPORT |
162 | static int perf_mmap__aio_alloc(struct perf_mmap *map, int idx) | 166 | static int perf_mmap__aio_alloc(struct perf_mmap *map, int idx) |
@@ -198,7 +202,7 @@ static int perf_mmap__aio_bind(struct perf_mmap *map, int idx, int cpu, int affi | |||
198 | 202 | ||
199 | return 0; | 203 | return 0; |
200 | } | 204 | } |
201 | #else | 205 | #else /* !HAVE_LIBNUMA_SUPPORT */ |
202 | static int perf_mmap__aio_alloc(struct perf_mmap *map, int idx) | 206 | static int perf_mmap__aio_alloc(struct perf_mmap *map, int idx) |
203 | { | 207 | { |
204 | map->aio.data[idx] = malloc(perf_mmap__mmap_len(map)); | 208 | map->aio.data[idx] = malloc(perf_mmap__mmap_len(map)); |
@@ -285,81 +289,12 @@ static void perf_mmap__aio_munmap(struct perf_mmap *map) | |||
285 | zfree(&map->aio.cblocks); | 289 | zfree(&map->aio.cblocks); |
286 | zfree(&map->aio.aiocb); | 290 | zfree(&map->aio.aiocb); |
287 | } | 291 | } |
288 | 292 | #else /* !HAVE_AIO_SUPPORT */ | |
289 | int perf_mmap__aio_push(struct perf_mmap *md, void *to, int idx, | 293 | static int perf_mmap__aio_enabled(struct perf_mmap *map __maybe_unused) |
290 | int push(void *to, struct aiocb *cblock, void *buf, size_t size, off_t off), | ||
291 | off_t *off) | ||
292 | { | 294 | { |
293 | u64 head = perf_mmap__read_head(md); | 295 | return 0; |
294 | unsigned char *data = md->base + page_size; | ||
295 | unsigned long size, size0 = 0; | ||
296 | void *buf; | ||
297 | int rc = 0; | ||
298 | |||
299 | rc = perf_mmap__read_init(md); | ||
300 | if (rc < 0) | ||
301 | return (rc == -EAGAIN) ? 0 : -1; | ||
302 | |||
303 | /* | ||
304 | * md->base data is copied into md->data[idx] buffer to | ||
305 | * release space in the kernel buffer as fast as possible, | ||
306 | * thru perf_mmap__consume() below. | ||
307 | * | ||
308 | * That lets the kernel to proceed with storing more | ||
309 | * profiling data into the kernel buffer earlier than other | ||
310 | * per-cpu kernel buffers are handled. | ||
311 | * | ||
312 | * Coping can be done in two steps in case the chunk of | ||
313 | * profiling data crosses the upper bound of the kernel buffer. | ||
314 | * In this case we first move part of data from md->start | ||
315 | * till the upper bound and then the reminder from the | ||
316 | * beginning of the kernel buffer till the end of | ||
317 | * the data chunk. | ||
318 | */ | ||
319 | |||
320 | size = md->end - md->start; | ||
321 | |||
322 | if ((md->start & md->mask) + size != (md->end & md->mask)) { | ||
323 | buf = &data[md->start & md->mask]; | ||
324 | size = md->mask + 1 - (md->start & md->mask); | ||
325 | md->start += size; | ||
326 | memcpy(md->aio.data[idx], buf, size); | ||
327 | size0 = size; | ||
328 | } | ||
329 | |||
330 | buf = &data[md->start & md->mask]; | ||
331 | size = md->end - md->start; | ||
332 | md->start += size; | ||
333 | memcpy(md->aio.data[idx] + size0, buf, size); | ||
334 | |||
335 | /* | ||
336 | * Increment md->refcount to guard md->data[idx] buffer | ||
337 | * from premature deallocation because md object can be | ||
338 | * released earlier than aio write request started | ||
339 | * on mmap->data[idx] is complete. | ||
340 | * | ||
341 | * perf_mmap__put() is done at record__aio_complete() | ||
342 | * after started request completion. | ||
343 | */ | ||
344 | perf_mmap__get(md); | ||
345 | |||
346 | md->prev = head; | ||
347 | perf_mmap__consume(md); | ||
348 | |||
349 | rc = push(to, &md->aio.cblocks[idx], md->aio.data[idx], size0 + size, *off); | ||
350 | if (!rc) { | ||
351 | *off += size0 + size; | ||
352 | } else { | ||
353 | /* | ||
354 | * Decrement md->refcount back if aio write | ||
355 | * operation failed to start. | ||
356 | */ | ||
357 | perf_mmap__put(md); | ||
358 | } | ||
359 | |||
360 | return rc; | ||
361 | } | 296 | } |
362 | #else | 297 | |
363 | static int perf_mmap__aio_mmap(struct perf_mmap *map __maybe_unused, | 298 | static int perf_mmap__aio_mmap(struct perf_mmap *map __maybe_unused, |
364 | struct mmap_params *mp __maybe_unused) | 299 | struct mmap_params *mp __maybe_unused) |
365 | { | 300 | { |
@@ -374,6 +309,10 @@ static void perf_mmap__aio_munmap(struct perf_mmap *map __maybe_unused) | |||
374 | void perf_mmap__munmap(struct perf_mmap *map) | 309 | void perf_mmap__munmap(struct perf_mmap *map) |
375 | { | 310 | { |
376 | perf_mmap__aio_munmap(map); | 311 | perf_mmap__aio_munmap(map); |
312 | if (map->data != NULL) { | ||
313 | munmap(map->data, perf_mmap__mmap_len(map)); | ||
314 | map->data = NULL; | ||
315 | } | ||
377 | if (map->base != NULL) { | 316 | if (map->base != NULL) { |
378 | munmap(map->base, perf_mmap__mmap_len(map)); | 317 | munmap(map->base, perf_mmap__mmap_len(map)); |
379 | map->base = NULL; | 318 | map->base = NULL; |
@@ -442,6 +381,19 @@ int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int c | |||
442 | 381 | ||
443 | map->flush = mp->flush; | 382 | map->flush = mp->flush; |
444 | 383 | ||
384 | map->comp_level = mp->comp_level; | ||
385 | |||
386 | if (map->comp_level && !perf_mmap__aio_enabled(map)) { | ||
387 | map->data = mmap(NULL, perf_mmap__mmap_len(map), PROT_READ|PROT_WRITE, | ||
388 | MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); | ||
389 | if (map->data == MAP_FAILED) { | ||
390 | pr_debug2("failed to mmap data buffer, error %d\n", | ||
391 | errno); | ||
392 | map->data = NULL; | ||
393 | return -1; | ||
394 | } | ||
395 | } | ||
396 | |||
445 | if (auxtrace_mmap__mmap(&map->auxtrace_mmap, | 397 | if (auxtrace_mmap__mmap(&map->auxtrace_mmap, |
446 | &mp->auxtrace_mp, map->base, fd)) | 398 | &mp->auxtrace_mp, map->base, fd)) |
447 | return -1; | 399 | return -1; |
@@ -540,7 +492,7 @@ int perf_mmap__push(struct perf_mmap *md, void *to, | |||
540 | 492 | ||
541 | rc = perf_mmap__read_init(md); | 493 | rc = perf_mmap__read_init(md); |
542 | if (rc < 0) | 494 | if (rc < 0) |
543 | return (rc == -EAGAIN) ? 0 : -1; | 495 | return (rc == -EAGAIN) ? 1 : -1; |
544 | 496 | ||
545 | size = md->end - md->start; | 497 | size = md->end - md->start; |
546 | 498 | ||
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index b82f8c2d55c4..274ce389cd84 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h | |||
@@ -40,6 +40,8 @@ struct perf_mmap { | |||
40 | #endif | 40 | #endif |
41 | cpu_set_t affinity_mask; | 41 | cpu_set_t affinity_mask; |
42 | u64 flush; | 42 | u64 flush; |
43 | void *data; | ||
44 | int comp_level; | ||
43 | }; | 45 | }; |
44 | 46 | ||
45 | /* | 47 | /* |
@@ -71,7 +73,7 @@ enum bkw_mmap_state { | |||
71 | }; | 73 | }; |
72 | 74 | ||
73 | struct mmap_params { | 75 | struct mmap_params { |
74 | int prot, mask, nr_cblocks, affinity, flush; | 76 | int prot, mask, nr_cblocks, affinity, flush, comp_level; |
75 | struct auxtrace_mmap_params auxtrace_mp; | 77 | struct auxtrace_mmap_params auxtrace_mp; |
76 | }; | 78 | }; |
77 | 79 | ||
@@ -99,18 +101,6 @@ union perf_event *perf_mmap__read_event(struct perf_mmap *map); | |||
99 | 101 | ||
100 | int perf_mmap__push(struct perf_mmap *md, void *to, | 102 | int perf_mmap__push(struct perf_mmap *md, void *to, |
101 | int push(struct perf_mmap *map, void *to, void *buf, size_t size)); | 103 | int push(struct perf_mmap *map, void *to, void *buf, size_t size)); |
102 | #ifdef HAVE_AIO_SUPPORT | ||
103 | int perf_mmap__aio_push(struct perf_mmap *md, void *to, int idx, | ||
104 | int push(void *to, struct aiocb *cblock, void *buf, size_t size, off_t off), | ||
105 | off_t *off); | ||
106 | #else | ||
107 | static inline int perf_mmap__aio_push(struct perf_mmap *md __maybe_unused, void *to __maybe_unused, int idx __maybe_unused, | ||
108 | int push(void *to, struct aiocb *cblock, void *buf, size_t size, off_t off) __maybe_unused, | ||
109 | off_t *off __maybe_unused) | ||
110 | { | ||
111 | return 0; | ||
112 | } | ||
113 | #endif | ||
114 | 104 | ||
115 | size_t perf_mmap__mmap_len(struct perf_mmap *map); | 105 | size_t perf_mmap__mmap_len(struct perf_mmap *map); |
116 | 106 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4432bfe039fd..cf0b9b81c5aa 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -950,6 +950,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { | |||
950 | [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", | 950 | [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", |
951 | [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", | 951 | [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", |
952 | [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", | 952 | [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", |
953 | [PARSE_EVENTS__TERM_TYPE_PERCORE] = "percore", | ||
953 | }; | 954 | }; |
954 | 955 | ||
955 | static bool config_term_shrinked; | 956 | static bool config_term_shrinked; |
@@ -970,6 +971,7 @@ config_term_avail(int term_type, struct parse_events_error *err) | |||
970 | case PARSE_EVENTS__TERM_TYPE_CONFIG2: | 971 | case PARSE_EVENTS__TERM_TYPE_CONFIG2: |
971 | case PARSE_EVENTS__TERM_TYPE_NAME: | 972 | case PARSE_EVENTS__TERM_TYPE_NAME: |
972 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: | 973 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: |
974 | case PARSE_EVENTS__TERM_TYPE_PERCORE: | ||
973 | return true; | 975 | return true; |
974 | default: | 976 | default: |
975 | if (!err) | 977 | if (!err) |
@@ -1061,6 +1063,14 @@ do { \ | |||
1061 | case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: | 1063 | case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: |
1062 | CHECK_TYPE_VAL(NUM); | 1064 | CHECK_TYPE_VAL(NUM); |
1063 | break; | 1065 | break; |
1066 | case PARSE_EVENTS__TERM_TYPE_PERCORE: | ||
1067 | CHECK_TYPE_VAL(NUM); | ||
1068 | if ((unsigned int)term->val.num > 1) { | ||
1069 | err->str = strdup("expected 0 or 1"); | ||
1070 | err->idx = term->err_val; | ||
1071 | return -EINVAL; | ||
1072 | } | ||
1073 | break; | ||
1064 | default: | 1074 | default: |
1065 | err->str = strdup("unknown term"); | 1075 | err->str = strdup("unknown term"); |
1066 | err->idx = term->err_term; | 1076 | err->idx = term->err_term; |
@@ -1199,6 +1209,10 @@ do { \ | |||
1199 | case PARSE_EVENTS__TERM_TYPE_DRV_CFG: | 1209 | case PARSE_EVENTS__TERM_TYPE_DRV_CFG: |
1200 | ADD_CONFIG_TERM(DRV_CFG, drv_cfg, term->val.str); | 1210 | ADD_CONFIG_TERM(DRV_CFG, drv_cfg, term->val.str); |
1201 | break; | 1211 | break; |
1212 | case PARSE_EVENTS__TERM_TYPE_PERCORE: | ||
1213 | ADD_CONFIG_TERM(PERCORE, percore, | ||
1214 | term->val.num ? true : false); | ||
1215 | break; | ||
1202 | default: | 1216 | default: |
1203 | break; | 1217 | break; |
1204 | } | 1218 | } |
@@ -1260,6 +1274,18 @@ int parse_events_add_tool(struct parse_events_state *parse_state, | |||
1260 | return add_event_tool(list, &parse_state->idx, tool_event); | 1274 | return add_event_tool(list, &parse_state->idx, tool_event); |
1261 | } | 1275 | } |
1262 | 1276 | ||
1277 | static bool config_term_percore(struct list_head *config_terms) | ||
1278 | { | ||
1279 | struct perf_evsel_config_term *term; | ||
1280 | |||
1281 | list_for_each_entry(term, config_terms, list) { | ||
1282 | if (term->type == PERF_EVSEL__CONFIG_TERM_PERCORE) | ||
1283 | return term->val.percore; | ||
1284 | } | ||
1285 | |||
1286 | return false; | ||
1287 | } | ||
1288 | |||
1263 | int parse_events_add_pmu(struct parse_events_state *parse_state, | 1289 | int parse_events_add_pmu(struct parse_events_state *parse_state, |
1264 | struct list_head *list, char *name, | 1290 | struct list_head *list, char *name, |
1265 | struct list_head *head_config, | 1291 | struct list_head *head_config, |
@@ -1333,6 +1359,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, | |||
1333 | evsel->metric_name = info.metric_name; | 1359 | evsel->metric_name = info.metric_name; |
1334 | evsel->pmu_name = name; | 1360 | evsel->pmu_name = name; |
1335 | evsel->use_uncore_alias = use_uncore_alias; | 1361 | evsel->use_uncore_alias = use_uncore_alias; |
1362 | evsel->percore = config_term_percore(&evsel->config_terms); | ||
1336 | } | 1363 | } |
1337 | 1364 | ||
1338 | return evsel ? 0 : -ENOMEM; | 1365 | return evsel ? 0 : -ENOMEM; |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index a052cd6ac63e..f7139e1a2fd3 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -75,6 +75,7 @@ enum { | |||
75 | PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, | 75 | PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, |
76 | PARSE_EVENTS__TERM_TYPE_OVERWRITE, | 76 | PARSE_EVENTS__TERM_TYPE_OVERWRITE, |
77 | PARSE_EVENTS__TERM_TYPE_DRV_CFG, | 77 | PARSE_EVENTS__TERM_TYPE_DRV_CFG, |
78 | PARSE_EVENTS__TERM_TYPE_PERCORE, | ||
78 | __PARSE_EVENTS__TERM_TYPE_NR, | 79 | __PARSE_EVENTS__TERM_TYPE_NR, |
79 | }; | 80 | }; |
80 | 81 | ||
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index c54bfe88626c..ca6098874fe2 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -283,6 +283,7 @@ inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } | |||
283 | no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } | 283 | no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } |
284 | overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } | 284 | overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } |
285 | no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); } | 285 | no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); } |
286 | percore { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); } | ||
286 | , { return ','; } | 287 | , { return ','; } |
287 | "/" { BEGIN(INITIAL); return '/'; } | 288 | "/" { BEGIN(INITIAL); return '/'; } |
288 | {name_minus} { return str(yyscanner, PE_NAME); } | 289 | {name_minus} { return str(yyscanner, PE_NAME); } |
diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c index e6599e290f46..08581e276225 100644 --- a/tools/perf/util/parse-regs-options.c +++ b/tools/perf/util/parse-regs-options.c | |||
@@ -5,13 +5,14 @@ | |||
5 | #include <subcmd/parse-options.h> | 5 | #include <subcmd/parse-options.h> |
6 | #include "util/parse-regs-options.h" | 6 | #include "util/parse-regs-options.h" |
7 | 7 | ||
8 | int | 8 | static int |
9 | parse_regs(const struct option *opt, const char *str, int unset) | 9 | __parse_regs(const struct option *opt, const char *str, int unset, bool intr) |
10 | { | 10 | { |
11 | uint64_t *mode = (uint64_t *)opt->value; | 11 | uint64_t *mode = (uint64_t *)opt->value; |
12 | const struct sample_reg *r; | 12 | const struct sample_reg *r; |
13 | char *s, *os = NULL, *p; | 13 | char *s, *os = NULL, *p; |
14 | int ret = -1; | 14 | int ret = -1; |
15 | uint64_t mask; | ||
15 | 16 | ||
16 | if (unset) | 17 | if (unset) |
17 | return 0; | 18 | return 0; |
@@ -22,6 +23,11 @@ parse_regs(const struct option *opt, const char *str, int unset) | |||
22 | if (*mode) | 23 | if (*mode) |
23 | return -1; | 24 | return -1; |
24 | 25 | ||
26 | if (intr) | ||
27 | mask = arch__intr_reg_mask(); | ||
28 | else | ||
29 | mask = arch__user_reg_mask(); | ||
30 | |||
25 | /* str may be NULL in case no arg is passed to -I */ | 31 | /* str may be NULL in case no arg is passed to -I */ |
26 | if (str) { | 32 | if (str) { |
27 | /* because str is read-only */ | 33 | /* because str is read-only */ |
@@ -37,19 +43,20 @@ parse_regs(const struct option *opt, const char *str, int unset) | |||
37 | if (!strcmp(s, "?")) { | 43 | if (!strcmp(s, "?")) { |
38 | fprintf(stderr, "available registers: "); | 44 | fprintf(stderr, "available registers: "); |
39 | for (r = sample_reg_masks; r->name; r++) { | 45 | for (r = sample_reg_masks; r->name; r++) { |
40 | fprintf(stderr, "%s ", r->name); | 46 | if (r->mask & mask) |
47 | fprintf(stderr, "%s ", r->name); | ||
41 | } | 48 | } |
42 | fputc('\n', stderr); | 49 | fputc('\n', stderr); |
43 | /* just printing available regs */ | 50 | /* just printing available regs */ |
44 | return -1; | 51 | return -1; |
45 | } | 52 | } |
46 | for (r = sample_reg_masks; r->name; r++) { | 53 | for (r = sample_reg_masks; r->name; r++) { |
47 | if (!strcasecmp(s, r->name)) | 54 | if ((r->mask & mask) && !strcasecmp(s, r->name)) |
48 | break; | 55 | break; |
49 | } | 56 | } |
50 | if (!r->name) { | 57 | if (!r->name) { |
51 | ui__warning("unknown register %s," | 58 | ui__warning("Unknown register \"%s\", check man page or run \"perf record %s?\"\n", |
52 | " check man page\n", s); | 59 | s, intr ? "-I" : "--user-regs="); |
53 | goto error; | 60 | goto error; |
54 | } | 61 | } |
55 | 62 | ||
@@ -65,8 +72,20 @@ parse_regs(const struct option *opt, const char *str, int unset) | |||
65 | 72 | ||
66 | /* default to all possible regs */ | 73 | /* default to all possible regs */ |
67 | if (*mode == 0) | 74 | if (*mode == 0) |
68 | *mode = PERF_REGS_MASK; | 75 | *mode = mask; |
69 | error: | 76 | error: |
70 | free(os); | 77 | free(os); |
71 | return ret; | 78 | return ret; |
72 | } | 79 | } |
80 | |||
81 | int | ||
82 | parse_user_regs(const struct option *opt, const char *str, int unset) | ||
83 | { | ||
84 | return __parse_regs(opt, str, unset, false); | ||
85 | } | ||
86 | |||
87 | int | ||
88 | parse_intr_regs(const struct option *opt, const char *str, int unset) | ||
89 | { | ||
90 | return __parse_regs(opt, str, unset, true); | ||
91 | } | ||
diff --git a/tools/perf/util/parse-regs-options.h b/tools/perf/util/parse-regs-options.h index cdefb1acf6be..2b23d25c6394 100644 --- a/tools/perf/util/parse-regs-options.h +++ b/tools/perf/util/parse-regs-options.h | |||
@@ -2,5 +2,6 @@ | |||
2 | #ifndef _PERF_PARSE_REGS_OPTIONS_H | 2 | #ifndef _PERF_PARSE_REGS_OPTIONS_H |
3 | #define _PERF_PARSE_REGS_OPTIONS_H 1 | 3 | #define _PERF_PARSE_REGS_OPTIONS_H 1 |
4 | struct option; | 4 | struct option; |
5 | int parse_regs(const struct option *opt, const char *str, int unset); | 5 | int parse_user_regs(const struct option *opt, const char *str, int unset); |
6 | int parse_intr_regs(const struct option *opt, const char *str, int unset); | ||
6 | #endif /* _PERF_PARSE_REGS_OPTIONS_H */ | 7 | #endif /* _PERF_PARSE_REGS_OPTIONS_H */ |
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c index 2acfcc527cac..2774cec1f15f 100644 --- a/tools/perf/util/perf_regs.c +++ b/tools/perf/util/perf_regs.c | |||
@@ -13,6 +13,16 @@ int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused, | |||
13 | return SDT_ARG_SKIP; | 13 | return SDT_ARG_SKIP; |
14 | } | 14 | } |
15 | 15 | ||
16 | uint64_t __weak arch__intr_reg_mask(void) | ||
17 | { | ||
18 | return PERF_REGS_MASK; | ||
19 | } | ||
20 | |||
21 | uint64_t __weak arch__user_reg_mask(void) | ||
22 | { | ||
23 | return PERF_REGS_MASK; | ||
24 | } | ||
25 | |||
16 | #ifdef HAVE_PERF_REGS_SUPPORT | 26 | #ifdef HAVE_PERF_REGS_SUPPORT |
17 | int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) | 27 | int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) |
18 | { | 28 | { |
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index c9319f8d17a6..cb9c246c8962 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h | |||
@@ -12,6 +12,7 @@ struct sample_reg { | |||
12 | uint64_t mask; | 12 | uint64_t mask; |
13 | }; | 13 | }; |
14 | #define SMPL_REG(n, b) { .name = #n, .mask = 1ULL << (b) } | 14 | #define SMPL_REG(n, b) { .name = #n, .mask = 1ULL << (b) } |
15 | #define SMPL_REG2(n, b) { .name = #n, .mask = 3ULL << (b) } | ||
15 | #define SMPL_REG_END { .name = NULL } | 16 | #define SMPL_REG_END { .name = NULL } |
16 | 17 | ||
17 | extern const struct sample_reg sample_reg_masks[]; | 18 | extern const struct sample_reg sample_reg_masks[]; |
@@ -22,6 +23,8 @@ enum { | |||
22 | }; | 23 | }; |
23 | 24 | ||
24 | int arch_sdt_arg_parse_op(char *old_op, char **new_op); | 25 | int arch_sdt_arg_parse_op(char *old_op, char **new_op); |
26 | uint64_t arch__intr_reg_mask(void); | ||
27 | uint64_t arch__user_reg_mask(void); | ||
25 | 28 | ||
26 | #ifdef HAVE_PERF_REGS_SUPPORT | 29 | #ifdef HAVE_PERF_REGS_SUPPORT |
27 | #include <perf_regs.h> | 30 | #include <perf_regs.h> |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index bad5f87ae001..2310a1752983 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -29,6 +29,61 @@ | |||
29 | #include "stat.h" | 29 | #include "stat.h" |
30 | #include "arch/common.h" | 30 | #include "arch/common.h" |
31 | 31 | ||
32 | #ifdef HAVE_ZSTD_SUPPORT | ||
33 | static int perf_session__process_compressed_event(struct perf_session *session, | ||
34 | union perf_event *event, u64 file_offset) | ||
35 | { | ||
36 | void *src; | ||
37 | size_t decomp_size, src_size; | ||
38 | u64 decomp_last_rem = 0; | ||
39 | size_t decomp_len = session->header.env.comp_mmap_len; | ||
40 | struct decomp *decomp, *decomp_last = session->decomp_last; | ||
41 | |||
42 | decomp = mmap(NULL, sizeof(struct decomp) + decomp_len, PROT_READ|PROT_WRITE, | ||
43 | MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); | ||
44 | if (decomp == MAP_FAILED) { | ||
45 | pr_err("Couldn't allocate memory for decompression\n"); | ||
46 | return -1; | ||
47 | } | ||
48 | |||
49 | decomp->file_pos = file_offset; | ||
50 | decomp->head = 0; | ||
51 | |||
52 | if (decomp_last) { | ||
53 | decomp_last_rem = decomp_last->size - decomp_last->head; | ||
54 | memcpy(decomp->data, &(decomp_last->data[decomp_last->head]), decomp_last_rem); | ||
55 | decomp->size = decomp_last_rem; | ||
56 | } | ||
57 | |||
58 | src = (void *)event + sizeof(struct compressed_event); | ||
59 | src_size = event->pack.header.size - sizeof(struct compressed_event); | ||
60 | |||
61 | decomp_size = zstd_decompress_stream(&(session->zstd_data), src, src_size, | ||
62 | &(decomp->data[decomp_last_rem]), decomp_len - decomp_last_rem); | ||
63 | if (!decomp_size) { | ||
64 | munmap(decomp, sizeof(struct decomp) + decomp_len); | ||
65 | pr_err("Couldn't decompress data\n"); | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | decomp->size += decomp_size; | ||
70 | |||
71 | if (session->decomp == NULL) { | ||
72 | session->decomp = decomp; | ||
73 | session->decomp_last = decomp; | ||
74 | } else { | ||
75 | session->decomp_last->next = decomp; | ||
76 | session->decomp_last = decomp; | ||
77 | } | ||
78 | |||
79 | pr_debug("decomp (B): %ld to %ld\n", src_size, decomp_size); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | #else /* !HAVE_ZSTD_SUPPORT */ | ||
84 | #define perf_session__process_compressed_event perf_session__process_compressed_event_stub | ||
85 | #endif | ||
86 | |||
32 | static int perf_session__deliver_event(struct perf_session *session, | 87 | static int perf_session__deliver_event(struct perf_session *session, |
33 | union perf_event *event, | 88 | union perf_event *event, |
34 | struct perf_tool *tool, | 89 | struct perf_tool *tool, |
@@ -197,6 +252,21 @@ static void perf_session__delete_threads(struct perf_session *session) | |||
197 | machine__delete_threads(&session->machines.host); | 252 | machine__delete_threads(&session->machines.host); |
198 | } | 253 | } |
199 | 254 | ||
255 | static void perf_session__release_decomp_events(struct perf_session *session) | ||
256 | { | ||
257 | struct decomp *next, *decomp; | ||
258 | size_t decomp_len; | ||
259 | next = session->decomp; | ||
260 | decomp_len = session->header.env.comp_mmap_len; | ||
261 | do { | ||
262 | decomp = next; | ||
263 | if (decomp == NULL) | ||
264 | break; | ||
265 | next = decomp->next; | ||
266 | munmap(decomp, decomp_len + sizeof(struct decomp)); | ||
267 | } while (1); | ||
268 | } | ||
269 | |||
200 | void perf_session__delete(struct perf_session *session) | 270 | void perf_session__delete(struct perf_session *session) |
201 | { | 271 | { |
202 | if (session == NULL) | 272 | if (session == NULL) |
@@ -205,6 +275,7 @@ void perf_session__delete(struct perf_session *session) | |||
205 | auxtrace_index__free(&session->auxtrace_index); | 275 | auxtrace_index__free(&session->auxtrace_index); |
206 | perf_session__destroy_kernel_maps(session); | 276 | perf_session__destroy_kernel_maps(session); |
207 | perf_session__delete_threads(session); | 277 | perf_session__delete_threads(session); |
278 | perf_session__release_decomp_events(session); | ||
208 | perf_env__exit(&session->header.env); | 279 | perf_env__exit(&session->header.env); |
209 | machines__exit(&session->machines); | 280 | machines__exit(&session->machines); |
210 | if (session->data) | 281 | if (session->data) |
@@ -358,6 +429,14 @@ static int process_stat_round_stub(struct perf_session *perf_session __maybe_unu | |||
358 | return 0; | 429 | return 0; |
359 | } | 430 | } |
360 | 431 | ||
432 | static int perf_session__process_compressed_event_stub(struct perf_session *session __maybe_unused, | ||
433 | union perf_event *event __maybe_unused, | ||
434 | u64 file_offset __maybe_unused) | ||
435 | { | ||
436 | dump_printf(": unhandled!\n"); | ||
437 | return 0; | ||
438 | } | ||
439 | |||
361 | void perf_tool__fill_defaults(struct perf_tool *tool) | 440 | void perf_tool__fill_defaults(struct perf_tool *tool) |
362 | { | 441 | { |
363 | if (tool->sample == NULL) | 442 | if (tool->sample == NULL) |
@@ -430,6 +509,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
430 | tool->time_conv = process_event_op2_stub; | 509 | tool->time_conv = process_event_op2_stub; |
431 | if (tool->feature == NULL) | 510 | if (tool->feature == NULL) |
432 | tool->feature = process_event_op2_stub; | 511 | tool->feature = process_event_op2_stub; |
512 | if (tool->compressed == NULL) | ||
513 | tool->compressed = perf_session__process_compressed_event; | ||
433 | } | 514 | } |
434 | 515 | ||
435 | static void swap_sample_id_all(union perf_event *event, void *data) | 516 | static void swap_sample_id_all(union perf_event *event, void *data) |
@@ -1373,7 +1454,9 @@ static s64 perf_session__process_user_event(struct perf_session *session, | |||
1373 | int fd = perf_data__fd(session->data); | 1454 | int fd = perf_data__fd(session->data); |
1374 | int err; | 1455 | int err; |
1375 | 1456 | ||
1376 | dump_event(session->evlist, event, file_offset, &sample); | 1457 | if (event->header.type != PERF_RECORD_COMPRESSED || |
1458 | tool->compressed == perf_session__process_compressed_event_stub) | ||
1459 | dump_event(session->evlist, event, file_offset, &sample); | ||
1377 | 1460 | ||
1378 | /* These events are processed right away */ | 1461 | /* These events are processed right away */ |
1379 | switch (event->header.type) { | 1462 | switch (event->header.type) { |
@@ -1426,6 +1509,11 @@ static s64 perf_session__process_user_event(struct perf_session *session, | |||
1426 | return tool->time_conv(session, event); | 1509 | return tool->time_conv(session, event); |
1427 | case PERF_RECORD_HEADER_FEATURE: | 1510 | case PERF_RECORD_HEADER_FEATURE: |
1428 | return tool->feature(session, event); | 1511 | return tool->feature(session, event); |
1512 | case PERF_RECORD_COMPRESSED: | ||
1513 | err = tool->compressed(session, event, file_offset); | ||
1514 | if (err) | ||
1515 | dump_event(session->evlist, event, file_offset, &sample); | ||
1516 | return err; | ||
1429 | default: | 1517 | default: |
1430 | return -EINVAL; | 1518 | return -EINVAL; |
1431 | } | 1519 | } |
@@ -1708,6 +1796,8 @@ static int perf_session__flush_thread_stacks(struct perf_session *session) | |||
1708 | 1796 | ||
1709 | volatile int session_done; | 1797 | volatile int session_done; |
1710 | 1798 | ||
1799 | static int __perf_session__process_decomp_events(struct perf_session *session); | ||
1800 | |||
1711 | static int __perf_session__process_pipe_events(struct perf_session *session) | 1801 | static int __perf_session__process_pipe_events(struct perf_session *session) |
1712 | { | 1802 | { |
1713 | struct ordered_events *oe = &session->ordered_events; | 1803 | struct ordered_events *oe = &session->ordered_events; |
@@ -1788,6 +1878,10 @@ more: | |||
1788 | if (skip > 0) | 1878 | if (skip > 0) |
1789 | head += skip; | 1879 | head += skip; |
1790 | 1880 | ||
1881 | err = __perf_session__process_decomp_events(session); | ||
1882 | if (err) | ||
1883 | goto out_err; | ||
1884 | |||
1791 | if (!session_done()) | 1885 | if (!session_done()) |
1792 | goto more; | 1886 | goto more; |
1793 | done: | 1887 | done: |
@@ -1836,6 +1930,39 @@ fetch_mmaped_event(struct perf_session *session, | |||
1836 | return event; | 1930 | return event; |
1837 | } | 1931 | } |
1838 | 1932 | ||
1933 | static int __perf_session__process_decomp_events(struct perf_session *session) | ||
1934 | { | ||
1935 | s64 skip; | ||
1936 | u64 size, file_pos = 0; | ||
1937 | struct decomp *decomp = session->decomp_last; | ||
1938 | |||
1939 | if (!decomp) | ||
1940 | return 0; | ||
1941 | |||
1942 | while (decomp->head < decomp->size && !session_done()) { | ||
1943 | union perf_event *event = fetch_mmaped_event(session, decomp->head, decomp->size, decomp->data); | ||
1944 | |||
1945 | if (!event) | ||
1946 | break; | ||
1947 | |||
1948 | size = event->header.size; | ||
1949 | |||
1950 | if (size < sizeof(struct perf_event_header) || | ||
1951 | (skip = perf_session__process_event(session, event, file_pos)) < 0) { | ||
1952 | pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", | ||
1953 | decomp->file_pos + decomp->head, event->header.size, event->header.type); | ||
1954 | return -EINVAL; | ||
1955 | } | ||
1956 | |||
1957 | if (skip) | ||
1958 | size += skip; | ||
1959 | |||
1960 | decomp->head += size; | ||
1961 | } | ||
1962 | |||
1963 | return 0; | ||
1964 | } | ||
1965 | |||
1839 | /* | 1966 | /* |
1840 | * On 64bit we can mmap the data file in one go. No need for tiny mmap | 1967 | * On 64bit we can mmap the data file in one go. No need for tiny mmap |
1841 | * slices. On 32bit we use 32MB. | 1968 | * slices. On 32bit we use 32MB. |
@@ -1945,6 +2072,10 @@ more: | |||
1945 | head += size; | 2072 | head += size; |
1946 | file_pos += size; | 2073 | file_pos += size; |
1947 | 2074 | ||
2075 | err = __perf_session__process_decomp_events(session); | ||
2076 | if (err) | ||
2077 | goto out; | ||
2078 | |||
1948 | ui_progress__update(prog, size); | 2079 | ui_progress__update(prog, size); |
1949 | 2080 | ||
1950 | if (session_done()) | 2081 | if (session_done()) |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index d96eccd7d27f..dd8920b745bc 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -8,6 +8,7 @@ | |||
8 | #include "machine.h" | 8 | #include "machine.h" |
9 | #include "data.h" | 9 | #include "data.h" |
10 | #include "ordered-events.h" | 10 | #include "ordered-events.h" |
11 | #include "util/compress.h" | ||
11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
12 | #include <linux/rbtree.h> | 13 | #include <linux/rbtree.h> |
13 | #include <linux/perf_event.h> | 14 | #include <linux/perf_event.h> |
@@ -35,6 +36,19 @@ struct perf_session { | |||
35 | struct ordered_events ordered_events; | 36 | struct ordered_events ordered_events; |
36 | struct perf_data *data; | 37 | struct perf_data *data; |
37 | struct perf_tool *tool; | 38 | struct perf_tool *tool; |
39 | u64 bytes_transferred; | ||
40 | u64 bytes_compressed; | ||
41 | struct zstd_data zstd_data; | ||
42 | struct decomp *decomp; | ||
43 | struct decomp *decomp_last; | ||
44 | }; | ||
45 | |||
46 | struct decomp { | ||
47 | struct decomp *next; | ||
48 | u64 file_pos; | ||
49 | u64 head; | ||
50 | size_t size; | ||
51 | char data[]; | ||
38 | }; | 52 | }; |
39 | 53 | ||
40 | struct perf_tool; | 54 | struct perf_tool; |
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index 3324f23c7efc..4c53bae5644b 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c | |||
@@ -88,9 +88,17 @@ static void aggr_printout(struct perf_stat_config *config, | |||
88 | config->csv_sep); | 88 | config->csv_sep); |
89 | break; | 89 | break; |
90 | case AGGR_NONE: | 90 | case AGGR_NONE: |
91 | fprintf(config->output, "CPU%*d%s", | 91 | if (evsel->percore) { |
92 | config->csv_output ? 0 : -4, | 92 | fprintf(config->output, "S%d-C%*d%s", |
93 | perf_evsel__cpus(evsel)->map[id], config->csv_sep); | 93 | cpu_map__id_to_socket(id), |
94 | config->csv_output ? 0 : -5, | ||
95 | cpu_map__id_to_cpu(id), config->csv_sep); | ||
96 | } else { | ||
97 | fprintf(config->output, "CPU%*d%s ", | ||
98 | config->csv_output ? 0 : -5, | ||
99 | perf_evsel__cpus(evsel)->map[id], | ||
100 | config->csv_sep); | ||
101 | } | ||
94 | break; | 102 | break; |
95 | case AGGR_THREAD: | 103 | case AGGR_THREAD: |
96 | fprintf(config->output, "%*s-%*d%s", | 104 | fprintf(config->output, "%*s-%*d%s", |
@@ -594,6 +602,41 @@ static void aggr_cb(struct perf_stat_config *config, | |||
594 | } | 602 | } |
595 | } | 603 | } |
596 | 604 | ||
605 | static void print_counter_aggrdata(struct perf_stat_config *config, | ||
606 | struct perf_evsel *counter, int s, | ||
607 | char *prefix, bool metric_only, | ||
608 | bool *first) | ||
609 | { | ||
610 | struct aggr_data ad; | ||
611 | FILE *output = config->output; | ||
612 | u64 ena, run, val; | ||
613 | int id, nr; | ||
614 | double uval; | ||
615 | |||
616 | ad.id = id = config->aggr_map->map[s]; | ||
617 | ad.val = ad.ena = ad.run = 0; | ||
618 | ad.nr = 0; | ||
619 | if (!collect_data(config, counter, aggr_cb, &ad)) | ||
620 | return; | ||
621 | |||
622 | nr = ad.nr; | ||
623 | ena = ad.ena; | ||
624 | run = ad.run; | ||
625 | val = ad.val; | ||
626 | if (*first && metric_only) { | ||
627 | *first = false; | ||
628 | aggr_printout(config, counter, id, nr); | ||
629 | } | ||
630 | if (prefix && !metric_only) | ||
631 | fprintf(output, "%s", prefix); | ||
632 | |||
633 | uval = val * counter->scale; | ||
634 | printout(config, id, nr, counter, uval, prefix, | ||
635 | run, ena, 1.0, &rt_stat); | ||
636 | if (!metric_only) | ||
637 | fputc('\n', output); | ||
638 | } | ||
639 | |||
597 | static void print_aggr(struct perf_stat_config *config, | 640 | static void print_aggr(struct perf_stat_config *config, |
598 | struct perf_evlist *evlist, | 641 | struct perf_evlist *evlist, |
599 | char *prefix) | 642 | char *prefix) |
@@ -601,9 +644,7 @@ static void print_aggr(struct perf_stat_config *config, | |||
601 | bool metric_only = config->metric_only; | 644 | bool metric_only = config->metric_only; |
602 | FILE *output = config->output; | 645 | FILE *output = config->output; |
603 | struct perf_evsel *counter; | 646 | struct perf_evsel *counter; |
604 | int s, id, nr; | 647 | int s; |
605 | double uval; | ||
606 | u64 ena, run, val; | ||
607 | bool first; | 648 | bool first; |
608 | 649 | ||
609 | if (!(config->aggr_map || config->aggr_get_id)) | 650 | if (!(config->aggr_map || config->aggr_get_id)) |
@@ -616,33 +657,14 @@ static void print_aggr(struct perf_stat_config *config, | |||
616 | * Without each counter has its own line. | 657 | * Without each counter has its own line. |
617 | */ | 658 | */ |
618 | for (s = 0; s < config->aggr_map->nr; s++) { | 659 | for (s = 0; s < config->aggr_map->nr; s++) { |
619 | struct aggr_data ad; | ||
620 | if (prefix && metric_only) | 660 | if (prefix && metric_only) |
621 | fprintf(output, "%s", prefix); | 661 | fprintf(output, "%s", prefix); |
622 | 662 | ||
623 | ad.id = id = config->aggr_map->map[s]; | ||
624 | first = true; | 663 | first = true; |
625 | evlist__for_each_entry(evlist, counter) { | 664 | evlist__for_each_entry(evlist, counter) { |
626 | ad.val = ad.ena = ad.run = 0; | 665 | print_counter_aggrdata(config, counter, s, |
627 | ad.nr = 0; | 666 | prefix, metric_only, |
628 | if (!collect_data(config, counter, aggr_cb, &ad)) | 667 | &first); |
629 | continue; | ||
630 | nr = ad.nr; | ||
631 | ena = ad.ena; | ||
632 | run = ad.run; | ||
633 | val = ad.val; | ||
634 | if (first && metric_only) { | ||
635 | first = false; | ||
636 | aggr_printout(config, counter, id, nr); | ||
637 | } | ||
638 | if (prefix && !metric_only) | ||
639 | fprintf(output, "%s", prefix); | ||
640 | |||
641 | uval = val * counter->scale; | ||
642 | printout(config, id, nr, counter, uval, prefix, | ||
643 | run, ena, 1.0, &rt_stat); | ||
644 | if (!metric_only) | ||
645 | fputc('\n', output); | ||
646 | } | 668 | } |
647 | if (metric_only) | 669 | if (metric_only) |
648 | fputc('\n', output); | 670 | fputc('\n', output); |
@@ -1089,6 +1111,30 @@ static void print_footer(struct perf_stat_config *config) | |||
1089 | "the same PMU. Try reorganizing the group.\n"); | 1111 | "the same PMU. Try reorganizing the group.\n"); |
1090 | } | 1112 | } |
1091 | 1113 | ||
1114 | static void print_percore(struct perf_stat_config *config, | ||
1115 | struct perf_evsel *counter, char *prefix) | ||
1116 | { | ||
1117 | bool metric_only = config->metric_only; | ||
1118 | FILE *output = config->output; | ||
1119 | int s; | ||
1120 | bool first = true; | ||
1121 | |||
1122 | if (!(config->aggr_map || config->aggr_get_id)) | ||
1123 | return; | ||
1124 | |||
1125 | for (s = 0; s < config->aggr_map->nr; s++) { | ||
1126 | if (prefix && metric_only) | ||
1127 | fprintf(output, "%s", prefix); | ||
1128 | |||
1129 | print_counter_aggrdata(config, counter, s, | ||
1130 | prefix, metric_only, | ||
1131 | &first); | ||
1132 | } | ||
1133 | |||
1134 | if (metric_only) | ||
1135 | fputc('\n', output); | ||
1136 | } | ||
1137 | |||
1092 | void | 1138 | void |
1093 | perf_evlist__print_counters(struct perf_evlist *evlist, | 1139 | perf_evlist__print_counters(struct perf_evlist *evlist, |
1094 | struct perf_stat_config *config, | 1140 | struct perf_stat_config *config, |
@@ -1139,7 +1185,10 @@ perf_evlist__print_counters(struct perf_evlist *evlist, | |||
1139 | print_no_aggr_metric(config, evlist, prefix); | 1185 | print_no_aggr_metric(config, evlist, prefix); |
1140 | else { | 1186 | else { |
1141 | evlist__for_each_entry(evlist, counter) { | 1187 | evlist__for_each_entry(evlist, counter) { |
1142 | print_counter(config, counter, prefix); | 1188 | if (counter->percore) |
1189 | print_percore(config, counter, prefix); | ||
1190 | else | ||
1191 | print_counter(config, counter, prefix); | ||
1143 | } | 1192 | } |
1144 | } | 1193 | } |
1145 | break; | 1194 | break; |
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 2856cc9d5a31..c3115d939b0b 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c | |||
@@ -277,9 +277,11 @@ process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel | |||
277 | if (!evsel->snapshot) | 277 | if (!evsel->snapshot) |
278 | perf_evsel__compute_deltas(evsel, cpu, thread, count); | 278 | perf_evsel__compute_deltas(evsel, cpu, thread, count); |
279 | perf_counts_values__scale(count, config->scale, NULL); | 279 | perf_counts_values__scale(count, config->scale, NULL); |
280 | if (config->aggr_mode == AGGR_NONE) | 280 | if ((config->aggr_mode == AGGR_NONE) && (!evsel->percore)) { |
281 | perf_stat__update_shadow_stats(evsel, count->val, cpu, | 281 | perf_stat__update_shadow_stats(evsel, count->val, |
282 | &rt_stat); | 282 | cpu, &rt_stat); |
283 | } | ||
284 | |||
283 | if (config->aggr_mode == AGGR_THREAD) { | 285 | if (config->aggr_mode == AGGR_THREAD) { |
284 | if (config->stats) | 286 | if (config->stats) |
285 | perf_stat__update_shadow_stats(evsel, | 287 | perf_stat__update_shadow_stats(evsel, |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 50678d318185..403045a2bbea 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "map.h" | 15 | #include "map.h" |
16 | #include "symbol.h" | 16 | #include "symbol.h" |
17 | #include "unwind.h" | 17 | #include "unwind.h" |
18 | #include "callchain.h" | ||
18 | 19 | ||
19 | #include <api/fs/fs.h> | 20 | #include <api/fs/fs.h> |
20 | 21 | ||
@@ -327,7 +328,7 @@ static int thread__prepare_access(struct thread *thread) | |||
327 | { | 328 | { |
328 | int err = 0; | 329 | int err = 0; |
329 | 330 | ||
330 | if (symbol_conf.use_callchain) | 331 | if (dwarf_callchain_users) |
331 | err = __thread__prepare_access(thread); | 332 | err = __thread__prepare_access(thread); |
332 | 333 | ||
333 | return err; | 334 | return err; |
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 250391672f9f..9096a6e3de59 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h | |||
@@ -28,6 +28,7 @@ typedef int (*event_attr_op)(struct perf_tool *tool, | |||
28 | 28 | ||
29 | typedef int (*event_op2)(struct perf_session *session, union perf_event *event); | 29 | typedef int (*event_op2)(struct perf_session *session, union perf_event *event); |
30 | typedef s64 (*event_op3)(struct perf_session *session, union perf_event *event); | 30 | typedef s64 (*event_op3)(struct perf_session *session, union perf_event *event); |
31 | typedef int (*event_op4)(struct perf_session *session, union perf_event *event, u64 data); | ||
31 | 32 | ||
32 | typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event, | 33 | typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event, |
33 | struct ordered_events *oe); | 34 | struct ordered_events *oe); |
@@ -72,6 +73,7 @@ struct perf_tool { | |||
72 | stat, | 73 | stat, |
73 | stat_round, | 74 | stat_round, |
74 | feature; | 75 | feature; |
76 | event_op4 compressed; | ||
75 | event_op3 auxtrace; | 77 | event_op3 auxtrace; |
76 | bool ordered_events; | 78 | bool ordered_events; |
77 | bool ordering_requires_timestamps; | 79 | bool ordering_requires_timestamps; |
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index f3c666a84e4d..25e1406b1f8b 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c | |||
@@ -617,8 +617,6 @@ static unw_accessors_t accessors = { | |||
617 | 617 | ||
618 | static int _unwind__prepare_access(struct thread *thread) | 618 | static int _unwind__prepare_access(struct thread *thread) |
619 | { | 619 | { |
620 | if (!dwarf_callchain_users) | ||
621 | return 0; | ||
622 | thread->addr_space = unw_create_addr_space(&accessors, 0); | 620 | thread->addr_space = unw_create_addr_space(&accessors, 0); |
623 | if (!thread->addr_space) { | 621 | if (!thread->addr_space) { |
624 | pr_err("unwind: Can't create unwind address space.\n"); | 622 | pr_err("unwind: Can't create unwind address space.\n"); |
@@ -631,15 +629,11 @@ static int _unwind__prepare_access(struct thread *thread) | |||
631 | 629 | ||
632 | static void _unwind__flush_access(struct thread *thread) | 630 | static void _unwind__flush_access(struct thread *thread) |
633 | { | 631 | { |
634 | if (!dwarf_callchain_users) | ||
635 | return; | ||
636 | unw_flush_cache(thread->addr_space, 0, 0); | 632 | unw_flush_cache(thread->addr_space, 0, 0); |
637 | } | 633 | } |
638 | 634 | ||
639 | static void _unwind__finish_access(struct thread *thread) | 635 | static void _unwind__finish_access(struct thread *thread) |
640 | { | 636 | { |
641 | if (!dwarf_callchain_users) | ||
642 | return; | ||
643 | unw_destroy_addr_space(thread->addr_space); | 637 | unw_destroy_addr_space(thread->addr_space); |
644 | } | 638 | } |
645 | 639 | ||
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 9778b3133b77..c0811977d7d5 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "session.h" | 5 | #include "session.h" |
6 | #include "debug.h" | 6 | #include "debug.h" |
7 | #include "env.h" | 7 | #include "env.h" |
8 | #include "callchain.h" | ||
8 | 9 | ||
9 | struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; | 10 | struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; |
10 | struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; | 11 | struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; |
@@ -24,6 +25,9 @@ int unwind__prepare_access(struct thread *thread, struct map *map, | |||
24 | struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; | 25 | struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; |
25 | int err; | 26 | int err; |
26 | 27 | ||
28 | if (!dwarf_callchain_users) | ||
29 | return 0; | ||
30 | |||
27 | if (thread->addr_space) { | 31 | if (thread->addr_space) { |
28 | pr_debug("unwind: thread map already set, dso=%s\n", | 32 | pr_debug("unwind: thread map already set, dso=%s\n", |
29 | map->dso->name); | 33 | map->dso->name); |
@@ -65,12 +69,18 @@ out_register: | |||
65 | 69 | ||
66 | void unwind__flush_access(struct thread *thread) | 70 | void unwind__flush_access(struct thread *thread) |
67 | { | 71 | { |
72 | if (!dwarf_callchain_users) | ||
73 | return; | ||
74 | |||
68 | if (thread->unwind_libunwind_ops) | 75 | if (thread->unwind_libunwind_ops) |
69 | thread->unwind_libunwind_ops->flush_access(thread); | 76 | thread->unwind_libunwind_ops->flush_access(thread); |
70 | } | 77 | } |
71 | 78 | ||
72 | void unwind__finish_access(struct thread *thread) | 79 | void unwind__finish_access(struct thread *thread) |
73 | { | 80 | { |
81 | if (!dwarf_callchain_users) | ||
82 | return; | ||
83 | |||
74 | if (thread->unwind_libunwind_ops) | 84 | if (thread->unwind_libunwind_ops) |
75 | thread->unwind_libunwind_ops->finish_access(thread); | 85 | thread->unwind_libunwind_ops->finish_access(thread); |
76 | } | 86 | } |
diff --git a/tools/perf/util/zstd.c b/tools/perf/util/zstd.c new file mode 100644 index 000000000000..23bdb9884576 --- /dev/null +++ b/tools/perf/util/zstd.c | |||
@@ -0,0 +1,111 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | #include <string.h> | ||
4 | |||
5 | #include "util/compress.h" | ||
6 | #include "util/debug.h" | ||
7 | |||
8 | int zstd_init(struct zstd_data *data, int level) | ||
9 | { | ||
10 | size_t ret; | ||
11 | |||
12 | data->dstream = ZSTD_createDStream(); | ||
13 | if (data->dstream == NULL) { | ||
14 | pr_err("Couldn't create decompression stream.\n"); | ||
15 | return -1; | ||
16 | } | ||
17 | |||
18 | ret = ZSTD_initDStream(data->dstream); | ||
19 | if (ZSTD_isError(ret)) { | ||
20 | pr_err("Failed to initialize decompression stream: %s\n", ZSTD_getErrorName(ret)); | ||
21 | return -1; | ||
22 | } | ||
23 | |||
24 | if (!level) | ||
25 | return 0; | ||
26 | |||
27 | data->cstream = ZSTD_createCStream(); | ||
28 | if (data->cstream == NULL) { | ||
29 | pr_err("Couldn't create compression stream.\n"); | ||
30 | return -1; | ||
31 | } | ||
32 | |||
33 | ret = ZSTD_initCStream(data->cstream, level); | ||
34 | if (ZSTD_isError(ret)) { | ||
35 | pr_err("Failed to initialize compression stream: %s\n", ZSTD_getErrorName(ret)); | ||
36 | return -1; | ||
37 | } | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | int zstd_fini(struct zstd_data *data) | ||
43 | { | ||
44 | if (data->dstream) { | ||
45 | ZSTD_freeDStream(data->dstream); | ||
46 | data->dstream = NULL; | ||
47 | } | ||
48 | |||
49 | if (data->cstream) { | ||
50 | ZSTD_freeCStream(data->cstream); | ||
51 | data->cstream = NULL; | ||
52 | } | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size, | ||
58 | void *src, size_t src_size, size_t max_record_size, | ||
59 | size_t process_header(void *record, size_t increment)) | ||
60 | { | ||
61 | size_t ret, size, compressed = 0; | ||
62 | ZSTD_inBuffer input = { src, src_size, 0 }; | ||
63 | ZSTD_outBuffer output; | ||
64 | void *record; | ||
65 | |||
66 | while (input.pos < input.size) { | ||
67 | record = dst; | ||
68 | size = process_header(record, 0); | ||
69 | compressed += size; | ||
70 | dst += size; | ||
71 | dst_size -= size; | ||
72 | output = (ZSTD_outBuffer){ dst, (dst_size > max_record_size) ? | ||
73 | max_record_size : dst_size, 0 }; | ||
74 | ret = ZSTD_compressStream(data->cstream, &output, &input); | ||
75 | ZSTD_flushStream(data->cstream, &output); | ||
76 | if (ZSTD_isError(ret)) { | ||
77 | pr_err("failed to compress %ld bytes: %s\n", | ||
78 | (long)src_size, ZSTD_getErrorName(ret)); | ||
79 | memcpy(dst, src, src_size); | ||
80 | return src_size; | ||
81 | } | ||
82 | size = output.pos; | ||
83 | size = process_header(record, size); | ||
84 | compressed += size; | ||
85 | dst += size; | ||
86 | dst_size -= size; | ||
87 | } | ||
88 | |||
89 | return compressed; | ||
90 | } | ||
91 | |||
92 | size_t zstd_decompress_stream(struct zstd_data *data, void *src, size_t src_size, | ||
93 | void *dst, size_t dst_size) | ||
94 | { | ||
95 | size_t ret; | ||
96 | ZSTD_inBuffer input = { src, src_size, 0 }; | ||
97 | ZSTD_outBuffer output = { dst, dst_size, 0 }; | ||
98 | |||
99 | while (input.pos < input.size) { | ||
100 | ret = ZSTD_decompressStream(data->dstream, &output, &input); | ||
101 | if (ZSTD_isError(ret)) { | ||
102 | pr_err("failed to decompress (B): %ld -> %ld : %s\n", | ||
103 | src_size, output.size, ZSTD_getErrorName(ret)); | ||
104 | break; | ||
105 | } | ||
106 | output.dst = dst + output.pos; | ||
107 | output.size = dst_size - output.pos; | ||
108 | } | ||
109 | |||
110 | return output.pos; | ||
111 | } | ||