aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-14 00:16:56 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-14 00:16:56 -0400
commitfc8e1ead9314cf0e0f1922e661428b93d3a50d88 (patch)
treef3cb97c4769b74f6627a59769f1ed5c92a13c58a /tools
parent2bcaa6a4238094c5695d5b1943078388d82d3004 (diff)
parent9de48cc300fb10f7d9faa978670becf5e352462a (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/.gitignore16
-rw-r--r--tools/perf/CREDITS30
-rw-r--r--tools/perf/Documentation/Makefile300
-rw-r--r--tools/perf/Documentation/asciidoc.conf91
-rw-r--r--tools/perf/Documentation/examples.txt225
-rw-r--r--tools/perf/Documentation/manpage-1.72.xsl14
-rw-r--r--tools/perf/Documentation/manpage-base.xsl35
-rw-r--r--tools/perf/Documentation/manpage-bold-literal.xsl17
-rw-r--r--tools/perf/Documentation/manpage-normal.xsl13
-rw-r--r--tools/perf/Documentation/manpage-suppress-sp.xsl21
-rw-r--r--tools/perf/Documentation/perf-annotate.txt29
-rw-r--r--tools/perf/Documentation/perf-help.txt38
-rw-r--r--tools/perf/Documentation/perf-list.txt25
-rw-r--r--tools/perf/Documentation/perf-record.txt96
-rw-r--r--tools/perf/Documentation/perf-report.txt53
-rw-r--r--tools/perf/Documentation/perf-stat.txt66
-rw-r--r--tools/perf/Documentation/perf-top.txt125
-rw-r--r--tools/perf/Documentation/perf.txt24
-rw-r--r--tools/perf/Makefile973
-rw-r--r--tools/perf/builtin-annotate.c1505
-rw-r--r--tools/perf/builtin-help.c463
-rw-r--r--tools/perf/builtin-list.c21
-rw-r--r--tools/perf/builtin-record.c712
-rw-r--r--tools/perf/builtin-report.c2173
-rw-r--r--tools/perf/builtin-stat.c552
-rw-r--r--tools/perf/builtin-top.c1220
-rw-r--r--tools/perf/builtin.h26
-rw-r--r--tools/perf/command-list.txt10
-rw-r--r--tools/perf/design.txt457
-rw-r--r--tools/perf/perf.c500
-rw-r--r--tools/perf/perf.h104
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN42
-rw-r--r--tools/perf/util/abspath.c117
-rw-r--r--tools/perf/util/alias.c77
-rw-r--r--tools/perf/util/cache.h121
-rw-r--r--tools/perf/util/callchain.c343
-rw-r--r--tools/perf/util/callchain.h60
-rw-r--r--tools/perf/util/color.c272
-rw-r--r--tools/perf/util/color.h41
-rw-r--r--tools/perf/util/config.c875
-rw-r--r--tools/perf/util/ctype.c31
-rw-r--r--tools/perf/util/environment.c9
-rw-r--r--tools/perf/util/exec_cmd.c168
-rw-r--r--tools/perf/util/exec_cmd.h13
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh24
-rw-r--r--tools/perf/util/header.c245
-rw-r--r--tools/perf/util/header.h37
-rw-r--r--tools/perf/util/help.c356
-rw-r--r--tools/perf/util/help.h29
-rw-r--r--tools/perf/util/include/asm/system.h1
-rw-r--r--tools/perf/util/include/linux/kernel.h29
-rw-r--r--tools/perf/util/include/linux/list.h18
-rw-r--r--tools/perf/util/include/linux/module.h6
-rw-r--r--tools/perf/util/include/linux/poison.h1
-rw-r--r--tools/perf/util/include/linux/prefetch.h6
-rw-r--r--tools/perf/util/include/linux/rbtree.h1
-rw-r--r--tools/perf/util/levenshtein.c84
-rw-r--r--tools/perf/util/levenshtein.h8
-rw-r--r--tools/perf/util/module.c509
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/pager.c96
-rw-r--r--tools/perf/util/parse-events.c682
-rw-r--r--tools/perf/util/parse-events.h23
-rw-r--r--tools/perf/util/parse-options.c509
-rw-r--r--tools/perf/util/parse-options.h175
-rw-r--r--tools/perf/util/path.c353
-rw-r--r--tools/perf/util/quote.c485
-rw-r--r--tools/perf/util/quote.h68
-rw-r--r--tools/perf/util/run-command.c304
-rw-r--r--tools/perf/util/run-command.h88
-rw-r--r--tools/perf/util/sigchain.c52
-rw-r--r--tools/perf/util/sigchain.h11
-rw-r--r--tools/perf/util/strbuf.c360
-rw-r--r--tools/perf/util/strbuf.h137
-rw-r--r--tools/perf/util/string.c34
-rw-r--r--tools/perf/util/string.h11
-rw-r--r--tools/perf/util/strlist.c200
-rw-r--r--tools/perf/util/strlist.h39
-rw-r--r--tools/perf/util/symbol.c930
-rw-r--r--tools/perf/util/symbol.h80
-rw-r--r--tools/perf/util/types.h17
-rw-r--r--tools/perf/util/usage.c80
-rw-r--r--tools/perf/util/util.h395
-rw-r--r--tools/perf/util/wrapper.c207
84 files changed, 18846 insertions, 0 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
new file mode 100644
index 000000000000..d69a759a1046
--- /dev/null
+++ b/tools/perf/.gitignore
@@ -0,0 +1,16 @@
1PERF-BUILD-OPTIONS
2PERF-CFLAGS
3PERF-GUI-VARS
4PERF-VERSION-FILE
5perf
6perf-help
7perf-record
8perf-report
9perf-stat
10perf-top
11perf*.1
12perf*.xml
13common-cmds.h
14tags
15TAGS
16cscope*
diff --git a/tools/perf/CREDITS b/tools/perf/CREDITS
new file mode 100644
index 000000000000..c2ddcb3acbd0
--- /dev/null
+++ b/tools/perf/CREDITS
@@ -0,0 +1,30 @@
1Most of the infrastructure that 'perf' uses here has been reused
2from the Git project, as of version:
3
4 66996ec: Sync with 1.6.2.4
5
6Here is an (incomplete!) list of main contributors to those files
7in util/* and elsewhere:
8
9 Alex Riesen
10 Christian Couder
11 Dmitry Potapov
12 Jeff King
13 Johannes Schindelin
14 Johannes Sixt
15 Junio C Hamano
16 Linus Torvalds
17 Matthias Kestenholz
18 Michal Ostrowski
19 Miklos Vajna
20 Petr Baudis
21 Pierre Habouzit
22 René Scharfe
23 Samuel Tardieu
24 Shawn O. Pearce
25 Steffen Prohaska
26 Steve Haslam
27
28Thanks guys!
29
30The full history of the files can be found in the upstream Git commits.
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
new file mode 100644
index 000000000000..bdd3b7ecad0a
--- /dev/null
+++ b/tools/perf/Documentation/Makefile
@@ -0,0 +1,300 @@
1MAN1_TXT= \
2 $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
3 $(wildcard perf-*.txt)) \
4 perf.txt
5MAN5_TXT=
6MAN7_TXT=
7
8MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
9MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
10MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
11
12DOC_HTML=$(MAN_HTML)
13
14ARTICLES =
15# with their own formatting rules.
16SP_ARTICLES =
17API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
18SP_ARTICLES += $(API_DOCS)
19SP_ARTICLES += technical/api-index
20
21DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
22
23DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
24DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
25DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
26
27prefix?=$(HOME)
28bindir?=$(prefix)/bin
29htmldir?=$(prefix)/share/doc/perf-doc
30pdfdir?=$(prefix)/share/doc/perf-doc
31mandir?=$(prefix)/share/man
32man1dir=$(mandir)/man1
33man5dir=$(mandir)/man5
34man7dir=$(mandir)/man7
35# DESTDIR=
36
37ASCIIDOC=asciidoc
38ASCIIDOC_EXTRA = --unsafe
39MANPAGE_XSL = manpage-normal.xsl
40XMLTO_EXTRA =
41INSTALL?=install
42RM ?= rm -f
43DOC_REF = origin/man
44HTML_REF = origin/html
45
46infodir?=$(prefix)/share/info
47MAKEINFO=makeinfo
48INSTALL_INFO=install-info
49DOCBOOK2X_TEXI=docbook2x-texi
50DBLATEX=dblatex
51ifndef PERL_PATH
52 PERL_PATH = /usr/bin/perl
53endif
54
55-include ../config.mak.autogen
56-include ../config.mak
57
58#
59# For asciidoc ...
60# -7.1.2, no extra settings are needed.
61# 8.0-, set ASCIIDOC8.
62#
63
64#
65# For docbook-xsl ...
66# -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0)
67# 1.69.0, no extra settings are needed?
68# 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP?
69# 1.71.1, no extra settings are needed?
70# 1.72.0, set DOCBOOK_XSL_172.
71# 1.73.0-, set ASCIIDOC_NO_ROFF
72#
73
74#
75# If you had been using DOCBOOK_XSL_172 in an attempt to get rid
76# of 'the ".ft C" problem' in your generated manpages, and you
77# instead ended up with weird characters around callouts, try
78# using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8).
79#
80
81ifdef ASCIIDOC8
82ASCIIDOC_EXTRA += -a asciidoc7compatible
83endif
84ifdef DOCBOOK_XSL_172
85ASCIIDOC_EXTRA += -a perf-asciidoc-no-roff
86MANPAGE_XSL = manpage-1.72.xsl
87else
88 ifdef ASCIIDOC_NO_ROFF
89 # docbook-xsl after 1.72 needs the regular XSL, but will not
90 # pass-thru raw roff codes from asciidoc.conf, so turn them off.
91 ASCIIDOC_EXTRA += -a perf-asciidoc-no-roff
92 endif
93endif
94ifdef MAN_BOLD_LITERAL
95XMLTO_EXTRA += -m manpage-bold-literal.xsl
96endif
97ifdef DOCBOOK_SUPPRESS_SP
98XMLTO_EXTRA += -m manpage-suppress-sp.xsl
99endif
100
101SHELL_PATH ?= $(SHELL)
102# Shell quote;
103SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
104
105#
106# Please note that there is a minor bug in asciidoc.
107# The version after 6.0.3 _will_ include the patch found here:
108# http://marc.theaimsgroup.com/?l=perf&m=111558757202243&w=2
109#
110# Until that version is released you may have to apply the patch
111# yourself - yes, all 6 characters of it!
112#
113
114QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
115QUIET_SUBDIR1 =
116
117ifneq ($(findstring $(MAKEFLAGS),w),w)
118PRINT_DIR = --no-print-directory
119else # "make -w"
120NO_SUBDIR = :
121endif
122
123ifneq ($(findstring $(MAKEFLAGS),s),s)
124ifndef V
125 QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@;
126 QUIET_XMLTO = @echo ' ' XMLTO $@;
127 QUIET_DB2TEXI = @echo ' ' DB2TEXI $@;
128 QUIET_MAKEINFO = @echo ' ' MAKEINFO $@;
129 QUIET_DBLATEX = @echo ' ' DBLATEX $@;
130 QUIET_XSLTPROC = @echo ' ' XSLTPROC $@;
131 QUIET_GEN = @echo ' ' GEN $@;
132 QUIET_STDERR = 2> /dev/null
133 QUIET_SUBDIR0 = +@subdir=
134 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
135 $(MAKE) $(PRINT_DIR) -C $$subdir
136 export V
137endif
138endif
139
140all: html man
141
142html: $(DOC_HTML)
143
144$(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7): asciidoc.conf
145
146man: man1 man5 man7
147man1: $(DOC_MAN1)
148man5: $(DOC_MAN5)
149man7: $(DOC_MAN7)
150
151info: perf.info perfman.info
152
153pdf: user-manual.pdf
154
155install: install-man
156
157install-man: man
158 $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
159# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir)
160# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
161 $(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(man1dir)
162# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir)
163# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
164
165install-info: info
166 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
167 $(INSTALL) -m 644 perf.info perfman.info $(DESTDIR)$(infodir)
168 if test -r $(DESTDIR)$(infodir)/dir; then \
169 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\
170 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\
171 else \
172 echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \
173 fi
174
175install-pdf: pdf
176 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
177 $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
178
179install-html: html
180 '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
181
182../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
183 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE
184
185-include ../PERF-VERSION-FILE
186
187#
188# Determine "include::" file references in asciidoc files.
189#
190doc.dep : $(wildcard *.txt) build-docdep.perl
191 $(QUIET_GEN)$(RM) $@+ $@ && \
192 $(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \
193 mv $@+ $@
194
195-include doc.dep
196
197cmds_txt = cmds-ancillaryinterrogators.txt \
198 cmds-ancillarymanipulators.txt \
199 cmds-mainporcelain.txt \
200 cmds-plumbinginterrogators.txt \
201 cmds-plumbingmanipulators.txt \
202 cmds-synchingrepositories.txt \
203 cmds-synchelpers.txt \
204 cmds-purehelpers.txt \
205 cmds-foreignscminterface.txt
206
207$(cmds_txt): cmd-list.made
208
209cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
210 $(QUIET_GEN)$(RM) $@ && \
211 $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
212 date >$@
213
214clean:
215 $(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7
216 $(RM) *.texi *.texi+ *.texi++ perf.info perfman.info
217 $(RM) howto-index.txt howto/*.html doc.dep
218 $(RM) technical/api-*.html technical/api-index.txt
219 $(RM) $(cmds_txt) *.made
220
221$(MAN_HTML): %.html : %.txt
222 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
223 $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
224 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
225 mv $@+ $@
226
227%.1 %.5 %.7 : %.xml
228 $(QUIET_XMLTO)$(RM) $@ && \
229 xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
230
231%.xml : %.txt
232 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
233 $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
234 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
235 mv $@+ $@
236
237XSLT = docbook.xsl
238XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
239
240user-manual.html: user-manual.xml
241 $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
242
243perf.info: user-manual.texi
244 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi
245
246user-manual.texi: user-manual.xml
247 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
248 $(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \
249 $(PERL_PATH) fix-texi.perl <$@++ >$@+ && \
250 rm $@++ && \
251 mv $@+ $@
252
253user-manual.pdf: user-manual.xml
254 $(QUIET_DBLATEX)$(RM) $@+ $@ && \
255 $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \
256 mv $@+ $@
257
258perfman.texi: $(MAN_XML) cat-texi.perl
259 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
260 ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \
261 --to-stdout $(xml) &&) true) > $@++ && \
262 $(PERL_PATH) cat-texi.perl $@ <$@++ >$@+ && \
263 rm $@++ && \
264 mv $@+ $@
265
266perfman.info: perfman.texi
267 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi
268
269$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
270 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
271 $(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+ && \
272 mv $@+ $@
273
274howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
275 $(QUIET_GEN)$(RM) $@+ $@ && \
276 '$(SHELL_PATH_SQ)' ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \
277 mv $@+ $@
278
279$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
280 $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 $*.txt
281
282WEBDOC_DEST = /pub/software/tools/perf/docs
283
284$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
285 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
286 sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \
287 mv $@+ $@
288
289install-webdoc : html
290 '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
291
292quick-install: quick-install-man
293
294quick-install-man:
295 '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
296
297quick-install-html:
298 '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
299
300.PHONY: .FORCE-PERF-VERSION-FILE
diff --git a/tools/perf/Documentation/asciidoc.conf b/tools/perf/Documentation/asciidoc.conf
new file mode 100644
index 000000000000..356b23a40339
--- /dev/null
+++ b/tools/perf/Documentation/asciidoc.conf
@@ -0,0 +1,91 @@
1## linkperf: macro
2#
3# Usage: linkperf:command[manpage-section]
4#
5# Note, {0} is the manpage section, while {target} is the command.
6#
7# Show PERF link as: <command>(<section>); if section is defined, else just show
8# the command.
9
10[macros]
11(?su)[\\]?(?P<name>linkperf):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
12
13[attributes]
14asterisk=&#42;
15plus=&#43;
16caret=&#94;
17startsb=&#91;
18endsb=&#93;
19tilde=&#126;
20
21ifdef::backend-docbook[]
22[linkperf-inlinemacro]
23{0%{target}}
24{0#<citerefentry>}
25{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
26{0#</citerefentry>}
27endif::backend-docbook[]
28
29ifdef::backend-docbook[]
30ifndef::perf-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>
36ifdef::doctype-manpage[]
37&#10;.ft C&#10;
38endif::doctype-manpage[]
39|
40ifdef::doctype-manpage[]
41&#10;.ft&#10;
42endif::doctype-manpage[]
43</literallayout>
44{title#}</example>
45endif::perf-asciidoc-no-roff[]
46
47ifdef::perf-asciidoc-no-roff[]
48ifdef::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>
65endif::doctype-manpage[]
66endif::perf-asciidoc-no-roff[]
67endif::backend-docbook[]
68
69ifdef::doctype-manpage[]
70ifdef::backend-docbook[]
71[header]
72template::[header-declarations]
73<refentry>
74<refmeta>
75<refentrytitle>{mantitle}</refentrytitle>
76<manvolnum>{manvolnum}</manvolnum>
77<refmiscinfo class="source">perf</refmiscinfo>
78<refmiscinfo class="version">{perf_version}</refmiscinfo>
79<refmiscinfo class="manual">perf Manual</refmiscinfo>
80</refmeta>
81<refnamediv>
82 <refname>{manname}</refname>
83 <refpurpose>{manpurpose}</refpurpose>
84</refnamediv>
85endif::backend-docbook[]
86endif::doctype-manpage[]
87
88ifdef::backend-xhtml11[]
89[linkperf-inlinemacro]
90<a href="{target}.html">{target}{0?({0})}</a>
91endif::backend-xhtml11[]
diff --git a/tools/perf/Documentation/examples.txt b/tools/perf/Documentation/examples.txt
new file mode 100644
index 000000000000..8eb6c489fb15
--- /dev/null
+++ b/tools/perf/Documentation/examples.txt
@@ -0,0 +1,225 @@
1
2 ------------------------------
3 ****** perf by examples ******
4 ------------------------------
5
6[ From an e-mail by Ingo Molnar, http://lkml.org/lkml/2009/8/4/346 ]
7
8
9First, discovery/enumeration of available counters can be done via
10'perf list':
11
12titan:~> perf list
13 [...]
14 kmem:kmalloc [Tracepoint event]
15 kmem:kmem_cache_alloc [Tracepoint event]
16 kmem:kmalloc_node [Tracepoint event]
17 kmem:kmem_cache_alloc_node [Tracepoint event]
18 kmem:kfree [Tracepoint event]
19 kmem:kmem_cache_free [Tracepoint event]
20 kmem:mm_page_free_direct [Tracepoint event]
21 kmem:mm_pagevec_free [Tracepoint event]
22 kmem:mm_page_alloc [Tracepoint event]
23 kmem:mm_page_alloc_zone_locked [Tracepoint event]
24 kmem:mm_page_pcpu_drain [Tracepoint event]
25 kmem:mm_page_alloc_extfrag [Tracepoint event]
26
27Then any (or all) of the above event sources can be activated and
28measured. For example the page alloc/free properties of a 'hackbench
29run' are:
30
31 titan:~> perf stat -e kmem:mm_page_pcpu_drain -e kmem:mm_page_alloc
32 -e kmem:mm_pagevec_free -e kmem:mm_page_free_direct ./hackbench 10
33 Time: 0.575
34
35 Performance counter stats for './hackbench 10':
36
37 13857 kmem:mm_page_pcpu_drain
38 27576 kmem:mm_page_alloc
39 6025 kmem:mm_pagevec_free
40 20934 kmem:mm_page_free_direct
41
42 0.613972165 seconds time elapsed
43
44You can observe the statistical properties as well, by using the
45'repeat the workload N times' feature of perf stat:
46
47 titan:~> perf stat --repeat 5 -e kmem:mm_page_pcpu_drain -e
48 kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
49 kmem:mm_page_free_direct ./hackbench 10
50 Time: 0.627
51 Time: 0.644
52 Time: 0.564
53 Time: 0.559
54 Time: 0.626
55
56 Performance counter stats for './hackbench 10' (5 runs):
57
58 12920 kmem:mm_page_pcpu_drain ( +- 3.359% )
59 25035 kmem:mm_page_alloc ( +- 3.783% )
60 6104 kmem:mm_pagevec_free ( +- 0.934% )
61 18376 kmem:mm_page_free_direct ( +- 4.941% )
62
63 0.643954516 seconds time elapsed ( +- 2.363% )
64
65Furthermore, these tracepoints can be used to sample the workload as
66well. For example the page allocations done by a 'git gc' can be
67captured the following way:
68
69 titan:~/git> perf record -f -e kmem:mm_page_alloc -c 1 ./git gc
70 Counting objects: 1148, done.
71 Delta compression using up to 2 threads.
72 Compressing objects: 100% (450/450), done.
73 Writing objects: 100% (1148/1148), done.
74 Total 1148 (delta 690), reused 1148 (delta 690)
75 [ perf record: Captured and wrote 0.267 MB perf.data (~11679 samples) ]
76
77To check which functions generated page allocations:
78
79 titan:~/git> perf report
80 # Samples: 10646
81 #
82 # Overhead Command Shared Object
83 # ........ ............... ..........................
84 #
85 23.57% git-repack /lib64/libc-2.5.so
86 21.81% git /lib64/libc-2.5.so
87 14.59% git ./git
88 11.79% git-repack ./git
89 7.12% git /lib64/ld-2.5.so
90 3.16% git-repack /lib64/libpthread-2.5.so
91 2.09% git-repack /bin/bash
92 1.97% rm /lib64/libc-2.5.so
93 1.39% mv /lib64/ld-2.5.so
94 1.37% mv /lib64/libc-2.5.so
95 1.12% git-repack /lib64/ld-2.5.so
96 0.95% rm /lib64/ld-2.5.so
97 0.90% git-update-serv /lib64/libc-2.5.so
98 0.73% git-update-serv /lib64/ld-2.5.so
99 0.68% perf /lib64/libpthread-2.5.so
100 0.64% git-repack /usr/lib64/libz.so.1.2.3
101
102Or to see it on a more finegrained level:
103
104titan:~/git> perf report --sort comm,dso,symbol
105# Samples: 10646
106#
107# Overhead Command Shared Object Symbol
108# ........ ............... .......................... ......
109#
110 9.35% git-repack ./git [.] insert_obj_hash
111 9.12% git ./git [.] insert_obj_hash
112 7.31% git /lib64/libc-2.5.so [.] memcpy
113 6.34% git-repack /lib64/libc-2.5.so [.] _int_malloc
114 6.24% git-repack /lib64/libc-2.5.so [.] memcpy
115 5.82% git-repack /lib64/libc-2.5.so [.] __GI___fork
116 5.47% git /lib64/libc-2.5.so [.] _int_malloc
117 2.99% git /lib64/libc-2.5.so [.] memset
118
119Furthermore, call-graph sampling can be done too, of page
120allocations - to see precisely what kind of page allocations there
121are:
122
123 titan:~/git> perf record -f -g -e kmem:mm_page_alloc -c 1 ./git gc
124 Counting objects: 1148, done.
125 Delta compression using up to 2 threads.
126 Compressing objects: 100% (450/450), done.
127 Writing objects: 100% (1148/1148), done.
128 Total 1148 (delta 690), reused 1148 (delta 690)
129 [ perf record: Captured and wrote 0.963 MB perf.data (~42069 samples) ]
130
131 titan:~/git> perf report -g
132 # Samples: 10686
133 #
134 # Overhead Command Shared Object
135 # ........ ............... ..........................
136 #
137 23.25% git-repack /lib64/libc-2.5.so
138 |
139 |--50.00%-- _int_free
140 |
141 |--37.50%-- __GI___fork
142 | make_child
143 |
144 |--12.50%-- ptmalloc_unlock_all2
145 | make_child
146 |
147 --6.25%-- __GI_strcpy
148 21.61% git /lib64/libc-2.5.so
149 |
150 |--30.00%-- __GI_read
151 | |
152 | --83.33%-- git_config_from_file
153 | git_config
154 | |
155 [...]
156
157Or you can observe the whole system's page allocations for 10
158seconds:
159
160titan:~/git> perf stat -a -e kmem:mm_page_pcpu_drain -e
161kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
162kmem:mm_page_free_direct sleep 10
163
164 Performance counter stats for 'sleep 10':
165
166 171585 kmem:mm_page_pcpu_drain
167 322114 kmem:mm_page_alloc
168 73623 kmem:mm_pagevec_free
169 254115 kmem:mm_page_free_direct
170
171 10.000591410 seconds time elapsed
172
173Or observe how fluctuating the page allocations are, via statistical
174analysis done over ten 1-second intervals:
175
176 titan:~/git> perf stat --repeat 10 -a -e kmem:mm_page_pcpu_drain -e
177 kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
178 kmem:mm_page_free_direct sleep 1
179
180 Performance counter stats for 'sleep 1' (10 runs):
181
182 17254 kmem:mm_page_pcpu_drain ( +- 3.709% )
183 34394 kmem:mm_page_alloc ( +- 4.617% )
184 7509 kmem:mm_pagevec_free ( +- 4.820% )
185 25653 kmem:mm_page_free_direct ( +- 3.672% )
186
187 1.058135029 seconds time elapsed ( +- 3.089% )
188
189Or you can annotate the recorded 'git gc' run on a per symbol basis
190and check which instructions/source-code generated page allocations:
191
192 titan:~/git> perf annotate __GI___fork
193 ------------------------------------------------
194 Percent | Source code & Disassembly of libc-2.5.so
195 ------------------------------------------------
196 :
197 :
198 : Disassembly of section .plt:
199 : Disassembly of section .text:
200 :
201 : 00000031a2e95560 <__fork>:
202 [...]
203 0.00 : 31a2e95602: b8 38 00 00 00 mov $0x38,%eax
204 0.00 : 31a2e95607: 0f 05 syscall
205 83.42 : 31a2e95609: 48 3d 00 f0 ff ff cmp $0xfffffffffffff000,%rax
206 0.00 : 31a2e9560f: 0f 87 4d 01 00 00 ja 31a2e95762 <__fork+0x202>
207 0.00 : 31a2e95615: 85 c0 test %eax,%eax
208
209( this shows that 83.42% of __GI___fork's page allocations come from
210 the 0x38 system call it performs. )
211
212etc. etc. - a lot more is possible. I could list a dozen of
213other different usecases straight away - neither of which is
214possible via /proc/vmstat.
215
216/proc/vmstat is not in the same league really, in terms of
217expressive power of system analysis and performance
218analysis.
219
220All that the above results needed were those new tracepoints
221in include/tracing/events/kmem.h.
222
223 Ingo
224
225
diff --git a/tools/perf/Documentation/manpage-1.72.xsl b/tools/perf/Documentation/manpage-1.72.xsl
new file mode 100644
index 000000000000..b4d315cb8c47
--- /dev/null
+++ b/tools/perf/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">&#x2593;</xsl:param>
12<xsl:param name="git.docbook.dot" >&#x2302;</xsl:param>
13
14</xsl:stylesheet>
diff --git a/tools/perf/Documentation/manpage-base.xsl b/tools/perf/Documentation/manpage-base.xsl
new file mode 100644
index 000000000000..a264fa616093
--- /dev/null
+++ b/tools/perf/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&#10;</xsl:text>
22 <xsl:apply-templates/>
23 <xsl:text>&#10;</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&#10;</xsl:text>
33</xsl:template>
34
35</xsl:stylesheet>
diff --git a/tools/perf/Documentation/manpage-bold-literal.xsl b/tools/perf/Documentation/manpage-bold-literal.xsl
new file mode 100644
index 000000000000..608eb5df6281
--- /dev/null
+++ b/tools/perf/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/perf/Documentation/manpage-normal.xsl b/tools/perf/Documentation/manpage-normal.xsl
new file mode 100644
index 000000000000..a48f5b11f3dc
--- /dev/null
+++ b/tools/perf/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/perf/Documentation/manpage-suppress-sp.xsl b/tools/perf/Documentation/manpage-suppress-sp.xsl
new file mode 100644
index 000000000000..a63c7632a87d
--- /dev/null
+++ b/tools/perf/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>&#10;&#10;</xsl:text>
18 </xsl:if>
19</xsl:template>
20
21</xsl:stylesheet>
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
new file mode 100644
index 000000000000..c9dcade06831
--- /dev/null
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -0,0 +1,29 @@
1perf-annotate(1)
2==============
3
4NAME
5----
6perf-annotate - Read perf.data (created by perf record) and display annotated code
7
8SYNOPSIS
9--------
10[verse]
11'perf annotate' [-i <file> | --input=file] symbol_name
12
13DESCRIPTION
14-----------
15This command reads the input file and displays an annotated version of the
16code. If the object file has debug symbols then the source code will be
17displayed alongside assembly code.
18
19If there is no debug info in the object, then annotated assembly is displayed.
20
21OPTIONS
22-------
23-i::
24--input=::
25 Input file name. (default: perf.data)
26
27SEE ALSO
28--------
29linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-help.txt b/tools/perf/Documentation/perf-help.txt
new file mode 100644
index 000000000000..514391818d1f
--- /dev/null
+++ b/tools/perf/Documentation/perf-help.txt
@@ -0,0 +1,38 @@
1perf-help(1)
2============
3
4NAME
5----
6perf-help - display help information about perf
7
8SYNOPSIS
9--------
10'perf help' [-a|--all] [COMMAND]
11
12DESCRIPTION
13-----------
14
15With no options and no COMMAND given, the synopsis of the 'perf'
16command and a list of the most commonly used perf commands are printed
17on the standard output.
18
19If the option '--all' or '-a' is given, then all available commands are
20printed on the standard output.
21
22If a perf command is named, a manual page for that command is brought
23up. The 'man' program is used by default for this purpose, but this
24can be overridden by other options or configuration variables.
25
26Note that `perf --help ...` is identical to `perf help ...` because the
27former is internally converted into the latter.
28
29OPTIONS
30-------
31-a::
32--all::
33 Prints all the available commands on the standard output. This
34 option supersedes any other option.
35
36PERF
37----
38Part of the linkperf:perf[1] suite
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
new file mode 100644
index 000000000000..8290b9422668
--- /dev/null
+++ b/tools/perf/Documentation/perf-list.txt
@@ -0,0 +1,25 @@
1perf-list(1)
2============
3
4NAME
5----
6perf-list - List all symbolic event types
7
8SYNOPSIS
9--------
10[verse]
11'perf list'
12
13DESCRIPTION
14-----------
15This command displays the symbolic event types which can be selected in the
16various perf commands with the -e option.
17
18OPTIONS
19-------
20None
21
22SEE ALSO
23--------
24linkperf:perf-stat[1], linkperf:perf-top[1],
25linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
new file mode 100644
index 000000000000..6be696b0a2bb
--- /dev/null
+++ b/tools/perf/Documentation/perf-record.txt
@@ -0,0 +1,96 @@
1perf-record(1)
2==============
3
4NAME
5----
6perf-record - Run a command and record its profile into perf.data
7
8SYNOPSIS
9--------
10[verse]
11'perf record' [-e <EVENT> | --event=EVENT] [-l] [-a] <command>
12'perf record' [-e <EVENT> | --event=EVENT] [-l] [-a] -- <command> [<options>]
13
14DESCRIPTION
15-----------
16This command runs a command and gathers a performance counter profile
17from it, into perf.data - without displaying anything.
18
19This file can then be inspected later on, using 'perf report'.
20
21
22OPTIONS
23-------
24<command>...::
25 Any command you can specify in a shell.
26
27-e::
28--event=::
29 Select the PMU event. Selection can be a symbolic event name
30 (use 'perf list' to list all events) or a raw PMU
31 event (eventsel+umask) in the form of rNNN where NNN is a
32 hexadecimal event descriptor.
33
34-a::
35 System-wide collection.
36
37-l::
38 Scale counter values.
39
40-p::
41--pid=::
42 Record events on existing pid.
43
44-r::
45--realtime=::
46 Collect data with this RT SCHED_FIFO priority.
47-A::
48--append::
49 Append to the output file to do incremental profiling.
50
51-f::
52--force::
53 Overwrite existing data file.
54
55-c::
56--count=::
57 Event period to sample.
58
59-o::
60--output=::
61 Output file name.
62
63-i::
64--inherit::
65 Child tasks inherit counters.
66-F::
67--freq=::
68 Profile at this frequency.
69
70-m::
71--mmap-pages=::
72 Number of mmap data pages.
73
74-g::
75--call-graph::
76 Do call-graph (stack chain/backtrace) recording.
77
78-v::
79--verbose::
80 Be more verbose (show counter open errors, etc).
81
82-s::
83--stat::
84 Per thread counts.
85
86-d::
87--data::
88 Sample addresses.
89
90-n::
91--no-samples::
92 Don't sample.
93
94SEE ALSO
95--------
96linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
new file mode 100644
index 000000000000..e72e93110782
--- /dev/null
+++ b/tools/perf/Documentation/perf-report.txt
@@ -0,0 +1,53 @@
1perf-report(1)
2==============
3
4NAME
5----
6perf-report - Read perf.data (created by perf record) and display the profile
7
8SYNOPSIS
9--------
10[verse]
11'perf report' [-i <file> | --input=file]
12
13DESCRIPTION
14-----------
15This command displays the performance counter profile information recorded
16via perf record.
17
18OPTIONS
19-------
20-i::
21--input=::
22 Input file name. (default: perf.data)
23-d::
24--dsos=::
25 Only consider symbols in these dsos. CSV that understands
26 file://filename entries.
27-n
28--show-nr-samples
29 Show the number of samples for each symbol
30-C::
31--comms=::
32 Only consider symbols in these comms. CSV that understands
33 file://filename entries.
34-S::
35--symbols=::
36 Only consider these symbols. CSV that understands
37 file://filename entries.
38
39-w::
40--field-width=::
41 Force each column width to the provided list, for large terminal
42 readability.
43
44-t::
45--field-separator=::
46
47 Use a special separator character and don't pad with spaces, replacing
48 all occurances of this separator in symbol names (and other output)
49 with a '.' character, that thus it's the only non valid separator.
50
51SEE ALSO
52--------
53linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
new file mode 100644
index 000000000000..484080dd5b6f
--- /dev/null
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -0,0 +1,66 @@
1perf-stat(1)
2============
3
4NAME
5----
6perf-stat - Run a command and gather performance counter statistics
7
8SYNOPSIS
9--------
10[verse]
11'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] <command>
12'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] -- <command> [<options>]
13
14DESCRIPTION
15-----------
16This command runs a command and gathers performance counter statistics
17from it.
18
19
20OPTIONS
21-------
22<command>...::
23 Any command you can specify in a shell.
24
25
26-e::
27--event=::
28 Select the PMU event. Selection can be a symbolic event name
29 (use 'perf list' to list all events) or a raw PMU
30 event (eventsel+umask) in the form of rNNN where NNN is a
31 hexadecimal event descriptor.
32
33-i::
34--inherit::
35 child tasks inherit counters
36-p::
37--pid=<pid>::
38 stat events on existing pid
39
40-a::
41 system-wide collection
42
43-c::
44 scale counter values
45
46EXAMPLES
47--------
48
49$ perf stat -- make -j
50
51 Performance counter stats for 'make -j':
52
53 8117.370256 task clock ticks # 11.281 CPU utilization factor
54 678 context switches # 0.000 M/sec
55 133 CPU migrations # 0.000 M/sec
56 235724 pagefaults # 0.029 M/sec
57 24821162526 CPU cycles # 3057.784 M/sec
58 18687303457 instructions # 2302.138 M/sec
59 172158895 cache references # 21.209 M/sec
60 27075259 cache misses # 3.335 M/sec
61
62 Wall-clock time elapsed: 719.554352 msecs
63
64SEE ALSO
65--------
66linkperf:perf-top[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
new file mode 100644
index 000000000000..4a7d558dc309
--- /dev/null
+++ b/tools/perf/Documentation/perf-top.txt
@@ -0,0 +1,125 @@
1perf-top(1)
2===========
3
4NAME
5----
6perf-top - System profiling tool.
7
8SYNOPSIS
9--------
10[verse]
11'perf top' [-e <EVENT> | --event=EVENT] [<options>]
12
13DESCRIPTION
14-----------
15This command generates and displays a performance counter profile in realtime.
16
17
18OPTIONS
19-------
20-a::
21--all-cpus::
22 System-wide collection. (default)
23
24-c <count>::
25--count=<count>::
26 Event period to sample.
27
28-C <cpu>::
29--CPU=<cpu>::
30 CPU to profile.
31
32-d <seconds>::
33--delay=<seconds>::
34 Number of seconds to delay between refreshes.
35
36-e <event>::
37--event=<event>::
38 Select the PMU event. Selection can be a symbolic event name
39 (use 'perf list' to list all events) or a raw PMU
40 event (eventsel+umask) in the form of rNNN where NNN is a
41 hexadecimal event descriptor.
42
43-E <entries>::
44--entries=<entries>::
45 Display this many functions.
46
47-f <count>::
48--count-filter=<count>::
49 Only display functions with more events than this.
50
51-F <freq>::
52--freq=<freq>::
53 Profile at this frequency.
54
55-i::
56--inherit::
57 Child tasks inherit counters, only makes sens with -p option.
58
59-k <path>::
60--vmlinux=<path>::
61 Path to vmlinux. Required for annotation functionality.
62
63-m <pages>::
64--mmap-pages=<pages>::
65 Number of mmapped data pages.
66
67-p <pid>::
68--pid=<pid>::
69 Profile events on existing pid.
70
71-r <priority>::
72--realtime=<priority>::
73 Collect data with this RT SCHED_FIFO priority.
74
75-s <symbol>::
76--sym-annotate=<symbol>::
77 Annotate this symbol. Requires -k option.
78
79-v::
80--verbose::
81 Be more verbose (show counter open errors, etc).
82
83-z::
84--zero::
85 Zero history across display updates.
86
87INTERACTIVE PROMPTING KEYS
88--------------------------
89
90[d]::
91 Display refresh delay.
92
93[e]::
94 Number of entries to display.
95
96[E]::
97 Event to display when multiple counters are active.
98
99[f]::
100 Profile display filter (>= hit count).
101
102[F]::
103 Annotation display filter (>= % of total).
104
105[s]::
106 Annotate symbol.
107
108[S]::
109 Stop annotation, return to full profile display.
110
111[w]::
112 Toggle between weighted sum and individual count[E]r profile.
113
114[z]::
115 Toggle event count zeroing across display updates.
116
117[qQ]::
118 Quit.
119
120Pressing any unmapped key displays a menu, and prompts for input.
121
122
123SEE ALSO
124--------
125linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt
new file mode 100644
index 000000000000..69c832557199
--- /dev/null
+++ b/tools/perf/Documentation/perf.txt
@@ -0,0 +1,24 @@
1perf(1)
2=======
3
4NAME
5----
6perf - Performance analysis tools for Linux
7
8SYNOPSIS
9--------
10[verse]
11'perf' [--version] [--help] COMMAND [ARGS]
12
13DESCRIPTION
14-----------
15Performance counters for Linux are are a new kernel-based subsystem
16that provide a framework for all things performance analysis. It
17covers hardware level (CPU/PMU, Performance Monitoring Unit) features
18and software features (software counters, tracepoints) as well.
19
20SEE ALSO
21--------
22linkperf:perf-stat[1], linkperf:perf-top[1],
23linkperf:perf-record[1], linkperf:perf-report[1],
24linkperf:perf-list[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
new file mode 100644
index 000000000000..c045b4271e57
--- /dev/null
+++ b/tools/perf/Makefile
@@ -0,0 +1,973 @@
1# The default target of this Makefile is...
2all::
3
4# Define V=1 to have a more verbose compile.
5#
6# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
7# or vsnprintf() return -1 instead of number of characters which would
8# have been written to the final string if enough space had been available.
9#
10# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
11# when attempting to read from an fopen'ed directory.
12#
13# Define NO_OPENSSL environment variable if you do not have OpenSSL.
14# This also implies MOZILLA_SHA1.
15#
16# Define CURLDIR=/foo/bar if your curl header and library files are in
17# /foo/bar/include and /foo/bar/lib directories.
18#
19# Define EXPATDIR=/foo/bar if your expat header and library files are in
20# /foo/bar/include and /foo/bar/lib directories.
21#
22# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
23#
24# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
25# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
26#
27# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
28# do not support the 'size specifiers' introduced by C99, namely ll, hh,
29# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
30# some C compilers supported these specifiers prior to C99 as an extension.
31#
32# Define NO_STRCASESTR if you don't have strcasestr.
33#
34# Define NO_MEMMEM if you don't have memmem.
35#
36# Define NO_STRTOUMAX if you don't have strtoumax in the C library.
37# If your compiler also does not support long long or does not have
38# strtoull, define NO_STRTOULL.
39#
40# Define NO_SETENV if you don't have setenv in the C library.
41#
42# Define NO_UNSETENV if you don't have unsetenv in the C library.
43#
44# Define NO_MKDTEMP if you don't have mkdtemp in the C library.
45#
46# Define NO_SYS_SELECT_H if you don't have sys/select.h.
47#
48# Define NO_SYMLINK_HEAD if you never want .perf/HEAD to be a symbolic link.
49# Enable it on Windows. By default, symrefs are still used.
50#
51# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
52# tests. These tests take up a significant amount of the total test time
53# but are not needed unless you plan to talk to SVN repos.
54#
55# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
56# installed in /sw, but don't want PERF to link against any libraries
57# installed there. If defined you may specify your own (or Fink's)
58# include directories and library directories by defining CFLAGS
59# and LDFLAGS appropriately.
60#
61# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
62# have DarwinPorts installed in /opt/local, but don't want PERF to
63# link against any libraries installed there. If defined you may
64# specify your own (or DarwinPort's) include directories and
65# library directories by defining CFLAGS and LDFLAGS appropriately.
66#
67# Define PPC_SHA1 environment variable when running make to make use of
68# a bundled SHA1 routine optimized for PowerPC.
69#
70# Define ARM_SHA1 environment variable when running make to make use of
71# a bundled SHA1 routine optimized for ARM.
72#
73# Define MOZILLA_SHA1 environment variable when running make to make use of
74# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
75# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
76# choice) has very fast version optimized for i586.
77#
78# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
79#
80# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
81#
82# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
83# Patrick Mauritz).
84#
85# Define NO_MMAP if you want to avoid mmap.
86#
87# Define NO_PTHREADS if you do not have or do not want to use Pthreads.
88#
89# Define NO_PREAD if you have a problem with pread() system call (e.g.
90# cygwin.dll before v1.5.22).
91#
92# Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
93# generally faster on your platform than accessing the working directory.
94#
95# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
96# the executable mode bit, but doesn't really do so.
97#
98# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
99#
100# Define NO_SOCKADDR_STORAGE if your platform does not have struct
101# sockaddr_storage.
102#
103# Define NO_ICONV if your libc does not properly support iconv.
104#
105# Define OLD_ICONV if your library has an old iconv(), where the second
106# (input buffer pointer) parameter is declared with type (const char **).
107#
108# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
109#
110# Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib"
111# that tells runtime paths to dynamic libraries;
112# "-Wl,-rpath=/path/lib" is used instead.
113#
114# Define USE_NSEC below if you want perf to care about sub-second file mtimes
115# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
116# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
117# randomly break unless your underlying filesystem supports those sub-second
118# times (my ext3 doesn't).
119#
120# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
121# "st_ctim"
122#
123# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
124# available. This automatically turns USE_NSEC off.
125#
126# Define USE_STDEV below if you want perf to care about the underlying device
127# change being considered an inode change from the update-index perspective.
128#
129# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
130# field that counts the on-disk footprint in 512-byte blocks.
131#
132# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
133#
134# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
135#
136# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
137# MakeMaker (e.g. using ActiveState under Cygwin).
138#
139# Define NO_PERL if you do not want Perl scripts or libraries at all.
140#
141# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
142# is a simplified version of the merge sort used in glibc. This is
143# recommended if Git triggers O(n^2) behavior in your platform's qsort().
144#
145# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call
146# your external grep (e.g., if your system lacks grep, if its grep is
147# broken, or spawning external process is slower than built-in grep perf has).
148
149PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
150 @$(SHELL_PATH) util/PERF-VERSION-GEN
151-include PERF-VERSION-FILE
152
153uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
154uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
155uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
156uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
157uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
158uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
159
160# If we're on a 64-bit kernel, use -m64
161ifndef NO_64BIT
162 ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
163 M64 := -m64
164 endif
165endif
166
167# CFLAGS and LDFLAGS are for the users to override from the command line.
168
169CFLAGS = $(M64) -ggdb3 -Wall -Wextra -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6
170LDFLAGS = -lpthread -lrt -lelf -lm
171ALL_CFLAGS = $(CFLAGS)
172ALL_LDFLAGS = $(LDFLAGS)
173STRIP ?= strip
174
175# Among the variables below, these:
176# perfexecdir
177# template_dir
178# mandir
179# infodir
180# htmldir
181# ETC_PERFCONFIG (but not sysconfdir)
182# can be specified as a relative path some/where/else;
183# this is interpreted as relative to $(prefix) and "perf" at
184# runtime figures out where they are based on the path to the executable.
185# This can help installing the suite in a relocatable way.
186
187prefix = $(HOME)
188bindir_relative = bin
189bindir = $(prefix)/$(bindir_relative)
190mandir = share/man
191infodir = share/info
192perfexecdir = libexec/perf-core
193sharedir = $(prefix)/share
194template_dir = share/perf-core/templates
195htmldir = share/doc/perf-doc
196ifeq ($(prefix),/usr)
197sysconfdir = /etc
198ETC_PERFCONFIG = $(sysconfdir)/perfconfig
199else
200sysconfdir = $(prefix)/etc
201ETC_PERFCONFIG = etc/perfconfig
202endif
203lib = lib
204# DESTDIR=
205
206export prefix bindir sharedir sysconfdir
207
208CC = gcc
209AR = ar
210RM = rm -f
211TAR = tar
212FIND = find
213INSTALL = install
214RPMBUILD = rpmbuild
215PTHREAD_LIBS = -lpthread
216
217# sparse is architecture-neutral, which means that we need to tell it
218# explicitly what architecture to check for. Fix this up for yours..
219SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
220
221
222
223### --- END CONFIGURATION SECTION ---
224
225# Those must not be GNU-specific; they are shared with perl/ which may
226# be built by a different compiler. (Note that this is an artifact now
227# but it still might be nice to keep that distinction.)
228BASIC_CFLAGS = -Iutil/include
229BASIC_LDFLAGS =
230
231# Guard against environment variables
232BUILTIN_OBJS =
233BUILT_INS =
234COMPAT_CFLAGS =
235COMPAT_OBJS =
236LIB_H =
237LIB_OBJS =
238SCRIPT_PERL =
239SCRIPT_SH =
240TEST_PROGRAMS =
241
242#
243# No scripts right now:
244#
245
246# SCRIPT_SH += perf-am.sh
247
248#
249# No Perl scripts right now:
250#
251
252# SCRIPT_PERL += perf-add--interactive.perl
253
254SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
255 $(patsubst %.perl,%,$(SCRIPT_PERL))
256
257# Empty...
258EXTRA_PROGRAMS =
259
260# ... and all the rest that could be moved out of bindir to perfexecdir
261PROGRAMS += $(EXTRA_PROGRAMS)
262
263#
264# Single 'perf' binary right now:
265#
266PROGRAMS += perf
267
268# List built-in command $C whose implementation cmd_$C() is not in
269# builtin-$C.o but is linked in as part of some other command.
270#
271# None right now:
272#
273# BUILT_INS += perf-init $X
274
275# what 'all' will build and 'install' will install, in perfexecdir
276ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
277
278# what 'all' will build but not install in perfexecdir
279OTHER_PROGRAMS = perf$X
280
281# Set paths to tools early so that they can be used for version tests.
282ifndef SHELL_PATH
283 SHELL_PATH = /bin/sh
284endif
285ifndef PERL_PATH
286 PERL_PATH = /usr/bin/perl
287endif
288
289export PERL_PATH
290
291LIB_FILE=libperf.a
292
293LIB_H += ../../include/linux/perf_counter.h
294LIB_H += ../../include/linux/rbtree.h
295LIB_H += ../../include/linux/list.h
296LIB_H += util/include/linux/list.h
297LIB_H += perf.h
298LIB_H += util/types.h
299LIB_H += util/levenshtein.h
300LIB_H += util/parse-options.h
301LIB_H += util/parse-events.h
302LIB_H += util/quote.h
303LIB_H += util/util.h
304LIB_H += util/help.h
305LIB_H += util/strbuf.h
306LIB_H += util/string.h
307LIB_H += util/strlist.h
308LIB_H += util/run-command.h
309LIB_H += util/sigchain.h
310LIB_H += util/symbol.h
311LIB_H += util/module.h
312LIB_H += util/color.h
313
314LIB_OBJS += util/abspath.o
315LIB_OBJS += util/alias.o
316LIB_OBJS += util/config.o
317LIB_OBJS += util/ctype.o
318LIB_OBJS += util/environment.o
319LIB_OBJS += util/exec_cmd.o
320LIB_OBJS += util/help.o
321LIB_OBJS += util/levenshtein.o
322LIB_OBJS += util/parse-options.o
323LIB_OBJS += util/parse-events.o
324LIB_OBJS += util/path.o
325LIB_OBJS += util/rbtree.o
326LIB_OBJS += util/run-command.o
327LIB_OBJS += util/quote.o
328LIB_OBJS += util/strbuf.o
329LIB_OBJS += util/string.o
330LIB_OBJS += util/strlist.o
331LIB_OBJS += util/usage.o
332LIB_OBJS += util/wrapper.o
333LIB_OBJS += util/sigchain.o
334LIB_OBJS += util/symbol.o
335LIB_OBJS += util/module.o
336LIB_OBJS += util/color.o
337LIB_OBJS += util/pager.o
338LIB_OBJS += util/header.o
339LIB_OBJS += util/callchain.o
340
341BUILTIN_OBJS += builtin-annotate.o
342BUILTIN_OBJS += builtin-help.o
343BUILTIN_OBJS += builtin-list.o
344BUILTIN_OBJS += builtin-record.o
345BUILTIN_OBJS += builtin-report.o
346BUILTIN_OBJS += builtin-stat.o
347BUILTIN_OBJS += builtin-top.o
348
349PERFLIBS = $(LIB_FILE)
350
351#
352# Platform specific tweaks
353#
354
355# We choose to avoid "if .. else if .. else .. endif endif"
356# because maintaining the nesting to match is a pain. If
357# we had "elif" things would have been much nicer...
358
359-include config.mak.autogen
360-include config.mak
361
362ifeq ($(uname_S),Darwin)
363 ifndef NO_FINK
364 ifeq ($(shell test -d /sw/lib && echo y),y)
365 BASIC_CFLAGS += -I/sw/include
366 BASIC_LDFLAGS += -L/sw/lib
367 endif
368 endif
369 ifndef NO_DARWIN_PORTS
370 ifeq ($(shell test -d /opt/local/lib && echo y),y)
371 BASIC_CFLAGS += -I/opt/local/include
372 BASIC_LDFLAGS += -L/opt/local/lib
373 endif
374 endif
375 PTHREAD_LIBS =
376endif
377
378ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y)
379 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
380endif
381
382ifdef NO_DEMANGLE
383 BASIC_CFLAGS += -DNO_DEMANGLE
384else
385 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd > /dev/null 2>&1 && echo y")
386
387 ifeq ($(has_bfd),y)
388 EXTLIBS += -lbfd
389 else
390 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y")
391 ifeq ($(has_bfd_iberty),y)
392 EXTLIBS += -lbfd -liberty
393 else
394 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty -lz > /dev/null 2>&1 && echo y")
395 ifeq ($(has_bfd_iberty_z),y)
396 EXTLIBS += -lbfd -liberty -lz
397 else
398 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -liberty > /dev/null 2>&1 && echo y")
399 ifeq ($(has_cplus_demangle),y)
400 EXTLIBS += -liberty
401 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
402 else
403 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling)
404 BASIC_CFLAGS += -DNO_DEMANGLE
405 endif
406 endif
407 endif
408 endif
409endif
410
411ifndef CC_LD_DYNPATH
412 ifdef NO_R_TO_GCC_LINKER
413 # Some gcc does not accept and pass -R to the linker to specify
414 # the runtime dynamic library path.
415 CC_LD_DYNPATH = -Wl,-rpath,
416 else
417 CC_LD_DYNPATH = -R
418 endif
419endif
420
421ifdef NEEDS_SOCKET
422 EXTLIBS += -lsocket
423endif
424ifdef NEEDS_NSL
425 EXTLIBS += -lnsl
426endif
427ifdef NO_D_TYPE_IN_DIRENT
428 BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
429endif
430ifdef NO_D_INO_IN_DIRENT
431 BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
432endif
433ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
434 BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
435endif
436ifdef USE_NSEC
437 BASIC_CFLAGS += -DUSE_NSEC
438endif
439ifdef USE_ST_TIMESPEC
440 BASIC_CFLAGS += -DUSE_ST_TIMESPEC
441endif
442ifdef NO_NSEC
443 BASIC_CFLAGS += -DNO_NSEC
444endif
445ifdef NO_C99_FORMAT
446 BASIC_CFLAGS += -DNO_C99_FORMAT
447endif
448ifdef SNPRINTF_RETURNS_BOGUS
449 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
450 COMPAT_OBJS += compat/snprintf.o
451endif
452ifdef FREAD_READS_DIRECTORIES
453 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
454 COMPAT_OBJS += compat/fopen.o
455endif
456ifdef NO_SYMLINK_HEAD
457 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
458endif
459ifdef NO_STRCASESTR
460 COMPAT_CFLAGS += -DNO_STRCASESTR
461 COMPAT_OBJS += compat/strcasestr.o
462endif
463ifdef NO_STRTOUMAX
464 COMPAT_CFLAGS += -DNO_STRTOUMAX
465 COMPAT_OBJS += compat/strtoumax.o
466endif
467ifdef NO_STRTOULL
468 COMPAT_CFLAGS += -DNO_STRTOULL
469endif
470ifdef NO_SETENV
471 COMPAT_CFLAGS += -DNO_SETENV
472 COMPAT_OBJS += compat/setenv.o
473endif
474ifdef NO_MKDTEMP
475 COMPAT_CFLAGS += -DNO_MKDTEMP
476 COMPAT_OBJS += compat/mkdtemp.o
477endif
478ifdef NO_UNSETENV
479 COMPAT_CFLAGS += -DNO_UNSETENV
480 COMPAT_OBJS += compat/unsetenv.o
481endif
482ifdef NO_SYS_SELECT_H
483 BASIC_CFLAGS += -DNO_SYS_SELECT_H
484endif
485ifdef NO_MMAP
486 COMPAT_CFLAGS += -DNO_MMAP
487 COMPAT_OBJS += compat/mmap.o
488else
489 ifdef USE_WIN32_MMAP
490 COMPAT_CFLAGS += -DUSE_WIN32_MMAP
491 COMPAT_OBJS += compat/win32mmap.o
492 endif
493endif
494ifdef NO_PREAD
495 COMPAT_CFLAGS += -DNO_PREAD
496 COMPAT_OBJS += compat/pread.o
497endif
498ifdef NO_FAST_WORKING_DIRECTORY
499 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
500endif
501ifdef NO_TRUSTABLE_FILEMODE
502 BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
503endif
504ifdef NO_IPV6
505 BASIC_CFLAGS += -DNO_IPV6
506endif
507ifdef NO_UINTMAX_T
508 BASIC_CFLAGS += -Duintmax_t=uint32_t
509endif
510ifdef NO_SOCKADDR_STORAGE
511ifdef NO_IPV6
512 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
513else
514 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
515endif
516endif
517ifdef NO_INET_NTOP
518 LIB_OBJS += compat/inet_ntop.o
519endif
520ifdef NO_INET_PTON
521 LIB_OBJS += compat/inet_pton.o
522endif
523
524ifdef NO_ICONV
525 BASIC_CFLAGS += -DNO_ICONV
526endif
527
528ifdef OLD_ICONV
529 BASIC_CFLAGS += -DOLD_ICONV
530endif
531
532ifdef NO_DEFLATE_BOUND
533 BASIC_CFLAGS += -DNO_DEFLATE_BOUND
534endif
535
536ifdef PPC_SHA1
537 SHA1_HEADER = "ppc/sha1.h"
538 LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
539else
540ifdef ARM_SHA1
541 SHA1_HEADER = "arm/sha1.h"
542 LIB_OBJS += arm/sha1.o arm/sha1_arm.o
543else
544ifdef MOZILLA_SHA1
545 SHA1_HEADER = "mozilla-sha1/sha1.h"
546 LIB_OBJS += mozilla-sha1/sha1.o
547else
548 SHA1_HEADER = <openssl/sha.h>
549 EXTLIBS += $(LIB_4_CRYPTO)
550endif
551endif
552endif
553ifdef NO_PERL_MAKEMAKER
554 export NO_PERL_MAKEMAKER
555endif
556ifdef NO_HSTRERROR
557 COMPAT_CFLAGS += -DNO_HSTRERROR
558 COMPAT_OBJS += compat/hstrerror.o
559endif
560ifdef NO_MEMMEM
561 COMPAT_CFLAGS += -DNO_MEMMEM
562 COMPAT_OBJS += compat/memmem.o
563endif
564ifdef INTERNAL_QSORT
565 COMPAT_CFLAGS += -DINTERNAL_QSORT
566 COMPAT_OBJS += compat/qsort.o
567endif
568ifdef RUNTIME_PREFIX
569 COMPAT_CFLAGS += -DRUNTIME_PREFIX
570endif
571
572ifdef DIR_HAS_BSD_GROUP_SEMANTICS
573 COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
574endif
575ifdef NO_EXTERNAL_GREP
576 BASIC_CFLAGS += -DNO_EXTERNAL_GREP
577endif
578
579ifeq ($(PERL_PATH),)
580NO_PERL=NoThanks
581endif
582
583QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
584QUIET_SUBDIR1 =
585
586ifneq ($(findstring $(MAKEFLAGS),w),w)
587PRINT_DIR = --no-print-directory
588else # "make -w"
589NO_SUBDIR = :
590endif
591
592ifneq ($(findstring $(MAKEFLAGS),s),s)
593ifndef V
594 QUIET_CC = @echo ' ' CC $@;
595 QUIET_AR = @echo ' ' AR $@;
596 QUIET_LINK = @echo ' ' LINK $@;
597 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
598 QUIET_GEN = @echo ' ' GEN $@;
599 QUIET_SUBDIR0 = +@subdir=
600 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
601 $(MAKE) $(PRINT_DIR) -C $$subdir
602 export V
603 export QUIET_GEN
604 export QUIET_BUILT_IN
605endif
606endif
607
608ifdef ASCIIDOC8
609 export ASCIIDOC8
610endif
611
612# Shell quote (do not use $(call) to accommodate ancient setups);
613
614SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
615ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
616
617DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
618bindir_SQ = $(subst ','\'',$(bindir))
619bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
620mandir_SQ = $(subst ','\'',$(mandir))
621infodir_SQ = $(subst ','\'',$(infodir))
622perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
623template_dir_SQ = $(subst ','\'',$(template_dir))
624htmldir_SQ = $(subst ','\'',$(htmldir))
625prefix_SQ = $(subst ','\'',$(prefix))
626
627SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
628PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
629
630LIBS = $(PERFLIBS) $(EXTLIBS)
631
632BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
633 $(COMPAT_CFLAGS)
634LIB_OBJS += $(COMPAT_OBJS)
635
636ALL_CFLAGS += $(BASIC_CFLAGS)
637ALL_LDFLAGS += $(BASIC_LDFLAGS)
638
639export TAR INSTALL DESTDIR SHELL_PATH
640
641
642### Build rules
643
644SHELL = $(SHELL_PATH)
645
646all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS
647ifneq (,$X)
648 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
649endif
650
651all::
652
653please_set_SHELL_PATH_to_a_more_modern_shell:
654 @$$(:)
655
656shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
657
658strip: $(PROGRAMS) perf$X
659 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) perf$X
660
661perf.o: perf.c common-cmds.h PERF-CFLAGS
662 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
663 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
664 $(ALL_CFLAGS) -c $(filter %.c,$^)
665
666perf$X: perf.o $(BUILTIN_OBJS) $(PERFLIBS)
667 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ perf.o \
668 $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
669
670builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS
671 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
672 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
673 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
674 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
675
676$(BUILT_INS): perf$X
677 $(QUIET_BUILT_IN)$(RM) $@ && \
678 ln perf$X $@ 2>/dev/null || \
679 ln -s perf$X $@ 2>/dev/null || \
680 cp perf$X $@
681
682common-cmds.h: util/generate-cmdlist.sh command-list.txt
683
684common-cmds.h: $(wildcard Documentation/perf-*.txt)
685 $(QUIET_GEN)util/generate-cmdlist.sh > $@+ && mv $@+ $@
686
687$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
688 $(QUIET_GEN)$(RM) $@ $@+ && \
689 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
690 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
691 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
692 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
693 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
694 $@.sh >$@+ && \
695 chmod +x $@+ && \
696 mv $@+ $@
697
698configure: configure.ac
699 $(QUIET_GEN)$(RM) $@ $<+ && \
700 sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
701 $< > $<+ && \
702 autoconf -o $@ $<+ && \
703 $(RM) $<+
704
705# These can record PERF_VERSION
706perf.o perf.spec \
707 $(patsubst %.sh,%,$(SCRIPT_SH)) \
708 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
709 : PERF-VERSION-FILE
710
711%.o: %.c PERF-CFLAGS
712 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
713%.s: %.c PERF-CFLAGS
714 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
715%.o: %.S
716 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
717
718util/exec_cmd.o: util/exec_cmd.c PERF-CFLAGS
719 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
720 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
721 '-DBINDIR="$(bindir_relative_SQ)"' \
722 '-DPREFIX="$(prefix_SQ)"' \
723 $<
724
725builtin-init-db.o: builtin-init-db.c PERF-CFLAGS
726 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
727
728util/config.o: util/config.c PERF-CFLAGS
729 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
730
731util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
732 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
733
734perf-%$X: %.o $(PERFLIBS)
735 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
736
737$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
738$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
739builtin-revert.o wt-status.o: wt-status.h
740
741$(LIB_FILE): $(LIB_OBJS)
742 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
743
744doc:
745 $(MAKE) -C Documentation all
746
747man:
748 $(MAKE) -C Documentation man
749
750html:
751 $(MAKE) -C Documentation html
752
753info:
754 $(MAKE) -C Documentation info
755
756pdf:
757 $(MAKE) -C Documentation pdf
758
759TAGS:
760 $(RM) TAGS
761 $(FIND) . -name '*.[hcS]' -print | xargs etags -a
762
763tags:
764 $(RM) tags
765 $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
766
767cscope:
768 $(RM) cscope*
769 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
770
771### Detect prefix changes
772TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
773 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
774
775PERF-CFLAGS: .FORCE-PERF-CFLAGS
776 @FLAGS='$(TRACK_CFLAGS)'; \
777 if test x"$$FLAGS" != x"`cat PERF-CFLAGS 2>/dev/null`" ; then \
778 echo 1>&2 " * new build flags or prefix"; \
779 echo "$$FLAGS" >PERF-CFLAGS; \
780 fi
781
782# We need to apply sq twice, once to protect from the shell
783# that runs PERF-BUILD-OPTIONS, and then again to protect it
784# and the first level quoting from the shell that runs "echo".
785PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
786 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
787 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
788 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
789 @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
790
791### Testing rules
792
793#
794# None right now:
795#
796# TEST_PROGRAMS += test-something$X
797
798all:: $(TEST_PROGRAMS)
799
800# GNU make supports exporting all variables by "export" without parameters.
801# However, the environment gets quite big, and some programs have problems
802# with that.
803
804export NO_SVN_TESTS
805
806check: common-cmds.h
807 if sparse; \
808 then \
809 for i in *.c */*.c; \
810 do \
811 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
812 done; \
813 else \
814 echo 2>&1 "Did you mean 'make test'?"; \
815 exit 1; \
816 fi
817
818remove-dashes:
819 ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
820
821### Installation rules
822
823ifneq ($(filter /%,$(firstword $(template_dir))),)
824template_instdir = $(template_dir)
825else
826template_instdir = $(prefix)/$(template_dir)
827endif
828export template_instdir
829
830ifneq ($(filter /%,$(firstword $(perfexecdir))),)
831perfexec_instdir = $(perfexecdir)
832else
833perfexec_instdir = $(prefix)/$(perfexecdir)
834endif
835perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
836export perfexec_instdir
837
838install: all
839 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
840 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
841ifdef BUILT_INS
842 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
843 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
844ifneq (,$X)
845 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
846endif
847endif
848
849install-doc:
850 $(MAKE) -C Documentation install
851
852install-man:
853 $(MAKE) -C Documentation install-man
854
855install-html:
856 $(MAKE) -C Documentation install-html
857
858install-info:
859 $(MAKE) -C Documentation install-info
860
861install-pdf:
862 $(MAKE) -C Documentation install-pdf
863
864quick-install-doc:
865 $(MAKE) -C Documentation quick-install
866
867quick-install-man:
868 $(MAKE) -C Documentation quick-install-man
869
870quick-install-html:
871 $(MAKE) -C Documentation quick-install-html
872
873
874### Maintainer's dist rules
875#
876# None right now
877#
878#
879# perf.spec: perf.spec.in
880# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+
881# mv $@+ $@
882#
883# PERF_TARNAME=perf-$(PERF_VERSION)
884# dist: perf.spec perf-archive$(X) configure
885# ./perf-archive --format=tar \
886# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar
887# @mkdir -p $(PERF_TARNAME)
888# @cp perf.spec configure $(PERF_TARNAME)
889# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version
890# $(TAR) rf $(PERF_TARNAME).tar \
891# $(PERF_TARNAME)/perf.spec \
892# $(PERF_TARNAME)/configure \
893# $(PERF_TARNAME)/version
894# @$(RM) -r $(PERF_TARNAME)
895# gzip -f -9 $(PERF_TARNAME).tar
896#
897# htmldocs = perf-htmldocs-$(PERF_VERSION)
898# manpages = perf-manpages-$(PERF_VERSION)
899# dist-doc:
900# $(RM) -r .doc-tmp-dir
901# mkdir .doc-tmp-dir
902# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
903# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
904# gzip -n -9 -f $(htmldocs).tar
905# :
906# $(RM) -r .doc-tmp-dir
907# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
908# $(MAKE) -C Documentation DESTDIR=./ \
909# man1dir=../.doc-tmp-dir/man1 \
910# man5dir=../.doc-tmp-dir/man5 \
911# man7dir=../.doc-tmp-dir/man7 \
912# install
913# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
914# gzip -n -9 -f $(manpages).tar
915# $(RM) -r .doc-tmp-dir
916#
917# rpm: dist
918# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz
919
920### Cleaning rules
921
922distclean: clean
923# $(RM) configure
924
925clean:
926 $(RM) *.o */*.o $(LIB_FILE)
927 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
928 $(RM) $(TEST_PROGRAMS)
929 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
930 $(RM) -r autom4te.cache
931 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
932 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
933 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
934 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
935 $(MAKE) -C Documentation/ clean
936 $(RM) PERF-VERSION-FILE PERF-CFLAGS PERF-BUILD-OPTIONS
937
938.PHONY: all install clean strip
939.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
940.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
941.PHONY: .FORCE-PERF-BUILD-OPTIONS
942
943### Make sure built-ins do not have dups and listed in perf.c
944#
945check-builtins::
946 ./check-builtins.sh
947
948### Test suite coverage testing
949#
950# None right now
951#
952# .PHONY: coverage coverage-clean coverage-build coverage-report
953#
954# coverage:
955# $(MAKE) coverage-build
956# $(MAKE) coverage-report
957#
958# coverage-clean:
959# rm -f *.gcda *.gcno
960#
961# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
962# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
963#
964# coverage-build: coverage-clean
965# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
966# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
967# -j1 test
968#
969# coverage-report:
970# gcov -b *.c */*.c
971# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \
972# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
973# | tee coverage-untested-functions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
new file mode 100644
index 000000000000..5e17de984dc8
--- /dev/null
+++ b/tools/perf/builtin-annotate.c
@@ -0,0 +1,1505 @@
1/*
2 * builtin-annotate.c
3 *
4 * Builtin annotate command: Analyze the perf.data input file,
5 * look up and read DSOs and symbol information and display
6 * a histogram of results, along various sorting keys.
7 */
8#include "builtin.h"
9
10#include "util/util.h"
11
12#include "util/color.h"
13#include <linux/list.h>
14#include "util/cache.h"
15#include <linux/rbtree.h>
16#include "util/symbol.h"
17#include "util/string.h"
18
19#include "perf.h"
20
21#include "util/parse-options.h"
22#include "util/parse-events.h"
23
24#define SHOW_KERNEL 1
25#define SHOW_USER 2
26#define SHOW_HV 4
27
28static char const *input_name = "perf.data";
29static char *vmlinux = "vmlinux";
30
31static char default_sort_order[] = "comm,symbol";
32static char *sort_order = default_sort_order;
33
34static int force;
35static int input;
36static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
37
38static int dump_trace = 0;
39#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
40
41static int verbose;
42
43static int modules;
44
45static int full_paths;
46
47static int print_line;
48
49static unsigned long page_size;
50static unsigned long mmap_window = 32;
51
52struct ip_event {
53 struct perf_event_header header;
54 u64 ip;
55 u32 pid, tid;
56};
57
58struct mmap_event {
59 struct perf_event_header header;
60 u32 pid, tid;
61 u64 start;
62 u64 len;
63 u64 pgoff;
64 char filename[PATH_MAX];
65};
66
67struct comm_event {
68 struct perf_event_header header;
69 u32 pid, tid;
70 char comm[16];
71};
72
73struct fork_event {
74 struct perf_event_header header;
75 u32 pid, ppid;
76};
77
78typedef union event_union {
79 struct perf_event_header header;
80 struct ip_event ip;
81 struct mmap_event mmap;
82 struct comm_event comm;
83 struct fork_event fork;
84} event_t;
85
86
87struct sym_ext {
88 struct rb_node node;
89 double percent;
90 char *path;
91};
92
93static LIST_HEAD(dsos);
94static struct dso *kernel_dso;
95static struct dso *vdso;
96
97
98static void dsos__add(struct dso *dso)
99{
100 list_add_tail(&dso->node, &dsos);
101}
102
103static struct dso *dsos__find(const char *name)
104{
105 struct dso *pos;
106
107 list_for_each_entry(pos, &dsos, node)
108 if (strcmp(pos->name, name) == 0)
109 return pos;
110 return NULL;
111}
112
113static struct dso *dsos__findnew(const char *name)
114{
115 struct dso *dso = dsos__find(name);
116 int nr;
117
118 if (dso)
119 return dso;
120
121 dso = dso__new(name, 0);
122 if (!dso)
123 goto out_delete_dso;
124
125 nr = dso__load(dso, NULL, verbose);
126 if (nr < 0) {
127 if (verbose)
128 fprintf(stderr, "Failed to open: %s\n", name);
129 goto out_delete_dso;
130 }
131 if (!nr && verbose) {
132 fprintf(stderr,
133 "No symbols found in: %s, maybe install a debug package?\n",
134 name);
135 }
136
137 dsos__add(dso);
138
139 return dso;
140
141out_delete_dso:
142 dso__delete(dso);
143 return NULL;
144}
145
146static void dsos__fprintf(FILE *fp)
147{
148 struct dso *pos;
149
150 list_for_each_entry(pos, &dsos, node)
151 dso__fprintf(pos, fp);
152}
153
154static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
155{
156 return dso__find_symbol(dso, ip);
157}
158
159static int load_kernel(void)
160{
161 int err;
162
163 kernel_dso = dso__new("[kernel]", 0);
164 if (!kernel_dso)
165 return -1;
166
167 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
168 if (err <= 0) {
169 dso__delete(kernel_dso);
170 kernel_dso = NULL;
171 } else
172 dsos__add(kernel_dso);
173
174 vdso = dso__new("[vdso]", 0);
175 if (!vdso)
176 return -1;
177
178 vdso->find_symbol = vdso__find_symbol;
179
180 dsos__add(vdso);
181
182 return err;
183}
184
185struct map {
186 struct list_head node;
187 u64 start;
188 u64 end;
189 u64 pgoff;
190 u64 (*map_ip)(struct map *, u64);
191 struct dso *dso;
192};
193
194static u64 map__map_ip(struct map *map, u64 ip)
195{
196 return ip - map->start + map->pgoff;
197}
198
199static u64 vdso__map_ip(struct map *map __used, u64 ip)
200{
201 return ip;
202}
203
204static struct map *map__new(struct mmap_event *event)
205{
206 struct map *self = malloc(sizeof(*self));
207
208 if (self != NULL) {
209 const char *filename = event->filename;
210
211 self->start = event->start;
212 self->end = event->start + event->len;
213 self->pgoff = event->pgoff;
214
215 self->dso = dsos__findnew(filename);
216 if (self->dso == NULL)
217 goto out_delete;
218
219 if (self->dso == vdso)
220 self->map_ip = vdso__map_ip;
221 else
222 self->map_ip = map__map_ip;
223 }
224 return self;
225out_delete:
226 free(self);
227 return NULL;
228}
229
230static struct map *map__clone(struct map *self)
231{
232 struct map *map = malloc(sizeof(*self));
233
234 if (!map)
235 return NULL;
236
237 memcpy(map, self, sizeof(*self));
238
239 return map;
240}
241
242static int map__overlap(struct map *l, struct map *r)
243{
244 if (l->start > r->start) {
245 struct map *t = l;
246 l = r;
247 r = t;
248 }
249
250 if (l->end > r->start)
251 return 1;
252
253 return 0;
254}
255
256static size_t map__fprintf(struct map *self, FILE *fp)
257{
258 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
259 self->start, self->end, self->pgoff, self->dso->name);
260}
261
262
263struct thread {
264 struct rb_node rb_node;
265 struct list_head maps;
266 pid_t pid;
267 char *comm;
268};
269
270static struct thread *thread__new(pid_t pid)
271{
272 struct thread *self = malloc(sizeof(*self));
273
274 if (self != NULL) {
275 self->pid = pid;
276 self->comm = malloc(32);
277 if (self->comm)
278 snprintf(self->comm, 32, ":%d", self->pid);
279 INIT_LIST_HEAD(&self->maps);
280 }
281
282 return self;
283}
284
285static int thread__set_comm(struct thread *self, const char *comm)
286{
287 if (self->comm)
288 free(self->comm);
289 self->comm = strdup(comm);
290 return self->comm ? 0 : -ENOMEM;
291}
292
293static size_t thread__fprintf(struct thread *self, FILE *fp)
294{
295 struct map *pos;
296 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
297
298 list_for_each_entry(pos, &self->maps, node)
299 ret += map__fprintf(pos, fp);
300
301 return ret;
302}
303
304
305static struct rb_root threads;
306static struct thread *last_match;
307
308static struct thread *threads__findnew(pid_t pid)
309{
310 struct rb_node **p = &threads.rb_node;
311 struct rb_node *parent = NULL;
312 struct thread *th;
313
314 /*
315 * Font-end cache - PID lookups come in blocks,
316 * so most of the time we dont have to look up
317 * the full rbtree:
318 */
319 if (last_match && last_match->pid == pid)
320 return last_match;
321
322 while (*p != NULL) {
323 parent = *p;
324 th = rb_entry(parent, struct thread, rb_node);
325
326 if (th->pid == pid) {
327 last_match = th;
328 return th;
329 }
330
331 if (pid < th->pid)
332 p = &(*p)->rb_left;
333 else
334 p = &(*p)->rb_right;
335 }
336
337 th = thread__new(pid);
338 if (th != NULL) {
339 rb_link_node(&th->rb_node, parent, p);
340 rb_insert_color(&th->rb_node, &threads);
341 last_match = th;
342 }
343
344 return th;
345}
346
347static void thread__insert_map(struct thread *self, struct map *map)
348{
349 struct map *pos, *tmp;
350
351 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
352 if (map__overlap(pos, map)) {
353 list_del_init(&pos->node);
354 /* XXX leaks dsos */
355 free(pos);
356 }
357 }
358
359 list_add_tail(&map->node, &self->maps);
360}
361
362static int thread__fork(struct thread *self, struct thread *parent)
363{
364 struct map *map;
365
366 if (self->comm)
367 free(self->comm);
368 self->comm = strdup(parent->comm);
369 if (!self->comm)
370 return -ENOMEM;
371
372 list_for_each_entry(map, &parent->maps, node) {
373 struct map *new = map__clone(map);
374 if (!new)
375 return -ENOMEM;
376 thread__insert_map(self, new);
377 }
378
379 return 0;
380}
381
382static struct map *thread__find_map(struct thread *self, u64 ip)
383{
384 struct map *pos;
385
386 if (self == NULL)
387 return NULL;
388
389 list_for_each_entry(pos, &self->maps, node)
390 if (ip >= pos->start && ip <= pos->end)
391 return pos;
392
393 return NULL;
394}
395
396static size_t threads__fprintf(FILE *fp)
397{
398 size_t ret = 0;
399 struct rb_node *nd;
400
401 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
402 struct thread *pos = rb_entry(nd, struct thread, rb_node);
403
404 ret += thread__fprintf(pos, fp);
405 }
406
407 return ret;
408}
409
410/*
411 * histogram, sorted on item, collects counts
412 */
413
414static struct rb_root hist;
415
416struct hist_entry {
417 struct rb_node rb_node;
418
419 struct thread *thread;
420 struct map *map;
421 struct dso *dso;
422 struct symbol *sym;
423 u64 ip;
424 char level;
425
426 uint32_t count;
427};
428
429/*
430 * configurable sorting bits
431 */
432
433struct sort_entry {
434 struct list_head list;
435
436 char *header;
437
438 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
439 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
440 size_t (*print)(FILE *fp, struct hist_entry *);
441};
442
443/* --sort pid */
444
445static int64_t
446sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
447{
448 return right->thread->pid - left->thread->pid;
449}
450
451static size_t
452sort__thread_print(FILE *fp, struct hist_entry *self)
453{
454 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
455}
456
457static struct sort_entry sort_thread = {
458 .header = " Command: Pid",
459 .cmp = sort__thread_cmp,
460 .print = sort__thread_print,
461};
462
463/* --sort comm */
464
465static int64_t
466sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
467{
468 return right->thread->pid - left->thread->pid;
469}
470
471static int64_t
472sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
473{
474 char *comm_l = left->thread->comm;
475 char *comm_r = right->thread->comm;
476
477 if (!comm_l || !comm_r) {
478 if (!comm_l && !comm_r)
479 return 0;
480 else if (!comm_l)
481 return -1;
482 else
483 return 1;
484 }
485
486 return strcmp(comm_l, comm_r);
487}
488
489static size_t
490sort__comm_print(FILE *fp, struct hist_entry *self)
491{
492 return fprintf(fp, "%16s", self->thread->comm);
493}
494
495static struct sort_entry sort_comm = {
496 .header = " Command",
497 .cmp = sort__comm_cmp,
498 .collapse = sort__comm_collapse,
499 .print = sort__comm_print,
500};
501
502/* --sort dso */
503
504static int64_t
505sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
506{
507 struct dso *dso_l = left->dso;
508 struct dso *dso_r = right->dso;
509
510 if (!dso_l || !dso_r) {
511 if (!dso_l && !dso_r)
512 return 0;
513 else if (!dso_l)
514 return -1;
515 else
516 return 1;
517 }
518
519 return strcmp(dso_l->name, dso_r->name);
520}
521
522static size_t
523sort__dso_print(FILE *fp, struct hist_entry *self)
524{
525 if (self->dso)
526 return fprintf(fp, "%-25s", self->dso->name);
527
528 return fprintf(fp, "%016llx ", (u64)self->ip);
529}
530
531static struct sort_entry sort_dso = {
532 .header = "Shared Object ",
533 .cmp = sort__dso_cmp,
534 .print = sort__dso_print,
535};
536
537/* --sort symbol */
538
539static int64_t
540sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
541{
542 u64 ip_l, ip_r;
543
544 if (left->sym == right->sym)
545 return 0;
546
547 ip_l = left->sym ? left->sym->start : left->ip;
548 ip_r = right->sym ? right->sym->start : right->ip;
549
550 return (int64_t)(ip_r - ip_l);
551}
552
553static size_t
554sort__sym_print(FILE *fp, struct hist_entry *self)
555{
556 size_t ret = 0;
557
558 if (verbose)
559 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
560
561 if (self->sym) {
562 ret += fprintf(fp, "[%c] %s",
563 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
564 } else {
565 ret += fprintf(fp, "%#016llx", (u64)self->ip);
566 }
567
568 return ret;
569}
570
571static struct sort_entry sort_sym = {
572 .header = "Symbol",
573 .cmp = sort__sym_cmp,
574 .print = sort__sym_print,
575};
576
577static int sort__need_collapse = 0;
578
579struct sort_dimension {
580 char *name;
581 struct sort_entry *entry;
582 int taken;
583};
584
585static struct sort_dimension sort_dimensions[] = {
586 { .name = "pid", .entry = &sort_thread, },
587 { .name = "comm", .entry = &sort_comm, },
588 { .name = "dso", .entry = &sort_dso, },
589 { .name = "symbol", .entry = &sort_sym, },
590};
591
592static LIST_HEAD(hist_entry__sort_list);
593
594static int sort_dimension__add(char *tok)
595{
596 unsigned int i;
597
598 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
599 struct sort_dimension *sd = &sort_dimensions[i];
600
601 if (sd->taken)
602 continue;
603
604 if (strncasecmp(tok, sd->name, strlen(tok)))
605 continue;
606
607 if (sd->entry->collapse)
608 sort__need_collapse = 1;
609
610 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
611 sd->taken = 1;
612
613 return 0;
614 }
615
616 return -ESRCH;
617}
618
619static int64_t
620hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
621{
622 struct sort_entry *se;
623 int64_t cmp = 0;
624
625 list_for_each_entry(se, &hist_entry__sort_list, list) {
626 cmp = se->cmp(left, right);
627 if (cmp)
628 break;
629 }
630
631 return cmp;
632}
633
634static int64_t
635hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
636{
637 struct sort_entry *se;
638 int64_t cmp = 0;
639
640 list_for_each_entry(se, &hist_entry__sort_list, list) {
641 int64_t (*f)(struct hist_entry *, struct hist_entry *);
642
643 f = se->collapse ?: se->cmp;
644
645 cmp = f(left, right);
646 if (cmp)
647 break;
648 }
649
650 return cmp;
651}
652
653/*
654 * collect histogram counts
655 */
656static void hist_hit(struct hist_entry *he, u64 ip)
657{
658 unsigned int sym_size, offset;
659 struct symbol *sym = he->sym;
660
661 he->count++;
662
663 if (!sym || !sym->hist)
664 return;
665
666 sym_size = sym->end - sym->start;
667 offset = ip - sym->start;
668
669 if (offset >= sym_size)
670 return;
671
672 sym->hist_sum++;
673 sym->hist[offset]++;
674
675 if (verbose >= 3)
676 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
677 (void *)(unsigned long)he->sym->start,
678 he->sym->name,
679 (void *)(unsigned long)ip, ip - he->sym->start,
680 sym->hist[offset]);
681}
682
683static int
684hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
685 struct symbol *sym, u64 ip, char level)
686{
687 struct rb_node **p = &hist.rb_node;
688 struct rb_node *parent = NULL;
689 struct hist_entry *he;
690 struct hist_entry entry = {
691 .thread = thread,
692 .map = map,
693 .dso = dso,
694 .sym = sym,
695 .ip = ip,
696 .level = level,
697 .count = 1,
698 };
699 int cmp;
700
701 while (*p != NULL) {
702 parent = *p;
703 he = rb_entry(parent, struct hist_entry, rb_node);
704
705 cmp = hist_entry__cmp(&entry, he);
706
707 if (!cmp) {
708 hist_hit(he, ip);
709
710 return 0;
711 }
712
713 if (cmp < 0)
714 p = &(*p)->rb_left;
715 else
716 p = &(*p)->rb_right;
717 }
718
719 he = malloc(sizeof(*he));
720 if (!he)
721 return -ENOMEM;
722 *he = entry;
723 rb_link_node(&he->rb_node, parent, p);
724 rb_insert_color(&he->rb_node, &hist);
725
726 return 0;
727}
728
729static void hist_entry__free(struct hist_entry *he)
730{
731 free(he);
732}
733
734/*
735 * collapse the histogram
736 */
737
738static struct rb_root collapse_hists;
739
740static void collapse__insert_entry(struct hist_entry *he)
741{
742 struct rb_node **p = &collapse_hists.rb_node;
743 struct rb_node *parent = NULL;
744 struct hist_entry *iter;
745 int64_t cmp;
746
747 while (*p != NULL) {
748 parent = *p;
749 iter = rb_entry(parent, struct hist_entry, rb_node);
750
751 cmp = hist_entry__collapse(iter, he);
752
753 if (!cmp) {
754 iter->count += he->count;
755 hist_entry__free(he);
756 return;
757 }
758
759 if (cmp < 0)
760 p = &(*p)->rb_left;
761 else
762 p = &(*p)->rb_right;
763 }
764
765 rb_link_node(&he->rb_node, parent, p);
766 rb_insert_color(&he->rb_node, &collapse_hists);
767}
768
769static void collapse__resort(void)
770{
771 struct rb_node *next;
772 struct hist_entry *n;
773
774 if (!sort__need_collapse)
775 return;
776
777 next = rb_first(&hist);
778 while (next) {
779 n = rb_entry(next, struct hist_entry, rb_node);
780 next = rb_next(&n->rb_node);
781
782 rb_erase(&n->rb_node, &hist);
783 collapse__insert_entry(n);
784 }
785}
786
787/*
788 * reverse the map, sort on count.
789 */
790
791static struct rb_root output_hists;
792
793static void output__insert_entry(struct hist_entry *he)
794{
795 struct rb_node **p = &output_hists.rb_node;
796 struct rb_node *parent = NULL;
797 struct hist_entry *iter;
798
799 while (*p != NULL) {
800 parent = *p;
801 iter = rb_entry(parent, struct hist_entry, rb_node);
802
803 if (he->count > iter->count)
804 p = &(*p)->rb_left;
805 else
806 p = &(*p)->rb_right;
807 }
808
809 rb_link_node(&he->rb_node, parent, p);
810 rb_insert_color(&he->rb_node, &output_hists);
811}
812
813static void output__resort(void)
814{
815 struct rb_node *next;
816 struct hist_entry *n;
817 struct rb_root *tree = &hist;
818
819 if (sort__need_collapse)
820 tree = &collapse_hists;
821
822 next = rb_first(tree);
823
824 while (next) {
825 n = rb_entry(next, struct hist_entry, rb_node);
826 next = rb_next(&n->rb_node);
827
828 rb_erase(&n->rb_node, tree);
829 output__insert_entry(n);
830 }
831}
832
833static void register_idle_thread(void)
834{
835 struct thread *thread = threads__findnew(0);
836
837 if (thread == NULL ||
838 thread__set_comm(thread, "[idle]")) {
839 fprintf(stderr, "problem inserting idle task.\n");
840 exit(-1);
841 }
842}
843
844static unsigned long total = 0,
845 total_mmap = 0,
846 total_comm = 0,
847 total_fork = 0,
848 total_unknown = 0;
849
850static int
851process_sample_event(event_t *event, unsigned long offset, unsigned long head)
852{
853 char level;
854 int show = 0;
855 struct dso *dso = NULL;
856 struct thread *thread = threads__findnew(event->ip.pid);
857 u64 ip = event->ip.ip;
858 struct map *map = NULL;
859
860 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
861 (void *)(offset + head),
862 (void *)(long)(event->header.size),
863 event->header.misc,
864 event->ip.pid,
865 (void *)(long)ip);
866
867 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
868
869 if (thread == NULL) {
870 fprintf(stderr, "problem processing %d event, skipping it.\n",
871 event->header.type);
872 return -1;
873 }
874
875 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
876 show = SHOW_KERNEL;
877 level = 'k';
878
879 dso = kernel_dso;
880
881 dprintf(" ...... dso: %s\n", dso->name);
882
883 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
884
885 show = SHOW_USER;
886 level = '.';
887
888 map = thread__find_map(thread, ip);
889 if (map != NULL) {
890 ip = map->map_ip(map, ip);
891 dso = map->dso;
892 } else {
893 /*
894 * If this is outside of all known maps,
895 * and is a negative address, try to look it
896 * up in the kernel dso, as it might be a
897 * vsyscall (which executes in user-mode):
898 */
899 if ((long long)ip < 0)
900 dso = kernel_dso;
901 }
902 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
903
904 } else {
905 show = SHOW_HV;
906 level = 'H';
907 dprintf(" ...... dso: [hypervisor]\n");
908 }
909
910 if (show & show_mask) {
911 struct symbol *sym = NULL;
912
913 if (dso)
914 sym = dso->find_symbol(dso, ip);
915
916 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
917 fprintf(stderr,
918 "problem incrementing symbol count, skipping event\n");
919 return -1;
920 }
921 }
922 total++;
923
924 return 0;
925}
926
927static int
928process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
929{
930 struct thread *thread = threads__findnew(event->mmap.pid);
931 struct map *map = map__new(&event->mmap);
932
933 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
934 (void *)(offset + head),
935 (void *)(long)(event->header.size),
936 event->mmap.pid,
937 (void *)(long)event->mmap.start,
938 (void *)(long)event->mmap.len,
939 (void *)(long)event->mmap.pgoff,
940 event->mmap.filename);
941
942 if (thread == NULL || map == NULL) {
943 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
944 return 0;
945 }
946
947 thread__insert_map(thread, map);
948 total_mmap++;
949
950 return 0;
951}
952
953static int
954process_comm_event(event_t *event, unsigned long offset, unsigned long head)
955{
956 struct thread *thread = threads__findnew(event->comm.pid);
957
958 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
959 (void *)(offset + head),
960 (void *)(long)(event->header.size),
961 event->comm.comm, event->comm.pid);
962
963 if (thread == NULL ||
964 thread__set_comm(thread, event->comm.comm)) {
965 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
966 return -1;
967 }
968 total_comm++;
969
970 return 0;
971}
972
973static int
974process_fork_event(event_t *event, unsigned long offset, unsigned long head)
975{
976 struct thread *thread = threads__findnew(event->fork.pid);
977 struct thread *parent = threads__findnew(event->fork.ppid);
978
979 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n",
980 (void *)(offset + head),
981 (void *)(long)(event->header.size),
982 event->fork.pid, event->fork.ppid);
983
984 /*
985 * A thread clone will have the same PID for both
986 * parent and child.
987 */
988 if (thread == parent)
989 return 0;
990
991 if (!thread || !parent || thread__fork(thread, parent)) {
992 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
993 return -1;
994 }
995 total_fork++;
996
997 return 0;
998}
999
1000static int
1001process_event(event_t *event, unsigned long offset, unsigned long head)
1002{
1003 switch (event->header.type) {
1004 case PERF_EVENT_SAMPLE:
1005 return process_sample_event(event, offset, head);
1006
1007 case PERF_EVENT_MMAP:
1008 return process_mmap_event(event, offset, head);
1009
1010 case PERF_EVENT_COMM:
1011 return process_comm_event(event, offset, head);
1012
1013 case PERF_EVENT_FORK:
1014 return process_fork_event(event, offset, head);
1015 /*
1016 * We dont process them right now but they are fine:
1017 */
1018
1019 case PERF_EVENT_THROTTLE:
1020 case PERF_EVENT_UNTHROTTLE:
1021 return 0;
1022
1023 default:
1024 return -1;
1025 }
1026
1027 return 0;
1028}
1029
1030static int
1031parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1032{
1033 char *line = NULL, *tmp, *tmp2;
1034 static const char *prev_line;
1035 static const char *prev_color;
1036 unsigned int offset;
1037 size_t line_len;
1038 s64 line_ip;
1039 int ret;
1040 char *c;
1041
1042 if (getline(&line, &line_len, file) < 0)
1043 return -1;
1044 if (!line)
1045 return -1;
1046
1047 c = strchr(line, '\n');
1048 if (c)
1049 *c = 0;
1050
1051 line_ip = -1;
1052 offset = 0;
1053 ret = -2;
1054
1055 /*
1056 * Strip leading spaces:
1057 */
1058 tmp = line;
1059 while (*tmp) {
1060 if (*tmp != ' ')
1061 break;
1062 tmp++;
1063 }
1064
1065 if (*tmp) {
1066 /*
1067 * Parse hexa addresses followed by ':'
1068 */
1069 line_ip = strtoull(tmp, &tmp2, 16);
1070 if (*tmp2 != ':')
1071 line_ip = -1;
1072 }
1073
1074 if (line_ip != -1) {
1075 const char *path = NULL;
1076 unsigned int hits = 0;
1077 double percent = 0.0;
1078 char *color;
1079 struct sym_ext *sym_ext = sym->priv;
1080
1081 offset = line_ip - start;
1082 if (offset < len)
1083 hits = sym->hist[offset];
1084
1085 if (offset < len && sym_ext) {
1086 path = sym_ext[offset].path;
1087 percent = sym_ext[offset].percent;
1088 } else if (sym->hist_sum)
1089 percent = 100.0 * hits / sym->hist_sum;
1090
1091 color = get_percent_color(percent);
1092
1093 /*
1094 * Also color the filename and line if needed, with
1095 * the same color than the percentage. Don't print it
1096 * twice for close colored ip with the same filename:line
1097 */
1098 if (path) {
1099 if (!prev_line || strcmp(prev_line, path)
1100 || color != prev_color) {
1101 color_fprintf(stdout, color, " %s", path);
1102 prev_line = path;
1103 prev_color = color;
1104 }
1105 }
1106
1107 color_fprintf(stdout, color, " %7.2f", percent);
1108 printf(" : ");
1109 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line);
1110 } else {
1111 if (!*line)
1112 printf(" :\n");
1113 else
1114 printf(" : %s\n", line);
1115 }
1116
1117 return 0;
1118}
1119
1120static struct rb_root root_sym_ext;
1121
1122static void insert_source_line(struct sym_ext *sym_ext)
1123{
1124 struct sym_ext *iter;
1125 struct rb_node **p = &root_sym_ext.rb_node;
1126 struct rb_node *parent = NULL;
1127
1128 while (*p != NULL) {
1129 parent = *p;
1130 iter = rb_entry(parent, struct sym_ext, node);
1131
1132 if (sym_ext->percent > iter->percent)
1133 p = &(*p)->rb_left;
1134 else
1135 p = &(*p)->rb_right;
1136 }
1137
1138 rb_link_node(&sym_ext->node, parent, p);
1139 rb_insert_color(&sym_ext->node, &root_sym_ext);
1140}
1141
1142static void free_source_line(struct symbol *sym, int len)
1143{
1144 struct sym_ext *sym_ext = sym->priv;
1145 int i;
1146
1147 if (!sym_ext)
1148 return;
1149
1150 for (i = 0; i < len; i++)
1151 free(sym_ext[i].path);
1152 free(sym_ext);
1153
1154 sym->priv = NULL;
1155 root_sym_ext = RB_ROOT;
1156}
1157
1158/* Get the filename:line for the colored entries */
1159static void
1160get_source_line(struct symbol *sym, u64 start, int len, char *filename)
1161{
1162 int i;
1163 char cmd[PATH_MAX * 2];
1164 struct sym_ext *sym_ext;
1165
1166 if (!sym->hist_sum)
1167 return;
1168
1169 sym->priv = calloc(len, sizeof(struct sym_ext));
1170 if (!sym->priv)
1171 return;
1172
1173 sym_ext = sym->priv;
1174
1175 for (i = 0; i < len; i++) {
1176 char *path = NULL;
1177 size_t line_len;
1178 u64 offset;
1179 FILE *fp;
1180
1181 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
1182 if (sym_ext[i].percent <= 0.5)
1183 continue;
1184
1185 offset = start + i;
1186 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
1187 fp = popen(cmd, "r");
1188 if (!fp)
1189 continue;
1190
1191 if (getline(&path, &line_len, fp) < 0 || !line_len)
1192 goto next;
1193
1194 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
1195 if (!sym_ext[i].path)
1196 goto next;
1197
1198 strcpy(sym_ext[i].path, path);
1199 insert_source_line(&sym_ext[i]);
1200
1201 next:
1202 pclose(fp);
1203 }
1204}
1205
1206static void print_summary(char *filename)
1207{
1208 struct sym_ext *sym_ext;
1209 struct rb_node *node;
1210
1211 printf("\nSorted summary for file %s\n", filename);
1212 printf("----------------------------------------------\n\n");
1213
1214 if (RB_EMPTY_ROOT(&root_sym_ext)) {
1215 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
1216 return;
1217 }
1218
1219 node = rb_first(&root_sym_ext);
1220 while (node) {
1221 double percent;
1222 char *color;
1223 char *path;
1224
1225 sym_ext = rb_entry(node, struct sym_ext, node);
1226 percent = sym_ext->percent;
1227 color = get_percent_color(percent);
1228 path = sym_ext->path;
1229
1230 color_fprintf(stdout, color, " %7.2f %s", percent, path);
1231 node = rb_next(node);
1232 }
1233}
1234
1235static void annotate_sym(struct dso *dso, struct symbol *sym)
1236{
1237 char *filename = dso->name, *d_filename;
1238 u64 start, end, len;
1239 char command[PATH_MAX*2];
1240 FILE *file;
1241
1242 if (!filename)
1243 return;
1244 if (sym->module)
1245 filename = sym->module->path;
1246 else if (dso == kernel_dso)
1247 filename = vmlinux;
1248
1249 start = sym->obj_start;
1250 if (!start)
1251 start = sym->start;
1252 if (full_paths)
1253 d_filename = filename;
1254 else
1255 d_filename = basename(filename);
1256
1257 end = start + sym->end - sym->start + 1;
1258 len = sym->end - sym->start;
1259
1260 if (print_line) {
1261 get_source_line(sym, start, len, filename);
1262 print_summary(filename);
1263 }
1264
1265 printf("\n\n------------------------------------------------\n");
1266 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
1267 printf("------------------------------------------------\n");
1268
1269 if (verbose >= 2)
1270 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1271
1272 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
1273 (u64)start, (u64)end, filename, filename);
1274
1275 if (verbose >= 3)
1276 printf("doing: %s\n", command);
1277
1278 file = popen(command, "r");
1279 if (!file)
1280 return;
1281
1282 while (!feof(file)) {
1283 if (parse_line(file, sym, start, len) < 0)
1284 break;
1285 }
1286
1287 pclose(file);
1288 if (print_line)
1289 free_source_line(sym, len);
1290}
1291
1292static void find_annotations(void)
1293{
1294 struct rb_node *nd;
1295 struct dso *dso;
1296 int count = 0;
1297
1298 list_for_each_entry(dso, &dsos, node) {
1299
1300 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
1301 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
1302
1303 if (sym->hist) {
1304 annotate_sym(dso, sym);
1305 count++;
1306 }
1307 }
1308 }
1309
1310 if (!count)
1311 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
1312}
1313
1314static int __cmd_annotate(void)
1315{
1316 int ret, rc = EXIT_FAILURE;
1317 unsigned long offset = 0;
1318 unsigned long head = 0;
1319 struct stat stat;
1320 event_t *event;
1321 uint32_t size;
1322 char *buf;
1323
1324 register_idle_thread();
1325
1326 input = open(input_name, O_RDONLY);
1327 if (input < 0) {
1328 perror("failed to open file");
1329 exit(-1);
1330 }
1331
1332 ret = fstat(input, &stat);
1333 if (ret < 0) {
1334 perror("failed to stat file");
1335 exit(-1);
1336 }
1337
1338 if (!force && (stat.st_uid != geteuid())) {
1339 fprintf(stderr, "file: %s not owned by current user\n", input_name);
1340 exit(-1);
1341 }
1342
1343 if (!stat.st_size) {
1344 fprintf(stderr, "zero-sized file, nothing to do!\n");
1345 exit(0);
1346 }
1347
1348 if (load_kernel() < 0) {
1349 perror("failed to load kernel symbols");
1350 return EXIT_FAILURE;
1351 }
1352
1353remap:
1354 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1355 MAP_SHARED, input, offset);
1356 if (buf == MAP_FAILED) {
1357 perror("failed to mmap file");
1358 exit(-1);
1359 }
1360
1361more:
1362 event = (event_t *)(buf + head);
1363
1364 size = event->header.size;
1365 if (!size)
1366 size = 8;
1367
1368 if (head + event->header.size >= page_size * mmap_window) {
1369 unsigned long shift = page_size * (head / page_size);
1370 int ret;
1371
1372 ret = munmap(buf, page_size * mmap_window);
1373 assert(ret == 0);
1374
1375 offset += shift;
1376 head -= shift;
1377 goto remap;
1378 }
1379
1380 size = event->header.size;
1381
1382 dprintf("%p [%p]: event: %d\n",
1383 (void *)(offset + head),
1384 (void *)(long)event->header.size,
1385 event->header.type);
1386
1387 if (!size || process_event(event, offset, head) < 0) {
1388
1389 dprintf("%p [%p]: skipping unknown header type: %d\n",
1390 (void *)(offset + head),
1391 (void *)(long)(event->header.size),
1392 event->header.type);
1393
1394 total_unknown++;
1395
1396 /*
1397 * assume we lost track of the stream, check alignment, and
1398 * increment a single u64 in the hope to catch on again 'soon'.
1399 */
1400
1401 if (unlikely(head & 7))
1402 head &= ~7ULL;
1403
1404 size = 8;
1405 }
1406
1407 head += size;
1408
1409 if (offset + head < (unsigned long)stat.st_size)
1410 goto more;
1411
1412 rc = EXIT_SUCCESS;
1413 close(input);
1414
1415 dprintf(" IP events: %10ld\n", total);
1416 dprintf(" mmap events: %10ld\n", total_mmap);
1417 dprintf(" comm events: %10ld\n", total_comm);
1418 dprintf(" fork events: %10ld\n", total_fork);
1419 dprintf(" unknown events: %10ld\n", total_unknown);
1420
1421 if (dump_trace)
1422 return 0;
1423
1424 if (verbose >= 3)
1425 threads__fprintf(stdout);
1426
1427 if (verbose >= 2)
1428 dsos__fprintf(stdout);
1429
1430 collapse__resort();
1431 output__resort();
1432
1433 find_annotations();
1434
1435 return rc;
1436}
1437
1438static const char * const annotate_usage[] = {
1439 "perf annotate [<options>] <command>",
1440 NULL
1441};
1442
1443static const struct option options[] = {
1444 OPT_STRING('i', "input", &input_name, "file",
1445 "input file name"),
1446 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
1447 "symbol to annotate"),
1448 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1449 OPT_BOOLEAN('v', "verbose", &verbose,
1450 "be more verbose (show symbol address, etc)"),
1451 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1452 "dump raw trace in ASCII"),
1453 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1454 OPT_BOOLEAN('m', "modules", &modules,
1455 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1456 OPT_BOOLEAN('l', "print-line", &print_line,
1457 "print matching source lines (may be slow)"),
1458 OPT_BOOLEAN('P', "full-paths", &full_paths,
1459 "Don't shorten the displayed pathnames"),
1460 OPT_END()
1461};
1462
1463static void setup_sorting(void)
1464{
1465 char *tmp, *tok, *str = strdup(sort_order);
1466
1467 for (tok = strtok_r(str, ", ", &tmp);
1468 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1469 if (sort_dimension__add(tok) < 0) {
1470 error("Unknown --sort key: `%s'", tok);
1471 usage_with_options(annotate_usage, options);
1472 }
1473 }
1474
1475 free(str);
1476}
1477
1478int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1479{
1480 symbol__init();
1481
1482 page_size = getpagesize();
1483
1484 argc = parse_options(argc, argv, options, annotate_usage, 0);
1485
1486 setup_sorting();
1487
1488 if (argc) {
1489 /*
1490 * Special case: if there's an argument left then assume tha
1491 * it's a symbol filter:
1492 */
1493 if (argc > 1)
1494 usage_with_options(annotate_usage, options);
1495
1496 sym_hist_filter = argv[0];
1497 }
1498
1499 if (!sym_hist_filter)
1500 usage_with_options(annotate_usage, options);
1501
1502 setup_pager();
1503
1504 return __cmd_annotate();
1505}
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
new file mode 100644
index 000000000000..2599d86a733b
--- /dev/null
+++ b/tools/perf/builtin-help.c
@@ -0,0 +1,463 @@
1/*
2 * builtin-help.c
3 *
4 * Builtin help command
5 */
6#include "perf.h"
7#include "util/cache.h"
8#include "builtin.h"
9#include "util/exec_cmd.h"
10#include "common-cmds.h"
11#include "util/parse-options.h"
12#include "util/run-command.h"
13#include "util/help.h"
14
15static struct man_viewer_list {
16 struct man_viewer_list *next;
17 char name[FLEX_ARRAY];
18} *man_viewer_list;
19
20static struct man_viewer_info_list {
21 struct man_viewer_info_list *next;
22 const char *info;
23 char name[FLEX_ARRAY];
24} *man_viewer_info_list;
25
26enum help_format {
27 HELP_FORMAT_MAN,
28 HELP_FORMAT_INFO,
29 HELP_FORMAT_WEB,
30};
31
32static int show_all = 0;
33static enum help_format help_format = HELP_FORMAT_MAN;
34static struct option builtin_help_options[] = {
35 OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
36 OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
37 OPT_SET_INT('w', "web", &help_format, "show manual in web browser",
38 HELP_FORMAT_WEB),
39 OPT_SET_INT('i', "info", &help_format, "show info page",
40 HELP_FORMAT_INFO),
41 OPT_END(),
42};
43
44static const char * const builtin_help_usage[] = {
45 "perf help [--all] [--man|--web|--info] [command]",
46 NULL
47};
48
49static enum help_format parse_help_format(const char *format)
50{
51 if (!strcmp(format, "man"))
52 return HELP_FORMAT_MAN;
53 if (!strcmp(format, "info"))
54 return HELP_FORMAT_INFO;
55 if (!strcmp(format, "web") || !strcmp(format, "html"))
56 return HELP_FORMAT_WEB;
57 die("unrecognized help format '%s'", format);
58}
59
60static const char *get_man_viewer_info(const char *name)
61{
62 struct man_viewer_info_list *viewer;
63
64 for (viewer = man_viewer_info_list; viewer; viewer = viewer->next)
65 {
66 if (!strcasecmp(name, viewer->name))
67 return viewer->info;
68 }
69 return NULL;
70}
71
72static int check_emacsclient_version(void)
73{
74 struct strbuf buffer = STRBUF_INIT;
75 struct child_process ec_process;
76 const char *argv_ec[] = { "emacsclient", "--version", NULL };
77 int version;
78
79 /* emacsclient prints its version number on stderr */
80 memset(&ec_process, 0, sizeof(ec_process));
81 ec_process.argv = argv_ec;
82 ec_process.err = -1;
83 ec_process.stdout_to_stderr = 1;
84 if (start_command(&ec_process)) {
85 fprintf(stderr, "Failed to start emacsclient.\n");
86 return -1;
87 }
88 strbuf_read(&buffer, ec_process.err, 20);
89 close(ec_process.err);
90
91 /*
92 * Don't bother checking return value, because "emacsclient --version"
93 * seems to always exits with code 1.
94 */
95 finish_command(&ec_process);
96
97 if (prefixcmp(buffer.buf, "emacsclient")) {
98 fprintf(stderr, "Failed to parse emacsclient version.\n");
99 strbuf_release(&buffer);
100 return -1;
101 }
102
103 strbuf_remove(&buffer, 0, strlen("emacsclient"));
104 version = atoi(buffer.buf);
105
106 if (version < 22) {
107 fprintf(stderr,
108 "emacsclient version '%d' too old (< 22).\n",
109 version);
110 strbuf_release(&buffer);
111 return -1;
112 }
113
114 strbuf_release(&buffer);
115 return 0;
116}
117
118static void exec_woman_emacs(const char* path, const char *page)
119{
120 if (!check_emacsclient_version()) {
121 /* This works only with emacsclient version >= 22. */
122 struct strbuf man_page = STRBUF_INIT;
123
124 if (!path)
125 path = "emacsclient";
126 strbuf_addf(&man_page, "(woman \"%s\")", page);
127 execlp(path, "emacsclient", "-e", man_page.buf, NULL);
128 warning("failed to exec '%s': %s", path, strerror(errno));
129 }
130}
131
132static void exec_man_konqueror(const char* path, const char *page)
133{
134 const char *display = getenv("DISPLAY");
135 if (display && *display) {
136 struct strbuf man_page = STRBUF_INIT;
137 const char *filename = "kfmclient";
138
139 /* It's simpler to launch konqueror using kfmclient. */
140 if (path) {
141 const char *file = strrchr(path, '/');
142 if (file && !strcmp(file + 1, "konqueror")) {
143 char *new = strdup(path);
144 char *dest = strrchr(new, '/');
145
146 /* strlen("konqueror") == strlen("kfmclient") */
147 strcpy(dest + 1, "kfmclient");
148 path = new;
149 }
150 if (file)
151 filename = file;
152 } else
153 path = "kfmclient";
154 strbuf_addf(&man_page, "man:%s(1)", page);
155 execlp(path, filename, "newTab", man_page.buf, NULL);
156 warning("failed to exec '%s': %s", path, strerror(errno));
157 }
158}
159
160static void exec_man_man(const char* path, const char *page)
161{
162 if (!path)
163 path = "man";
164 execlp(path, "man", page, NULL);
165 warning("failed to exec '%s': %s", path, strerror(errno));
166}
167
168static void exec_man_cmd(const char *cmd, const char *page)
169{
170 struct strbuf shell_cmd = STRBUF_INIT;
171 strbuf_addf(&shell_cmd, "%s %s", cmd, page);
172 execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
173 warning("failed to exec '%s': %s", cmd, strerror(errno));
174}
175
176static void add_man_viewer(const char *name)
177{
178 struct man_viewer_list **p = &man_viewer_list;
179 size_t len = strlen(name);
180
181 while (*p)
182 p = &((*p)->next);
183 *p = calloc(1, (sizeof(**p) + len + 1));
184 strncpy((*p)->name, name, len);
185}
186
187static int supported_man_viewer(const char *name, size_t len)
188{
189 return (!strncasecmp("man", name, len) ||
190 !strncasecmp("woman", name, len) ||
191 !strncasecmp("konqueror", name, len));
192}
193
194static void do_add_man_viewer_info(const char *name,
195 size_t len,
196 const char *value)
197{
198 struct man_viewer_info_list *new = calloc(1, sizeof(*new) + len + 1);
199
200 strncpy(new->name, name, len);
201 new->info = strdup(value);
202 new->next = man_viewer_info_list;
203 man_viewer_info_list = new;
204}
205
206static int add_man_viewer_path(const char *name,
207 size_t len,
208 const char *value)
209{
210 if (supported_man_viewer(name, len))
211 do_add_man_viewer_info(name, len, value);
212 else
213 warning("'%s': path for unsupported man viewer.\n"
214 "Please consider using 'man.<tool>.cmd' instead.",
215 name);
216
217 return 0;
218}
219
220static int add_man_viewer_cmd(const char *name,
221 size_t len,
222 const char *value)
223{
224 if (supported_man_viewer(name, len))
225 warning("'%s': cmd for supported man viewer.\n"
226 "Please consider using 'man.<tool>.path' instead.",
227 name);
228 else
229 do_add_man_viewer_info(name, len, value);
230
231 return 0;
232}
233
234static int add_man_viewer_info(const char *var, const char *value)
235{
236 const char *name = var + 4;
237 const char *subkey = strrchr(name, '.');
238
239 if (!subkey)
240 return error("Config with no key for man viewer: %s", name);
241
242 if (!strcmp(subkey, ".path")) {
243 if (!value)
244 return config_error_nonbool(var);
245 return add_man_viewer_path(name, subkey - name, value);
246 }
247 if (!strcmp(subkey, ".cmd")) {
248 if (!value)
249 return config_error_nonbool(var);
250 return add_man_viewer_cmd(name, subkey - name, value);
251 }
252
253 warning("'%s': unsupported man viewer sub key.", subkey);
254 return 0;
255}
256
257static int perf_help_config(const char *var, const char *value, void *cb)
258{
259 if (!strcmp(var, "help.format")) {
260 if (!value)
261 return config_error_nonbool(var);
262 help_format = parse_help_format(value);
263 return 0;
264 }
265 if (!strcmp(var, "man.viewer")) {
266 if (!value)
267 return config_error_nonbool(var);
268 add_man_viewer(value);
269 return 0;
270 }
271 if (!prefixcmp(var, "man."))
272 return add_man_viewer_info(var, value);
273
274 return perf_default_config(var, value, cb);
275}
276
277static struct cmdnames main_cmds, other_cmds;
278
279void list_common_cmds_help(void)
280{
281 unsigned int i, longest = 0;
282
283 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
284 if (longest < strlen(common_cmds[i].name))
285 longest = strlen(common_cmds[i].name);
286 }
287
288 puts(" The most commonly used perf commands are:");
289 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
290 printf(" %s ", common_cmds[i].name);
291 mput_char(' ', longest - strlen(common_cmds[i].name));
292 puts(common_cmds[i].help);
293 }
294}
295
296static int is_perf_command(const char *s)
297{
298 return is_in_cmdlist(&main_cmds, s) ||
299 is_in_cmdlist(&other_cmds, s);
300}
301
302static const char *prepend(const char *prefix, const char *cmd)
303{
304 size_t pre_len = strlen(prefix);
305 size_t cmd_len = strlen(cmd);
306 char *p = malloc(pre_len + cmd_len + 1);
307 memcpy(p, prefix, pre_len);
308 strcpy(p + pre_len, cmd);
309 return p;
310}
311
312static const char *cmd_to_page(const char *perf_cmd)
313{
314 if (!perf_cmd)
315 return "perf";
316 else if (!prefixcmp(perf_cmd, "perf"))
317 return perf_cmd;
318 else if (is_perf_command(perf_cmd))
319 return prepend("perf-", perf_cmd);
320 else
321 return prepend("perf-", perf_cmd);
322}
323
324static void setup_man_path(void)
325{
326 struct strbuf new_path = STRBUF_INIT;
327 const char *old_path = getenv("MANPATH");
328
329 /* We should always put ':' after our path. If there is no
330 * old_path, the ':' at the end will let 'man' to try
331 * system-wide paths after ours to find the manual page. If
332 * there is old_path, we need ':' as delimiter. */
333 strbuf_addstr(&new_path, system_path(PERF_MAN_PATH));
334 strbuf_addch(&new_path, ':');
335 if (old_path)
336 strbuf_addstr(&new_path, old_path);
337
338 setenv("MANPATH", new_path.buf, 1);
339
340 strbuf_release(&new_path);
341}
342
343static void exec_viewer(const char *name, const char *page)
344{
345 const char *info = get_man_viewer_info(name);
346
347 if (!strcasecmp(name, "man"))
348 exec_man_man(info, page);
349 else if (!strcasecmp(name, "woman"))
350 exec_woman_emacs(info, page);
351 else if (!strcasecmp(name, "konqueror"))
352 exec_man_konqueror(info, page);
353 else if (info)
354 exec_man_cmd(info, page);
355 else
356 warning("'%s': unknown man viewer.", name);
357}
358
359static void show_man_page(const char *perf_cmd)
360{
361 struct man_viewer_list *viewer;
362 const char *page = cmd_to_page(perf_cmd);
363 const char *fallback = getenv("PERF_MAN_VIEWER");
364
365 setup_man_path();
366 for (viewer = man_viewer_list; viewer; viewer = viewer->next)
367 {
368 exec_viewer(viewer->name, page); /* will return when unable */
369 }
370 if (fallback)
371 exec_viewer(fallback, page);
372 exec_viewer("man", page);
373 die("no man viewer handled the request");
374}
375
376static void show_info_page(const char *perf_cmd)
377{
378 const char *page = cmd_to_page(perf_cmd);
379 setenv("INFOPATH", system_path(PERF_INFO_PATH), 1);
380 execlp("info", "info", "perfman", page, NULL);
381}
382
383static void get_html_page_path(struct strbuf *page_path, const char *page)
384{
385 struct stat st;
386 const char *html_path = system_path(PERF_HTML_PATH);
387
388 /* Check that we have a perf documentation directory. */
389 if (stat(mkpath("%s/perf.html", html_path), &st)
390 || !S_ISREG(st.st_mode))
391 die("'%s': not a documentation directory.", html_path);
392
393 strbuf_init(page_path, 0);
394 strbuf_addf(page_path, "%s/%s.html", html_path, page);
395}
396
397/*
398 * If open_html is not defined in a platform-specific way (see for
399 * example compat/mingw.h), we use the script web--browse to display
400 * HTML.
401 */
402#ifndef open_html
403static void open_html(const char *path)
404{
405 execl_perf_cmd("web--browse", "-c", "help.browser", path, NULL);
406}
407#endif
408
409static void show_html_page(const char *perf_cmd)
410{
411 const char *page = cmd_to_page(perf_cmd);
412 struct strbuf page_path; /* it leaks but we exec bellow */
413
414 get_html_page_path(&page_path, page);
415
416 open_html(page_path.buf);
417}
418
419int cmd_help(int argc, const char **argv, const char *prefix __used)
420{
421 const char *alias;
422
423 load_command_list("perf-", &main_cmds, &other_cmds);
424
425 perf_config(perf_help_config, NULL);
426
427 argc = parse_options(argc, argv, builtin_help_options,
428 builtin_help_usage, 0);
429
430 if (show_all) {
431 printf("\n usage: %s\n\n", perf_usage_string);
432 list_commands("perf commands", &main_cmds, &other_cmds);
433 printf(" %s\n\n", perf_more_info_string);
434 return 0;
435 }
436
437 if (!argv[0]) {
438 printf("\n usage: %s\n\n", perf_usage_string);
439 list_common_cmds_help();
440 printf("\n %s\n\n", perf_more_info_string);
441 return 0;
442 }
443
444 alias = alias_lookup(argv[0]);
445 if (alias && !is_perf_command(argv[0])) {
446 printf("`perf %s' is aliased to `%s'\n", argv[0], alias);
447 return 0;
448 }
449
450 switch (help_format) {
451 case HELP_FORMAT_MAN:
452 show_man_page(argv[0]);
453 break;
454 case HELP_FORMAT_INFO:
455 show_info_page(argv[0]);
456 break;
457 case HELP_FORMAT_WEB:
458 show_html_page(argv[0]);
459 break;
460 }
461
462 return 0;
463}
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
new file mode 100644
index 000000000000..d88c6961274c
--- /dev/null
+++ b/tools/perf/builtin-list.c
@@ -0,0 +1,21 @@
1/*
2 * builtin-list.c
3 *
4 * Builtin list command: list all event types
5 *
6 * Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de>
7 * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
8 */
9#include "builtin.h"
10
11#include "perf.h"
12
13#include "util/parse-events.h"
14#include "util/cache.h"
15
16int cmd_list(int argc __used, const char **argv __used, const char *prefix __used)
17{
18 setup_pager();
19 print_events();
20 return 0;
21}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
new file mode 100644
index 000000000000..89a5ddcd1ded
--- /dev/null
+++ b/tools/perf/builtin-record.c
@@ -0,0 +1,712 @@
1/*
2 * builtin-record.c
3 *
4 * Builtin record command: Record the profile of a workload
5 * (or a CPU, or a PID) into the perf.data output file - for
6 * later analysis via perf report.
7 */
8#include "builtin.h"
9
10#include "perf.h"
11
12#include "util/util.h"
13#include "util/parse-options.h"
14#include "util/parse-events.h"
15#include "util/string.h"
16
17#include "util/header.h"
18
19#include <unistd.h>
20#include <sched.h>
21
22#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
23#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
24
25static int fd[MAX_NR_CPUS][MAX_COUNTERS];
26
27static long default_interval = 100000;
28
29static int nr_cpus = 0;
30static unsigned int page_size;
31static unsigned int mmap_pages = 128;
32static int freq = 0;
33static int output;
34static const char *output_name = "perf.data";
35static int group = 0;
36static unsigned int realtime_prio = 0;
37static int raw_samples = 0;
38static int system_wide = 0;
39static int profile_cpu = -1;
40static pid_t target_pid = -1;
41static int inherit = 1;
42static int force = 0;
43static int append_file = 0;
44static int call_graph = 0;
45static int verbose = 0;
46static int inherit_stat = 0;
47static int no_samples = 0;
48static int sample_address = 0;
49
50static long samples;
51static struct timeval last_read;
52static struct timeval this_read;
53
54static u64 bytes_written;
55
56static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
57
58static int nr_poll;
59static int nr_cpu;
60
61static int file_new = 1;
62
63struct perf_header *header;
64
65struct mmap_event {
66 struct perf_event_header header;
67 u32 pid;
68 u32 tid;
69 u64 start;
70 u64 len;
71 u64 pgoff;
72 char filename[PATH_MAX];
73};
74
75struct comm_event {
76 struct perf_event_header header;
77 u32 pid;
78 u32 tid;
79 char comm[16];
80};
81
82
83struct mmap_data {
84 int counter;
85 void *base;
86 unsigned int mask;
87 unsigned int prev;
88};
89
90static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
91
92static unsigned long mmap_read_head(struct mmap_data *md)
93{
94 struct perf_counter_mmap_page *pc = md->base;
95 long head;
96
97 head = pc->data_head;
98 rmb();
99
100 return head;
101}
102
103static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
104{
105 struct perf_counter_mmap_page *pc = md->base;
106
107 /*
108 * ensure all reads are done before we write the tail out.
109 */
110 /* mb(); */
111 pc->data_tail = tail;
112}
113
114static void write_output(void *buf, size_t size)
115{
116 while (size) {
117 int ret = write(output, buf, size);
118
119 if (ret < 0)
120 die("failed to write");
121
122 size -= ret;
123 buf += ret;
124
125 bytes_written += ret;
126 }
127}
128
129static void mmap_read(struct mmap_data *md)
130{
131 unsigned int head = mmap_read_head(md);
132 unsigned int old = md->prev;
133 unsigned char *data = md->base + page_size;
134 unsigned long size;
135 void *buf;
136 int diff;
137
138 gettimeofday(&this_read, NULL);
139
140 /*
141 * If we're further behind than half the buffer, there's a chance
142 * the writer will bite our tail and mess up the samples under us.
143 *
144 * If we somehow ended up ahead of the head, we got messed up.
145 *
146 * In either case, truncate and restart at head.
147 */
148 diff = head - old;
149 if (diff < 0) {
150 struct timeval iv;
151 unsigned long msecs;
152
153 timersub(&this_read, &last_read, &iv);
154 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
155
156 fprintf(stderr, "WARNING: failed to keep up with mmap data."
157 " Last read %lu msecs ago.\n", msecs);
158
159 /*
160 * head points to a known good entry, start there.
161 */
162 old = head;
163 }
164
165 last_read = this_read;
166
167 if (old != head)
168 samples++;
169
170 size = head - old;
171
172 if ((old & md->mask) + size != (head & md->mask)) {
173 buf = &data[old & md->mask];
174 size = md->mask + 1 - (old & md->mask);
175 old += size;
176
177 write_output(buf, size);
178 }
179
180 buf = &data[old & md->mask];
181 size = head - old;
182 old += size;
183
184 write_output(buf, size);
185
186 md->prev = old;
187 mmap_write_tail(md, old);
188}
189
190static volatile int done = 0;
191static volatile int signr = -1;
192
193static void sig_handler(int sig)
194{
195 done = 1;
196 signr = sig;
197}
198
199static void sig_atexit(void)
200{
201 if (signr == -1)
202 return;
203
204 signal(signr, SIG_DFL);
205 kill(getpid(), signr);
206}
207
208static pid_t pid_synthesize_comm_event(pid_t pid, int full)
209{
210 struct comm_event comm_ev;
211 char filename[PATH_MAX];
212 char bf[BUFSIZ];
213 FILE *fp;
214 size_t size = 0;
215 DIR *tasks;
216 struct dirent dirent, *next;
217 pid_t tgid = 0;
218
219 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
220
221 fp = fopen(filename, "r");
222 if (fp == NULL) {
223 /*
224 * We raced with a task exiting - just return:
225 */
226 if (verbose)
227 fprintf(stderr, "couldn't open %s\n", filename);
228 return 0;
229 }
230
231 memset(&comm_ev, 0, sizeof(comm_ev));
232 while (!comm_ev.comm[0] || !comm_ev.pid) {
233 if (fgets(bf, sizeof(bf), fp) == NULL)
234 goto out_failure;
235
236 if (memcmp(bf, "Name:", 5) == 0) {
237 char *name = bf + 5;
238 while (*name && isspace(*name))
239 ++name;
240 size = strlen(name) - 1;
241 memcpy(comm_ev.comm, name, size++);
242 } else if (memcmp(bf, "Tgid:", 5) == 0) {
243 char *tgids = bf + 5;
244 while (*tgids && isspace(*tgids))
245 ++tgids;
246 tgid = comm_ev.pid = atoi(tgids);
247 }
248 }
249
250 comm_ev.header.type = PERF_EVENT_COMM;
251 size = ALIGN(size, sizeof(u64));
252 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
253
254 if (!full) {
255 comm_ev.tid = pid;
256
257 write_output(&comm_ev, comm_ev.header.size);
258 goto out_fclose;
259 }
260
261 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
262
263 tasks = opendir(filename);
264 while (!readdir_r(tasks, &dirent, &next) && next) {
265 char *end;
266 pid = strtol(dirent.d_name, &end, 10);
267 if (*end)
268 continue;
269
270 comm_ev.tid = pid;
271
272 write_output(&comm_ev, comm_ev.header.size);
273 }
274 closedir(tasks);
275
276out_fclose:
277 fclose(fp);
278 return tgid;
279
280out_failure:
281 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
282 filename);
283 exit(EXIT_FAILURE);
284}
285
286static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
287{
288 char filename[PATH_MAX];
289 FILE *fp;
290
291 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
292
293 fp = fopen(filename, "r");
294 if (fp == NULL) {
295 /*
296 * We raced with a task exiting - just return:
297 */
298 if (verbose)
299 fprintf(stderr, "couldn't open %s\n", filename);
300 return;
301 }
302 while (1) {
303 char bf[BUFSIZ], *pbf = bf;
304 struct mmap_event mmap_ev = {
305 .header = { .type = PERF_EVENT_MMAP },
306 };
307 int n;
308 size_t size;
309 if (fgets(bf, sizeof(bf), fp) == NULL)
310 break;
311
312 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
313 n = hex2u64(pbf, &mmap_ev.start);
314 if (n < 0)
315 continue;
316 pbf += n + 1;
317 n = hex2u64(pbf, &mmap_ev.len);
318 if (n < 0)
319 continue;
320 pbf += n + 3;
321 if (*pbf == 'x') { /* vm_exec */
322 char *execname = strchr(bf, '/');
323
324 /* Catch VDSO */
325 if (execname == NULL)
326 execname = strstr(bf, "[vdso]");
327
328 if (execname == NULL)
329 continue;
330
331 size = strlen(execname);
332 execname[size - 1] = '\0'; /* Remove \n */
333 memcpy(mmap_ev.filename, execname, size);
334 size = ALIGN(size, sizeof(u64));
335 mmap_ev.len -= mmap_ev.start;
336 mmap_ev.header.size = (sizeof(mmap_ev) -
337 (sizeof(mmap_ev.filename) - size));
338 mmap_ev.pid = tgid;
339 mmap_ev.tid = pid;
340
341 write_output(&mmap_ev, mmap_ev.header.size);
342 }
343 }
344
345 fclose(fp);
346}
347
348static void synthesize_all(void)
349{
350 DIR *proc;
351 struct dirent dirent, *next;
352
353 proc = opendir("/proc");
354
355 while (!readdir_r(proc, &dirent, &next) && next) {
356 char *end;
357 pid_t pid, tgid;
358
359 pid = strtol(dirent.d_name, &end, 10);
360 if (*end) /* only interested in proper numerical dirents */
361 continue;
362
363 tgid = pid_synthesize_comm_event(pid, 1);
364 pid_synthesize_mmap_samples(pid, tgid);
365 }
366
367 closedir(proc);
368}
369
370static int group_fd;
371
372static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr)
373{
374 struct perf_header_attr *h_attr;
375
376 if (nr < header->attrs) {
377 h_attr = header->attr[nr];
378 } else {
379 h_attr = perf_header_attr__new(a);
380 perf_header__add_attr(header, h_attr);
381 }
382
383 return h_attr;
384}
385
386static void create_counter(int counter, int cpu, pid_t pid)
387{
388 struct perf_counter_attr *attr = attrs + counter;
389 struct perf_header_attr *h_attr;
390 int track = !counter; /* only the first counter needs these */
391 struct {
392 u64 count;
393 u64 time_enabled;
394 u64 time_running;
395 u64 id;
396 } read_data;
397
398 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
399 PERF_FORMAT_TOTAL_TIME_RUNNING |
400 PERF_FORMAT_ID;
401
402 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
403
404 if (freq) {
405 attr->sample_type |= PERF_SAMPLE_PERIOD;
406 attr->freq = 1;
407 attr->sample_freq = freq;
408 }
409
410 if (no_samples)
411 attr->sample_freq = 0;
412
413 if (inherit_stat)
414 attr->inherit_stat = 1;
415
416 if (sample_address)
417 attr->sample_type |= PERF_SAMPLE_ADDR;
418
419 if (call_graph)
420 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
421
422 if (raw_samples)
423 attr->sample_type |= PERF_SAMPLE_RAW;
424
425 attr->mmap = track;
426 attr->comm = track;
427 attr->inherit = (cpu < 0) && inherit;
428 attr->disabled = 1;
429
430try_again:
431 fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
432
433 if (fd[nr_cpu][counter] < 0) {
434 int err = errno;
435
436 if (err == EPERM)
437 die("Permission error - are you root?\n");
438 else if (err == ENODEV && profile_cpu != -1)
439 die("No such device - did you specify an out-of-range profile CPU?\n");
440
441 /*
442 * If it's cycles then fall back to hrtimer
443 * based cpu-clock-tick sw counter, which
444 * is always available even if no PMU support:
445 */
446 if (attr->type == PERF_TYPE_HARDWARE
447 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
448
449 if (verbose)
450 warning(" ... trying to fall back to cpu-clock-ticks\n");
451 attr->type = PERF_TYPE_SOFTWARE;
452 attr->config = PERF_COUNT_SW_CPU_CLOCK;
453 goto try_again;
454 }
455 printf("\n");
456 error("perfcounter syscall returned with %d (%s)\n",
457 fd[nr_cpu][counter], strerror(err));
458 die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n");
459 exit(-1);
460 }
461
462 h_attr = get_header_attr(attr, counter);
463
464 if (!file_new) {
465 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
466 fprintf(stderr, "incompatible append\n");
467 exit(-1);
468 }
469 }
470
471 if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) {
472 perror("Unable to read perf file descriptor\n");
473 exit(-1);
474 }
475
476 perf_header_attr__add_id(h_attr, read_data.id);
477
478 assert(fd[nr_cpu][counter] >= 0);
479 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
480
481 /*
482 * First counter acts as the group leader:
483 */
484 if (group && group_fd == -1)
485 group_fd = fd[nr_cpu][counter];
486
487 event_array[nr_poll].fd = fd[nr_cpu][counter];
488 event_array[nr_poll].events = POLLIN;
489 nr_poll++;
490
491 mmap_array[nr_cpu][counter].counter = counter;
492 mmap_array[nr_cpu][counter].prev = 0;
493 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1;
494 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
495 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0);
496 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) {
497 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
498 exit(-1);
499 }
500
501 ioctl(fd[nr_cpu][counter], PERF_COUNTER_IOC_ENABLE);
502}
503
504static void open_counters(int cpu, pid_t pid)
505{
506 int counter;
507
508 group_fd = -1;
509 for (counter = 0; counter < nr_counters; counter++)
510 create_counter(counter, cpu, pid);
511
512 nr_cpu++;
513}
514
515static void atexit_header(void)
516{
517 header->data_size += bytes_written;
518
519 perf_header__write(header, output);
520}
521
522static int __cmd_record(int argc, const char **argv)
523{
524 int i, counter;
525 struct stat st;
526 pid_t pid = 0;
527 int flags;
528 int ret;
529
530 page_size = sysconf(_SC_PAGE_SIZE);
531 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
532 assert(nr_cpus <= MAX_NR_CPUS);
533 assert(nr_cpus >= 0);
534
535 atexit(sig_atexit);
536 signal(SIGCHLD, sig_handler);
537 signal(SIGINT, sig_handler);
538
539 if (!stat(output_name, &st) && st.st_size) {
540 if (!force && !append_file) {
541 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
542 output_name);
543 exit(-1);
544 }
545 } else {
546 append_file = 0;
547 }
548
549 flags = O_CREAT|O_RDWR;
550 if (append_file)
551 file_new = 0;
552 else
553 flags |= O_TRUNC;
554
555 output = open(output_name, flags, S_IRUSR|S_IWUSR);
556 if (output < 0) {
557 perror("failed to create output file");
558 exit(-1);
559 }
560
561 if (!file_new)
562 header = perf_header__read(output);
563 else
564 header = perf_header__new();
565
566 atexit(atexit_header);
567
568 if (!system_wide) {
569 pid = target_pid;
570 if (pid == -1)
571 pid = getpid();
572
573 open_counters(profile_cpu, pid);
574 } else {
575 if (profile_cpu != -1) {
576 open_counters(profile_cpu, target_pid);
577 } else {
578 for (i = 0; i < nr_cpus; i++)
579 open_counters(i, target_pid);
580 }
581 }
582
583 if (file_new)
584 perf_header__write(header, output);
585
586 if (!system_wide) {
587 pid_t tgid = pid_synthesize_comm_event(pid, 0);
588 pid_synthesize_mmap_samples(pid, tgid);
589 } else
590 synthesize_all();
591
592 if (target_pid == -1 && argc) {
593 pid = fork();
594 if (pid < 0)
595 perror("failed to fork");
596
597 if (!pid) {
598 if (execvp(argv[0], (char **)argv)) {
599 perror(argv[0]);
600 exit(-1);
601 }
602 }
603 }
604
605 if (realtime_prio) {
606 struct sched_param param;
607
608 param.sched_priority = realtime_prio;
609 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
610 printf("Could not set realtime priority.\n");
611 exit(-1);
612 }
613 }
614
615 for (;;) {
616 int hits = samples;
617
618 for (i = 0; i < nr_cpu; i++) {
619 for (counter = 0; counter < nr_counters; counter++)
620 mmap_read(&mmap_array[i][counter]);
621 }
622
623 if (hits == samples) {
624 if (done)
625 break;
626 ret = poll(event_array, nr_poll, 100);
627 }
628 }
629
630 /*
631 * Approximate RIP event size: 24 bytes.
632 */
633 fprintf(stderr,
634 "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n",
635 (double)bytes_written / 1024.0 / 1024.0,
636 output_name,
637 bytes_written / 24);
638
639 return 0;
640}
641
642static const char * const record_usage[] = {
643 "perf record [<options>] [<command>]",
644 "perf record [<options>] -- <command> [<options>]",
645 NULL
646};
647
648static const struct option options[] = {
649 OPT_CALLBACK('e', "event", NULL, "event",
650 "event selector. use 'perf list' to list available events",
651 parse_events),
652 OPT_INTEGER('p', "pid", &target_pid,
653 "record events on existing pid"),
654 OPT_INTEGER('r', "realtime", &realtime_prio,
655 "collect data with this RT SCHED_FIFO priority"),
656 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
657 "collect raw sample records from all opened counters"),
658 OPT_BOOLEAN('a', "all-cpus", &system_wide,
659 "system-wide collection from all CPUs"),
660 OPT_BOOLEAN('A', "append", &append_file,
661 "append to the output file to do incremental profiling"),
662 OPT_INTEGER('C', "profile_cpu", &profile_cpu,
663 "CPU to profile on"),
664 OPT_BOOLEAN('f', "force", &force,
665 "overwrite existing data file"),
666 OPT_LONG('c', "count", &default_interval,
667 "event period to sample"),
668 OPT_STRING('o', "output", &output_name, "file",
669 "output file name"),
670 OPT_BOOLEAN('i', "inherit", &inherit,
671 "child tasks inherit counters"),
672 OPT_INTEGER('F', "freq", &freq,
673 "profile at this frequency"),
674 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
675 "number of mmap data pages"),
676 OPT_BOOLEAN('g', "call-graph", &call_graph,
677 "do call-graph (stack chain/backtrace) recording"),
678 OPT_BOOLEAN('v', "verbose", &verbose,
679 "be more verbose (show counter open errors, etc)"),
680 OPT_BOOLEAN('s', "stat", &inherit_stat,
681 "per thread counts"),
682 OPT_BOOLEAN('d', "data", &sample_address,
683 "Sample addresses"),
684 OPT_BOOLEAN('n', "no-samples", &no_samples,
685 "don't sample"),
686 OPT_END()
687};
688
689int cmd_record(int argc, const char **argv, const char *prefix __used)
690{
691 int counter;
692
693 argc = parse_options(argc, argv, options, record_usage,
694 PARSE_OPT_STOP_AT_NON_OPTION);
695 if (!argc && target_pid == -1 && !system_wide)
696 usage_with_options(record_usage, options);
697
698 if (!nr_counters) {
699 nr_counters = 1;
700 attrs[0].type = PERF_TYPE_HARDWARE;
701 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
702 }
703
704 for (counter = 0; counter < nr_counters; counter++) {
705 if (attrs[counter].sample_period)
706 continue;
707
708 attrs[counter].sample_period = default_interval;
709 }
710
711 return __cmd_record(argc, argv);
712}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
new file mode 100644
index 000000000000..8b2ec882e6e0
--- /dev/null
+++ b/tools/perf/builtin-report.c
@@ -0,0 +1,2173 @@
1/*
2 * builtin-report.c
3 *
4 * Builtin report command: Analyze the perf.data input file,
5 * look up and read DSOs and symbol information and display
6 * a histogram of results, along various sorting keys.
7 */
8#include "builtin.h"
9
10#include "util/util.h"
11
12#include "util/color.h"
13#include <linux/list.h>
14#include "util/cache.h"
15#include <linux/rbtree.h>
16#include "util/symbol.h"
17#include "util/string.h"
18#include "util/callchain.h"
19#include "util/strlist.h"
20
21#include "perf.h"
22#include "util/header.h"
23
24#include "util/parse-options.h"
25#include "util/parse-events.h"
26
27#define SHOW_KERNEL 1
28#define SHOW_USER 2
29#define SHOW_HV 4
30
31static char const *input_name = "perf.data";
32static char *vmlinux = NULL;
33
34static char default_sort_order[] = "comm,dso,symbol";
35static char *sort_order = default_sort_order;
36static char *dso_list_str, *comm_list_str, *sym_list_str,
37 *col_width_list_str;
38static struct strlist *dso_list, *comm_list, *sym_list;
39static char *field_sep;
40
41static int force;
42static int input;
43static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
44
45static int dump_trace = 0;
46#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
47#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
48
49static int verbose;
50#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
51
52static int modules;
53
54static int full_paths;
55static int show_nr_samples;
56
57static unsigned long page_size;
58static unsigned long mmap_window = 32;
59
60static char default_parent_pattern[] = "^sys_|^do_page_fault";
61static char *parent_pattern = default_parent_pattern;
62static regex_t parent_regex;
63
64static int exclude_other = 1;
65
66static char callchain_default_opt[] = "fractal,0.5";
67
68static int callchain;
69
70static
71struct callchain_param callchain_param = {
72 .mode = CHAIN_GRAPH_REL,
73 .min_percent = 0.5
74};
75
76static u64 sample_type;
77
78struct ip_event {
79 struct perf_event_header header;
80 u64 ip;
81 u32 pid, tid;
82 unsigned char __more_data[];
83};
84
85struct mmap_event {
86 struct perf_event_header header;
87 u32 pid, tid;
88 u64 start;
89 u64 len;
90 u64 pgoff;
91 char filename[PATH_MAX];
92};
93
94struct comm_event {
95 struct perf_event_header header;
96 u32 pid, tid;
97 char comm[16];
98};
99
100struct fork_event {
101 struct perf_event_header header;
102 u32 pid, ppid;
103 u32 tid, ptid;
104};
105
106struct lost_event {
107 struct perf_event_header header;
108 u64 id;
109 u64 lost;
110};
111
112struct read_event {
113 struct perf_event_header header;
114 u32 pid,tid;
115 u64 value;
116 u64 time_enabled;
117 u64 time_running;
118 u64 id;
119};
120
121typedef union event_union {
122 struct perf_event_header header;
123 struct ip_event ip;
124 struct mmap_event mmap;
125 struct comm_event comm;
126 struct fork_event fork;
127 struct lost_event lost;
128 struct read_event read;
129} event_t;
130
131static int repsep_fprintf(FILE *fp, const char *fmt, ...)
132{
133 int n;
134 va_list ap;
135
136 va_start(ap, fmt);
137 if (!field_sep)
138 n = vfprintf(fp, fmt, ap);
139 else {
140 char *bf = NULL;
141 n = vasprintf(&bf, fmt, ap);
142 if (n > 0) {
143 char *sep = bf;
144 while (1) {
145 sep = strchr(sep, *field_sep);
146 if (sep == NULL)
147 break;
148 *sep = '.';
149 }
150 }
151 fputs(bf, fp);
152 free(bf);
153 }
154 va_end(ap);
155 return n;
156}
157
158static LIST_HEAD(dsos);
159static struct dso *kernel_dso;
160static struct dso *vdso;
161static struct dso *hypervisor_dso;
162
163static void dsos__add(struct dso *dso)
164{
165 list_add_tail(&dso->node, &dsos);
166}
167
168static struct dso *dsos__find(const char *name)
169{
170 struct dso *pos;
171
172 list_for_each_entry(pos, &dsos, node)
173 if (strcmp(pos->name, name) == 0)
174 return pos;
175 return NULL;
176}
177
178static struct dso *dsos__findnew(const char *name)
179{
180 struct dso *dso = dsos__find(name);
181 int nr;
182
183 if (dso)
184 return dso;
185
186 dso = dso__new(name, 0);
187 if (!dso)
188 goto out_delete_dso;
189
190 nr = dso__load(dso, NULL, verbose);
191 if (nr < 0) {
192 eprintf("Failed to open: %s\n", name);
193 goto out_delete_dso;
194 }
195 if (!nr)
196 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
197
198 dsos__add(dso);
199
200 return dso;
201
202out_delete_dso:
203 dso__delete(dso);
204 return NULL;
205}
206
207static void dsos__fprintf(FILE *fp)
208{
209 struct dso *pos;
210
211 list_for_each_entry(pos, &dsos, node)
212 dso__fprintf(pos, fp);
213}
214
215static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
216{
217 return dso__find_symbol(dso, ip);
218}
219
220static int load_kernel(void)
221{
222 int err;
223
224 kernel_dso = dso__new("[kernel]", 0);
225 if (!kernel_dso)
226 return -1;
227
228 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
229 if (err <= 0) {
230 dso__delete(kernel_dso);
231 kernel_dso = NULL;
232 } else
233 dsos__add(kernel_dso);
234
235 vdso = dso__new("[vdso]", 0);
236 if (!vdso)
237 return -1;
238
239 vdso->find_symbol = vdso__find_symbol;
240
241 dsos__add(vdso);
242
243 hypervisor_dso = dso__new("[hypervisor]", 0);
244 if (!hypervisor_dso)
245 return -1;
246 dsos__add(hypervisor_dso);
247
248 return err;
249}
250
251static char __cwd[PATH_MAX];
252static char *cwd = __cwd;
253static int cwdlen;
254
255static int strcommon(const char *pathname)
256{
257 int n = 0;
258
259 while (n < cwdlen && pathname[n] == cwd[n])
260 ++n;
261
262 return n;
263}
264
265struct map {
266 struct list_head node;
267 u64 start;
268 u64 end;
269 u64 pgoff;
270 u64 (*map_ip)(struct map *, u64);
271 struct dso *dso;
272};
273
274static u64 map__map_ip(struct map *map, u64 ip)
275{
276 return ip - map->start + map->pgoff;
277}
278
279static u64 vdso__map_ip(struct map *map __used, u64 ip)
280{
281 return ip;
282}
283
284static inline int is_anon_memory(const char *filename)
285{
286 return strcmp(filename, "//anon") == 0;
287}
288
289static struct map *map__new(struct mmap_event *event)
290{
291 struct map *self = malloc(sizeof(*self));
292
293 if (self != NULL) {
294 const char *filename = event->filename;
295 char newfilename[PATH_MAX];
296 int anon;
297
298 if (cwd) {
299 int n = strcommon(filename);
300
301 if (n == cwdlen) {
302 snprintf(newfilename, sizeof(newfilename),
303 ".%s", filename + n);
304 filename = newfilename;
305 }
306 }
307
308 anon = is_anon_memory(filename);
309
310 if (anon) {
311 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
312 filename = newfilename;
313 }
314
315 self->start = event->start;
316 self->end = event->start + event->len;
317 self->pgoff = event->pgoff;
318
319 self->dso = dsos__findnew(filename);
320 if (self->dso == NULL)
321 goto out_delete;
322
323 if (self->dso == vdso || anon)
324 self->map_ip = vdso__map_ip;
325 else
326 self->map_ip = map__map_ip;
327 }
328 return self;
329out_delete:
330 free(self);
331 return NULL;
332}
333
334static struct map *map__clone(struct map *self)
335{
336 struct map *map = malloc(sizeof(*self));
337
338 if (!map)
339 return NULL;
340
341 memcpy(map, self, sizeof(*self));
342
343 return map;
344}
345
346static int map__overlap(struct map *l, struct map *r)
347{
348 if (l->start > r->start) {
349 struct map *t = l;
350 l = r;
351 r = t;
352 }
353
354 if (l->end > r->start)
355 return 1;
356
357 return 0;
358}
359
360static size_t map__fprintf(struct map *self, FILE *fp)
361{
362 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
363 self->start, self->end, self->pgoff, self->dso->name);
364}
365
366
367struct thread {
368 struct rb_node rb_node;
369 struct list_head maps;
370 pid_t pid;
371 char *comm;
372};
373
374static struct thread *thread__new(pid_t pid)
375{
376 struct thread *self = malloc(sizeof(*self));
377
378 if (self != NULL) {
379 self->pid = pid;
380 self->comm = malloc(32);
381 if (self->comm)
382 snprintf(self->comm, 32, ":%d", self->pid);
383 INIT_LIST_HEAD(&self->maps);
384 }
385
386 return self;
387}
388
389static unsigned int dsos__col_width,
390 comms__col_width,
391 threads__col_width;
392
393static int thread__set_comm(struct thread *self, const char *comm)
394{
395 if (self->comm)
396 free(self->comm);
397 self->comm = strdup(comm);
398 if (!self->comm)
399 return -ENOMEM;
400
401 if (!col_width_list_str && !field_sep &&
402 (!comm_list || strlist__has_entry(comm_list, comm))) {
403 unsigned int slen = strlen(comm);
404 if (slen > comms__col_width) {
405 comms__col_width = slen;
406 threads__col_width = slen + 6;
407 }
408 }
409
410 return 0;
411}
412
413static size_t thread__fprintf(struct thread *self, FILE *fp)
414{
415 struct map *pos;
416 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
417
418 list_for_each_entry(pos, &self->maps, node)
419 ret += map__fprintf(pos, fp);
420
421 return ret;
422}
423
424
425static struct rb_root threads;
426static struct thread *last_match;
427
428static struct thread *threads__findnew(pid_t pid)
429{
430 struct rb_node **p = &threads.rb_node;
431 struct rb_node *parent = NULL;
432 struct thread *th;
433
434 /*
435 * Font-end cache - PID lookups come in blocks,
436 * so most of the time we dont have to look up
437 * the full rbtree:
438 */
439 if (last_match && last_match->pid == pid)
440 return last_match;
441
442 while (*p != NULL) {
443 parent = *p;
444 th = rb_entry(parent, struct thread, rb_node);
445
446 if (th->pid == pid) {
447 last_match = th;
448 return th;
449 }
450
451 if (pid < th->pid)
452 p = &(*p)->rb_left;
453 else
454 p = &(*p)->rb_right;
455 }
456
457 th = thread__new(pid);
458 if (th != NULL) {
459 rb_link_node(&th->rb_node, parent, p);
460 rb_insert_color(&th->rb_node, &threads);
461 last_match = th;
462 }
463
464 return th;
465}
466
467static void thread__insert_map(struct thread *self, struct map *map)
468{
469 struct map *pos, *tmp;
470
471 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
472 if (map__overlap(pos, map)) {
473 if (verbose >= 2) {
474 printf("overlapping maps:\n");
475 map__fprintf(map, stdout);
476 map__fprintf(pos, stdout);
477 }
478
479 if (map->start <= pos->start && map->end > pos->start)
480 pos->start = map->end;
481
482 if (map->end >= pos->end && map->start < pos->end)
483 pos->end = map->start;
484
485 if (verbose >= 2) {
486 printf("after collision:\n");
487 map__fprintf(pos, stdout);
488 }
489
490 if (pos->start >= pos->end) {
491 list_del_init(&pos->node);
492 free(pos);
493 }
494 }
495 }
496
497 list_add_tail(&map->node, &self->maps);
498}
499
500static int thread__fork(struct thread *self, struct thread *parent)
501{
502 struct map *map;
503
504 if (self->comm)
505 free(self->comm);
506 self->comm = strdup(parent->comm);
507 if (!self->comm)
508 return -ENOMEM;
509
510 list_for_each_entry(map, &parent->maps, node) {
511 struct map *new = map__clone(map);
512 if (!new)
513 return -ENOMEM;
514 thread__insert_map(self, new);
515 }
516
517 return 0;
518}
519
520static struct map *thread__find_map(struct thread *self, u64 ip)
521{
522 struct map *pos;
523
524 if (self == NULL)
525 return NULL;
526
527 list_for_each_entry(pos, &self->maps, node)
528 if (ip >= pos->start && ip <= pos->end)
529 return pos;
530
531 return NULL;
532}
533
534static size_t threads__fprintf(FILE *fp)
535{
536 size_t ret = 0;
537 struct rb_node *nd;
538
539 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
540 struct thread *pos = rb_entry(nd, struct thread, rb_node);
541
542 ret += thread__fprintf(pos, fp);
543 }
544
545 return ret;
546}
547
548/*
549 * histogram, sorted on item, collects counts
550 */
551
552static struct rb_root hist;
553
554struct hist_entry {
555 struct rb_node rb_node;
556
557 struct thread *thread;
558 struct map *map;
559 struct dso *dso;
560 struct symbol *sym;
561 struct symbol *parent;
562 u64 ip;
563 char level;
564 struct callchain_node callchain;
565 struct rb_root sorted_chain;
566
567 u64 count;
568};
569
570/*
571 * configurable sorting bits
572 */
573
574struct sort_entry {
575 struct list_head list;
576
577 char *header;
578
579 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
580 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
581 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
582 unsigned int *width;
583 bool elide;
584};
585
586static int64_t cmp_null(void *l, void *r)
587{
588 if (!l && !r)
589 return 0;
590 else if (!l)
591 return -1;
592 else
593 return 1;
594}
595
596/* --sort pid */
597
598static int64_t
599sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
600{
601 return right->thread->pid - left->thread->pid;
602}
603
604static size_t
605sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
606{
607 return repsep_fprintf(fp, "%*s:%5d", width - 6,
608 self->thread->comm ?: "", self->thread->pid);
609}
610
611static struct sort_entry sort_thread = {
612 .header = "Command: Pid",
613 .cmp = sort__thread_cmp,
614 .print = sort__thread_print,
615 .width = &threads__col_width,
616};
617
618/* --sort comm */
619
620static int64_t
621sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
622{
623 return right->thread->pid - left->thread->pid;
624}
625
626static int64_t
627sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
628{
629 char *comm_l = left->thread->comm;
630 char *comm_r = right->thread->comm;
631
632 if (!comm_l || !comm_r)
633 return cmp_null(comm_l, comm_r);
634
635 return strcmp(comm_l, comm_r);
636}
637
638static size_t
639sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
640{
641 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
642}
643
644static struct sort_entry sort_comm = {
645 .header = "Command",
646 .cmp = sort__comm_cmp,
647 .collapse = sort__comm_collapse,
648 .print = sort__comm_print,
649 .width = &comms__col_width,
650};
651
652/* --sort dso */
653
654static int64_t
655sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
656{
657 struct dso *dso_l = left->dso;
658 struct dso *dso_r = right->dso;
659
660 if (!dso_l || !dso_r)
661 return cmp_null(dso_l, dso_r);
662
663 return strcmp(dso_l->name, dso_r->name);
664}
665
666static size_t
667sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
668{
669 if (self->dso)
670 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
671
672 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
673}
674
675static struct sort_entry sort_dso = {
676 .header = "Shared Object",
677 .cmp = sort__dso_cmp,
678 .print = sort__dso_print,
679 .width = &dsos__col_width,
680};
681
682/* --sort symbol */
683
684static int64_t
685sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
686{
687 u64 ip_l, ip_r;
688
689 if (left->sym == right->sym)
690 return 0;
691
692 ip_l = left->sym ? left->sym->start : left->ip;
693 ip_r = right->sym ? right->sym->start : right->ip;
694
695 return (int64_t)(ip_r - ip_l);
696}
697
698static size_t
699sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
700{
701 size_t ret = 0;
702
703 if (verbose)
704 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
705 dso__symtab_origin(self->dso));
706
707 ret += repsep_fprintf(fp, "[%c] ", self->level);
708 if (self->sym) {
709 ret += repsep_fprintf(fp, "%s", self->sym->name);
710
711 if (self->sym->module)
712 ret += repsep_fprintf(fp, "\t[%s]",
713 self->sym->module->name);
714 } else {
715 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
716 }
717
718 return ret;
719}
720
721static struct sort_entry sort_sym = {
722 .header = "Symbol",
723 .cmp = sort__sym_cmp,
724 .print = sort__sym_print,
725};
726
727/* --sort parent */
728
729static int64_t
730sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
731{
732 struct symbol *sym_l = left->parent;
733 struct symbol *sym_r = right->parent;
734
735 if (!sym_l || !sym_r)
736 return cmp_null(sym_l, sym_r);
737
738 return strcmp(sym_l->name, sym_r->name);
739}
740
741static size_t
742sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
743{
744 return repsep_fprintf(fp, "%-*s", width,
745 self->parent ? self->parent->name : "[other]");
746}
747
748static unsigned int parent_symbol__col_width;
749
750static struct sort_entry sort_parent = {
751 .header = "Parent symbol",
752 .cmp = sort__parent_cmp,
753 .print = sort__parent_print,
754 .width = &parent_symbol__col_width,
755};
756
757static int sort__need_collapse = 0;
758static int sort__has_parent = 0;
759
760struct sort_dimension {
761 char *name;
762 struct sort_entry *entry;
763 int taken;
764};
765
766static struct sort_dimension sort_dimensions[] = {
767 { .name = "pid", .entry = &sort_thread, },
768 { .name = "comm", .entry = &sort_comm, },
769 { .name = "dso", .entry = &sort_dso, },
770 { .name = "symbol", .entry = &sort_sym, },
771 { .name = "parent", .entry = &sort_parent, },
772};
773
774static LIST_HEAD(hist_entry__sort_list);
775
776static int sort_dimension__add(char *tok)
777{
778 unsigned int i;
779
780 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
781 struct sort_dimension *sd = &sort_dimensions[i];
782
783 if (sd->taken)
784 continue;
785
786 if (strncasecmp(tok, sd->name, strlen(tok)))
787 continue;
788
789 if (sd->entry->collapse)
790 sort__need_collapse = 1;
791
792 if (sd->entry == &sort_parent) {
793 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
794 if (ret) {
795 char err[BUFSIZ];
796
797 regerror(ret, &parent_regex, err, sizeof(err));
798 fprintf(stderr, "Invalid regex: %s\n%s",
799 parent_pattern, err);
800 exit(-1);
801 }
802 sort__has_parent = 1;
803 }
804
805 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
806 sd->taken = 1;
807
808 return 0;
809 }
810
811 return -ESRCH;
812}
813
814static int64_t
815hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
816{
817 struct sort_entry *se;
818 int64_t cmp = 0;
819
820 list_for_each_entry(se, &hist_entry__sort_list, list) {
821 cmp = se->cmp(left, right);
822 if (cmp)
823 break;
824 }
825
826 return cmp;
827}
828
829static int64_t
830hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
831{
832 struct sort_entry *se;
833 int64_t cmp = 0;
834
835 list_for_each_entry(se, &hist_entry__sort_list, list) {
836 int64_t (*f)(struct hist_entry *, struct hist_entry *);
837
838 f = se->collapse ?: se->cmp;
839
840 cmp = f(left, right);
841 if (cmp)
842 break;
843 }
844
845 return cmp;
846}
847
848static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
849{
850 int i;
851 size_t ret = 0;
852
853 ret += fprintf(fp, "%s", " ");
854
855 for (i = 0; i < depth; i++)
856 if (depth_mask & (1 << i))
857 ret += fprintf(fp, "| ");
858 else
859 ret += fprintf(fp, " ");
860
861 ret += fprintf(fp, "\n");
862
863 return ret;
864}
865static size_t
866ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
867 int depth_mask, int count, u64 total_samples,
868 int hits)
869{
870 int i;
871 size_t ret = 0;
872
873 ret += fprintf(fp, "%s", " ");
874 for (i = 0; i < depth; i++) {
875 if (depth_mask & (1 << i))
876 ret += fprintf(fp, "|");
877 else
878 ret += fprintf(fp, " ");
879 if (!count && i == depth - 1) {
880 double percent;
881
882 percent = hits * 100.0 / total_samples;
883 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
884 } else
885 ret += fprintf(fp, "%s", " ");
886 }
887 if (chain->sym)
888 ret += fprintf(fp, "%s\n", chain->sym->name);
889 else
890 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
891
892 return ret;
893}
894
895static struct symbol *rem_sq_bracket;
896static struct callchain_list rem_hits;
897
898static void init_rem_hits(void)
899{
900 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
901 if (!rem_sq_bracket) {
902 fprintf(stderr, "Not enough memory to display remaining hits\n");
903 return;
904 }
905
906 strcpy(rem_sq_bracket->name, "[...]");
907 rem_hits.sym = rem_sq_bracket;
908}
909
910static size_t
911callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
912 u64 total_samples, int depth, int depth_mask)
913{
914 struct rb_node *node, *next;
915 struct callchain_node *child;
916 struct callchain_list *chain;
917 int new_depth_mask = depth_mask;
918 u64 new_total;
919 u64 remaining;
920 size_t ret = 0;
921 int i;
922
923 if (callchain_param.mode == CHAIN_GRAPH_REL)
924 new_total = self->children_hit;
925 else
926 new_total = total_samples;
927
928 remaining = new_total;
929
930 node = rb_first(&self->rb_root);
931 while (node) {
932 u64 cumul;
933
934 child = rb_entry(node, struct callchain_node, rb_node);
935 cumul = cumul_hits(child);
936 remaining -= cumul;
937
938 /*
939 * The depth mask manages the output of pipes that show
940 * the depth. We don't want to keep the pipes of the current
941 * level for the last child of this depth.
942 * Except if we have remaining filtered hits. They will
943 * supersede the last child
944 */
945 next = rb_next(node);
946 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
947 new_depth_mask &= ~(1 << (depth - 1));
948
949 /*
950 * But we keep the older depth mask for the line seperator
951 * to keep the level link until we reach the last child
952 */
953 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
954 i = 0;
955 list_for_each_entry(chain, &child->val, list) {
956 if (chain->ip >= PERF_CONTEXT_MAX)
957 continue;
958 ret += ipchain__fprintf_graph(fp, chain, depth,
959 new_depth_mask, i++,
960 new_total,
961 cumul);
962 }
963 ret += callchain__fprintf_graph(fp, child, new_total,
964 depth + 1,
965 new_depth_mask | (1 << depth));
966 node = next;
967 }
968
969 if (callchain_param.mode == CHAIN_GRAPH_REL &&
970 remaining && remaining != new_total) {
971
972 if (!rem_sq_bracket)
973 return ret;
974
975 new_depth_mask &= ~(1 << (depth - 1));
976
977 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
978 new_depth_mask, 0, new_total,
979 remaining);
980 }
981
982 return ret;
983}
984
985static size_t
986callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
987 u64 total_samples)
988{
989 struct callchain_list *chain;
990 size_t ret = 0;
991
992 if (!self)
993 return 0;
994
995 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
996
997
998 list_for_each_entry(chain, &self->val, list) {
999 if (chain->ip >= PERF_CONTEXT_MAX)
1000 continue;
1001 if (chain->sym)
1002 ret += fprintf(fp, " %s\n", chain->sym->name);
1003 else
1004 ret += fprintf(fp, " %p\n",
1005 (void *)(long)chain->ip);
1006 }
1007
1008 return ret;
1009}
1010
1011static size_t
1012hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
1013 u64 total_samples)
1014{
1015 struct rb_node *rb_node;
1016 struct callchain_node *chain;
1017 size_t ret = 0;
1018
1019 rb_node = rb_first(&self->sorted_chain);
1020 while (rb_node) {
1021 double percent;
1022
1023 chain = rb_entry(rb_node, struct callchain_node, rb_node);
1024 percent = chain->hit * 100.0 / total_samples;
1025 switch (callchain_param.mode) {
1026 case CHAIN_FLAT:
1027 ret += percent_color_fprintf(fp, " %6.2f%%\n",
1028 percent);
1029 ret += callchain__fprintf_flat(fp, chain, total_samples);
1030 break;
1031 case CHAIN_GRAPH_ABS: /* Falldown */
1032 case CHAIN_GRAPH_REL:
1033 ret += callchain__fprintf_graph(fp, chain,
1034 total_samples, 1, 1);
1035 default:
1036 break;
1037 }
1038 ret += fprintf(fp, "\n");
1039 rb_node = rb_next(rb_node);
1040 }
1041
1042 return ret;
1043}
1044
1045
1046static size_t
1047hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
1048{
1049 struct sort_entry *se;
1050 size_t ret;
1051
1052 if (exclude_other && !self->parent)
1053 return 0;
1054
1055 if (total_samples)
1056 ret = percent_color_fprintf(fp,
1057 field_sep ? "%.2f" : " %6.2f%%",
1058 (self->count * 100.0) / total_samples);
1059 else
1060 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
1061
1062 if (show_nr_samples) {
1063 if (field_sep)
1064 fprintf(fp, "%c%lld", *field_sep, self->count);
1065 else
1066 fprintf(fp, "%11lld", self->count);
1067 }
1068
1069 list_for_each_entry(se, &hist_entry__sort_list, list) {
1070 if (se->elide)
1071 continue;
1072
1073 fprintf(fp, "%s", field_sep ?: " ");
1074 ret += se->print(fp, self, se->width ? *se->width : 0);
1075 }
1076
1077 ret += fprintf(fp, "\n");
1078
1079 if (callchain)
1080 hist_entry_callchain__fprintf(fp, self, total_samples);
1081
1082 return ret;
1083}
1084
1085/*
1086 *
1087 */
1088
1089static void dso__calc_col_width(struct dso *self)
1090{
1091 if (!col_width_list_str && !field_sep &&
1092 (!dso_list || strlist__has_entry(dso_list, self->name))) {
1093 unsigned int slen = strlen(self->name);
1094 if (slen > dsos__col_width)
1095 dsos__col_width = slen;
1096 }
1097
1098 self->slen_calculated = 1;
1099}
1100
1101static struct symbol *
1102resolve_symbol(struct thread *thread, struct map **mapp,
1103 struct dso **dsop, u64 *ipp)
1104{
1105 struct dso *dso = dsop ? *dsop : NULL;
1106 struct map *map = mapp ? *mapp : NULL;
1107 u64 ip = *ipp;
1108
1109 if (!thread)
1110 return NULL;
1111
1112 if (dso)
1113 goto got_dso;
1114
1115 if (map)
1116 goto got_map;
1117
1118 map = thread__find_map(thread, ip);
1119 if (map != NULL) {
1120 /*
1121 * We have to do this here as we may have a dso
1122 * with no symbol hit that has a name longer than
1123 * the ones with symbols sampled.
1124 */
1125 if (!sort_dso.elide && !map->dso->slen_calculated)
1126 dso__calc_col_width(map->dso);
1127
1128 if (mapp)
1129 *mapp = map;
1130got_map:
1131 ip = map->map_ip(map, ip);
1132
1133 dso = map->dso;
1134 } else {
1135 /*
1136 * If this is outside of all known maps,
1137 * and is a negative address, try to look it
1138 * up in the kernel dso, as it might be a
1139 * vsyscall (which executes in user-mode):
1140 */
1141 if ((long long)ip < 0)
1142 dso = kernel_dso;
1143 }
1144 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
1145 dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
1146 *ipp = ip;
1147
1148 if (dsop)
1149 *dsop = dso;
1150
1151 if (!dso)
1152 return NULL;
1153got_dso:
1154 return dso->find_symbol(dso, ip);
1155}
1156
1157static int call__match(struct symbol *sym)
1158{
1159 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
1160 return 1;
1161
1162 return 0;
1163}
1164
1165static struct symbol **
1166resolve_callchain(struct thread *thread, struct map *map __used,
1167 struct ip_callchain *chain, struct hist_entry *entry)
1168{
1169 u64 context = PERF_CONTEXT_MAX;
1170 struct symbol **syms = NULL;
1171 unsigned int i;
1172
1173 if (callchain) {
1174 syms = calloc(chain->nr, sizeof(*syms));
1175 if (!syms) {
1176 fprintf(stderr, "Can't allocate memory for symbols\n");
1177 exit(-1);
1178 }
1179 }
1180
1181 for (i = 0; i < chain->nr; i++) {
1182 u64 ip = chain->ips[i];
1183 struct dso *dso = NULL;
1184 struct symbol *sym;
1185
1186 if (ip >= PERF_CONTEXT_MAX) {
1187 context = ip;
1188 continue;
1189 }
1190
1191 switch (context) {
1192 case PERF_CONTEXT_HV:
1193 dso = hypervisor_dso;
1194 break;
1195 case PERF_CONTEXT_KERNEL:
1196 dso = kernel_dso;
1197 break;
1198 default:
1199 break;
1200 }
1201
1202 sym = resolve_symbol(thread, NULL, &dso, &ip);
1203
1204 if (sym) {
1205 if (sort__has_parent && call__match(sym) &&
1206 !entry->parent)
1207 entry->parent = sym;
1208 if (!callchain)
1209 break;
1210 syms[i] = sym;
1211 }
1212 }
1213
1214 return syms;
1215}
1216
1217/*
1218 * collect histogram counts
1219 */
1220
1221static int
1222hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
1223 struct symbol *sym, u64 ip, struct ip_callchain *chain,
1224 char level, u64 count)
1225{
1226 struct rb_node **p = &hist.rb_node;
1227 struct rb_node *parent = NULL;
1228 struct hist_entry *he;
1229 struct symbol **syms = NULL;
1230 struct hist_entry entry = {
1231 .thread = thread,
1232 .map = map,
1233 .dso = dso,
1234 .sym = sym,
1235 .ip = ip,
1236 .level = level,
1237 .count = count,
1238 .parent = NULL,
1239 .sorted_chain = RB_ROOT
1240 };
1241 int cmp;
1242
1243 if ((sort__has_parent || callchain) && chain)
1244 syms = resolve_callchain(thread, map, chain, &entry);
1245
1246 while (*p != NULL) {
1247 parent = *p;
1248 he = rb_entry(parent, struct hist_entry, rb_node);
1249
1250 cmp = hist_entry__cmp(&entry, he);
1251
1252 if (!cmp) {
1253 he->count += count;
1254 if (callchain) {
1255 append_chain(&he->callchain, chain, syms);
1256 free(syms);
1257 }
1258 return 0;
1259 }
1260
1261 if (cmp < 0)
1262 p = &(*p)->rb_left;
1263 else
1264 p = &(*p)->rb_right;
1265 }
1266
1267 he = malloc(sizeof(*he));
1268 if (!he)
1269 return -ENOMEM;
1270 *he = entry;
1271 if (callchain) {
1272 callchain_init(&he->callchain);
1273 append_chain(&he->callchain, chain, syms);
1274 free(syms);
1275 }
1276 rb_link_node(&he->rb_node, parent, p);
1277 rb_insert_color(&he->rb_node, &hist);
1278
1279 return 0;
1280}
1281
1282static void hist_entry__free(struct hist_entry *he)
1283{
1284 free(he);
1285}
1286
1287/*
1288 * collapse the histogram
1289 */
1290
1291static struct rb_root collapse_hists;
1292
1293static void collapse__insert_entry(struct hist_entry *he)
1294{
1295 struct rb_node **p = &collapse_hists.rb_node;
1296 struct rb_node *parent = NULL;
1297 struct hist_entry *iter;
1298 int64_t cmp;
1299
1300 while (*p != NULL) {
1301 parent = *p;
1302 iter = rb_entry(parent, struct hist_entry, rb_node);
1303
1304 cmp = hist_entry__collapse(iter, he);
1305
1306 if (!cmp) {
1307 iter->count += he->count;
1308 hist_entry__free(he);
1309 return;
1310 }
1311
1312 if (cmp < 0)
1313 p = &(*p)->rb_left;
1314 else
1315 p = &(*p)->rb_right;
1316 }
1317
1318 rb_link_node(&he->rb_node, parent, p);
1319 rb_insert_color(&he->rb_node, &collapse_hists);
1320}
1321
1322static void collapse__resort(void)
1323{
1324 struct rb_node *next;
1325 struct hist_entry *n;
1326
1327 if (!sort__need_collapse)
1328 return;
1329
1330 next = rb_first(&hist);
1331 while (next) {
1332 n = rb_entry(next, struct hist_entry, rb_node);
1333 next = rb_next(&n->rb_node);
1334
1335 rb_erase(&n->rb_node, &hist);
1336 collapse__insert_entry(n);
1337 }
1338}
1339
1340/*
1341 * reverse the map, sort on count.
1342 */
1343
1344static struct rb_root output_hists;
1345
1346static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
1347{
1348 struct rb_node **p = &output_hists.rb_node;
1349 struct rb_node *parent = NULL;
1350 struct hist_entry *iter;
1351
1352 if (callchain)
1353 callchain_param.sort(&he->sorted_chain, &he->callchain,
1354 min_callchain_hits, &callchain_param);
1355
1356 while (*p != NULL) {
1357 parent = *p;
1358 iter = rb_entry(parent, struct hist_entry, rb_node);
1359
1360 if (he->count > iter->count)
1361 p = &(*p)->rb_left;
1362 else
1363 p = &(*p)->rb_right;
1364 }
1365
1366 rb_link_node(&he->rb_node, parent, p);
1367 rb_insert_color(&he->rb_node, &output_hists);
1368}
1369
1370static void output__resort(u64 total_samples)
1371{
1372 struct rb_node *next;
1373 struct hist_entry *n;
1374 struct rb_root *tree = &hist;
1375 u64 min_callchain_hits;
1376
1377 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
1378
1379 if (sort__need_collapse)
1380 tree = &collapse_hists;
1381
1382 next = rb_first(tree);
1383
1384 while (next) {
1385 n = rb_entry(next, struct hist_entry, rb_node);
1386 next = rb_next(&n->rb_node);
1387
1388 rb_erase(&n->rb_node, tree);
1389 output__insert_entry(n, min_callchain_hits);
1390 }
1391}
1392
1393static size_t output__fprintf(FILE *fp, u64 total_samples)
1394{
1395 struct hist_entry *pos;
1396 struct sort_entry *se;
1397 struct rb_node *nd;
1398 size_t ret = 0;
1399 unsigned int width;
1400 char *col_width = col_width_list_str;
1401
1402 init_rem_hits();
1403
1404 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1405 fprintf(fp, "#\n");
1406
1407 fprintf(fp, "# Overhead");
1408 if (show_nr_samples) {
1409 if (field_sep)
1410 fprintf(fp, "%cSamples", *field_sep);
1411 else
1412 fputs(" Samples ", fp);
1413 }
1414 list_for_each_entry(se, &hist_entry__sort_list, list) {
1415 if (se->elide)
1416 continue;
1417 if (field_sep) {
1418 fprintf(fp, "%c%s", *field_sep, se->header);
1419 continue;
1420 }
1421 width = strlen(se->header);
1422 if (se->width) {
1423 if (col_width_list_str) {
1424 if (col_width) {
1425 *se->width = atoi(col_width);
1426 col_width = strchr(col_width, ',');
1427 if (col_width)
1428 ++col_width;
1429 }
1430 }
1431 width = *se->width = max(*se->width, width);
1432 }
1433 fprintf(fp, " %*s", width, se->header);
1434 }
1435 fprintf(fp, "\n");
1436
1437 if (field_sep)
1438 goto print_entries;
1439
1440 fprintf(fp, "# ........");
1441 if (show_nr_samples)
1442 fprintf(fp, " ..........");
1443 list_for_each_entry(se, &hist_entry__sort_list, list) {
1444 unsigned int i;
1445
1446 if (se->elide)
1447 continue;
1448
1449 fprintf(fp, " ");
1450 if (se->width)
1451 width = *se->width;
1452 else
1453 width = strlen(se->header);
1454 for (i = 0; i < width; i++)
1455 fprintf(fp, ".");
1456 }
1457 fprintf(fp, "\n");
1458
1459 fprintf(fp, "#\n");
1460
1461print_entries:
1462 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1463 pos = rb_entry(nd, struct hist_entry, rb_node);
1464 ret += hist_entry__fprintf(fp, pos, total_samples);
1465 }
1466
1467 if (sort_order == default_sort_order &&
1468 parent_pattern == default_parent_pattern) {
1469 fprintf(fp, "#\n");
1470 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1471 fprintf(fp, "#\n");
1472 }
1473 fprintf(fp, "\n");
1474
1475 free(rem_sq_bracket);
1476
1477 return ret;
1478}
1479
1480static void register_idle_thread(void)
1481{
1482 struct thread *thread = threads__findnew(0);
1483
1484 if (thread == NULL ||
1485 thread__set_comm(thread, "[idle]")) {
1486 fprintf(stderr, "problem inserting idle task.\n");
1487 exit(-1);
1488 }
1489}
1490
1491static unsigned long total = 0,
1492 total_mmap = 0,
1493 total_comm = 0,
1494 total_fork = 0,
1495 total_unknown = 0,
1496 total_lost = 0;
1497
1498static int validate_chain(struct ip_callchain *chain, event_t *event)
1499{
1500 unsigned int chain_size;
1501
1502 chain_size = event->header.size;
1503 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
1504
1505 if (chain->nr*sizeof(u64) > chain_size)
1506 return -1;
1507
1508 return 0;
1509}
1510
1511static int
1512process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1513{
1514 char level;
1515 int show = 0;
1516 struct dso *dso = NULL;
1517 struct thread *thread = threads__findnew(event->ip.pid);
1518 u64 ip = event->ip.ip;
1519 u64 period = 1;
1520 struct map *map = NULL;
1521 void *more_data = event->ip.__more_data;
1522 struct ip_callchain *chain = NULL;
1523 int cpumode;
1524
1525 if (sample_type & PERF_SAMPLE_PERIOD) {
1526 period = *(u64 *)more_data;
1527 more_data += sizeof(u64);
1528 }
1529
1530 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1531 (void *)(offset + head),
1532 (void *)(long)(event->header.size),
1533 event->header.misc,
1534 event->ip.pid, event->ip.tid,
1535 (void *)(long)ip,
1536 (long long)period);
1537
1538 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1539 unsigned int i;
1540
1541 chain = (void *)more_data;
1542
1543 dprintf("... chain: nr:%Lu\n", chain->nr);
1544
1545 if (validate_chain(chain, event) < 0) {
1546 eprintf("call-chain problem with event, skipping it.\n");
1547 return 0;
1548 }
1549
1550 if (dump_trace) {
1551 for (i = 0; i < chain->nr; i++)
1552 dprintf("..... %2d: %016Lx\n", i, chain->ips[i]);
1553 }
1554 }
1555
1556 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1557
1558 if (thread == NULL) {
1559 eprintf("problem processing %d event, skipping it.\n",
1560 event->header.type);
1561 return -1;
1562 }
1563
1564 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1565 return 0;
1566
1567 cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
1568
1569 if (cpumode == PERF_EVENT_MISC_KERNEL) {
1570 show = SHOW_KERNEL;
1571 level = 'k';
1572
1573 dso = kernel_dso;
1574
1575 dprintf(" ...... dso: %s\n", dso->name);
1576
1577 } else if (cpumode == PERF_EVENT_MISC_USER) {
1578
1579 show = SHOW_USER;
1580 level = '.';
1581
1582 } else {
1583 show = SHOW_HV;
1584 level = 'H';
1585
1586 dso = hypervisor_dso;
1587
1588 dprintf(" ...... dso: [hypervisor]\n");
1589 }
1590
1591 if (show & show_mask) {
1592 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1593
1594 if (dso_list && (!dso || !dso->name ||
1595 !strlist__has_entry(dso_list, dso->name)))
1596 return 0;
1597
1598 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1599 return 0;
1600
1601 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1602 eprintf("problem incrementing symbol count, skipping event\n");
1603 return -1;
1604 }
1605 }
1606 total += period;
1607
1608 return 0;
1609}
1610
1611static int
1612process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1613{
1614 struct thread *thread = threads__findnew(event->mmap.pid);
1615 struct map *map = map__new(&event->mmap);
1616
1617 dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1618 (void *)(offset + head),
1619 (void *)(long)(event->header.size),
1620 event->mmap.pid,
1621 event->mmap.tid,
1622 (void *)(long)event->mmap.start,
1623 (void *)(long)event->mmap.len,
1624 (void *)(long)event->mmap.pgoff,
1625 event->mmap.filename);
1626
1627 if (thread == NULL || map == NULL) {
1628 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
1629 return 0;
1630 }
1631
1632 thread__insert_map(thread, map);
1633 total_mmap++;
1634
1635 return 0;
1636}
1637
1638static int
1639process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1640{
1641 struct thread *thread = threads__findnew(event->comm.pid);
1642
1643 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
1644 (void *)(offset + head),
1645 (void *)(long)(event->header.size),
1646 event->comm.comm, event->comm.pid);
1647
1648 if (thread == NULL ||
1649 thread__set_comm(thread, event->comm.comm)) {
1650 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
1651 return -1;
1652 }
1653 total_comm++;
1654
1655 return 0;
1656}
1657
1658static int
1659process_task_event(event_t *event, unsigned long offset, unsigned long head)
1660{
1661 struct thread *thread = threads__findnew(event->fork.pid);
1662 struct thread *parent = threads__findnew(event->fork.ppid);
1663
1664 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
1665 (void *)(offset + head),
1666 (void *)(long)(event->header.size),
1667 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1668 event->fork.pid, event->fork.tid,
1669 event->fork.ppid, event->fork.ptid);
1670
1671 /*
1672 * A thread clone will have the same PID for both
1673 * parent and child.
1674 */
1675 if (thread == parent)
1676 return 0;
1677
1678 if (event->header.type == PERF_EVENT_EXIT)
1679 return 0;
1680
1681 if (!thread || !parent || thread__fork(thread, parent)) {
1682 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
1683 return -1;
1684 }
1685 total_fork++;
1686
1687 return 0;
1688}
1689
1690static int
1691process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1692{
1693 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
1694 (void *)(offset + head),
1695 (void *)(long)(event->header.size),
1696 event->lost.id,
1697 event->lost.lost);
1698
1699 total_lost += event->lost.lost;
1700
1701 return 0;
1702}
1703
1704static void trace_event(event_t *event)
1705{
1706 unsigned char *raw_event = (void *)event;
1707 char *color = PERF_COLOR_BLUE;
1708 int i, j;
1709
1710 if (!dump_trace)
1711 return;
1712
1713 dprintf(".");
1714 cdprintf("\n. ... raw event: size %d bytes\n", event->header.size);
1715
1716 for (i = 0; i < event->header.size; i++) {
1717 if ((i & 15) == 0) {
1718 dprintf(".");
1719 cdprintf(" %04x: ", i);
1720 }
1721
1722 cdprintf(" %02x", raw_event[i]);
1723
1724 if (((i & 15) == 15) || i == event->header.size-1) {
1725 cdprintf(" ");
1726 for (j = 0; j < 15-(i & 15); j++)
1727 cdprintf(" ");
1728 for (j = 0; j < (i & 15); j++) {
1729 if (isprint(raw_event[i-15+j]))
1730 cdprintf("%c", raw_event[i-15+j]);
1731 else
1732 cdprintf(".");
1733 }
1734 cdprintf("\n");
1735 }
1736 }
1737 dprintf(".\n");
1738}
1739
1740static struct perf_header *header;
1741
1742static struct perf_counter_attr *perf_header__find_attr(u64 id)
1743{
1744 int i;
1745
1746 for (i = 0; i < header->attrs; i++) {
1747 struct perf_header_attr *attr = header->attr[i];
1748 int j;
1749
1750 for (j = 0; j < attr->ids; j++) {
1751 if (attr->id[j] == id)
1752 return &attr->attr;
1753 }
1754 }
1755
1756 return NULL;
1757}
1758
1759static int
1760process_read_event(event_t *event, unsigned long offset, unsigned long head)
1761{
1762 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1763
1764 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
1765 (void *)(offset + head),
1766 (void *)(long)(event->header.size),
1767 event->read.pid,
1768 event->read.tid,
1769 attr ? __event_name(attr->type, attr->config)
1770 : "FAIL",
1771 event->read.value);
1772
1773 return 0;
1774}
1775
1776static int
1777process_event(event_t *event, unsigned long offset, unsigned long head)
1778{
1779 trace_event(event);
1780
1781 switch (event->header.type) {
1782 case PERF_EVENT_SAMPLE:
1783 return process_sample_event(event, offset, head);
1784
1785 case PERF_EVENT_MMAP:
1786 return process_mmap_event(event, offset, head);
1787
1788 case PERF_EVENT_COMM:
1789 return process_comm_event(event, offset, head);
1790
1791 case PERF_EVENT_FORK:
1792 case PERF_EVENT_EXIT:
1793 return process_task_event(event, offset, head);
1794
1795 case PERF_EVENT_LOST:
1796 return process_lost_event(event, offset, head);
1797
1798 case PERF_EVENT_READ:
1799 return process_read_event(event, offset, head);
1800
1801 /*
1802 * We dont process them right now but they are fine:
1803 */
1804
1805 case PERF_EVENT_THROTTLE:
1806 case PERF_EVENT_UNTHROTTLE:
1807 return 0;
1808
1809 default:
1810 return -1;
1811 }
1812
1813 return 0;
1814}
1815
1816static u64 perf_header__sample_type(void)
1817{
1818 u64 sample_type = 0;
1819 int i;
1820
1821 for (i = 0; i < header->attrs; i++) {
1822 struct perf_header_attr *attr = header->attr[i];
1823
1824 if (!sample_type)
1825 sample_type = attr->attr.sample_type;
1826 else if (sample_type != attr->attr.sample_type)
1827 die("non matching sample_type");
1828 }
1829
1830 return sample_type;
1831}
1832
1833static int __cmd_report(void)
1834{
1835 int ret, rc = EXIT_FAILURE;
1836 unsigned long offset = 0;
1837 unsigned long head, shift;
1838 struct stat stat;
1839 event_t *event;
1840 uint32_t size;
1841 char *buf;
1842
1843 register_idle_thread();
1844
1845 input = open(input_name, O_RDONLY);
1846 if (input < 0) {
1847 fprintf(stderr, " failed to open file: %s", input_name);
1848 if (!strcmp(input_name, "perf.data"))
1849 fprintf(stderr, " (try 'perf record' first)");
1850 fprintf(stderr, "\n");
1851 exit(-1);
1852 }
1853
1854 ret = fstat(input, &stat);
1855 if (ret < 0) {
1856 perror("failed to stat file");
1857 exit(-1);
1858 }
1859
1860 if (!force && (stat.st_uid != geteuid())) {
1861 fprintf(stderr, "file: %s not owned by current user\n", input_name);
1862 exit(-1);
1863 }
1864
1865 if (!stat.st_size) {
1866 fprintf(stderr, "zero-sized file, nothing to do!\n");
1867 exit(0);
1868 }
1869
1870 header = perf_header__read(input);
1871 head = header->data_offset;
1872
1873 sample_type = perf_header__sample_type();
1874
1875 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1876 if (sort__has_parent) {
1877 fprintf(stderr, "selected --sort parent, but no"
1878 " callchain data. Did you call"
1879 " perf record without -g?\n");
1880 exit(-1);
1881 }
1882 if (callchain) {
1883 fprintf(stderr, "selected -c but no callchain data."
1884 " Did you call perf record without"
1885 " -g?\n");
1886 exit(-1);
1887 }
1888 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1889 callchain = 1;
1890 if (register_callchain_param(&callchain_param) < 0) {
1891 fprintf(stderr, "Can't register callchain"
1892 " params\n");
1893 exit(-1);
1894 }
1895 }
1896
1897 if (load_kernel() < 0) {
1898 perror("failed to load kernel symbols");
1899 return EXIT_FAILURE;
1900 }
1901
1902 if (!full_paths) {
1903 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1904 perror("failed to get the current directory");
1905 return EXIT_FAILURE;
1906 }
1907 cwdlen = strlen(cwd);
1908 } else {
1909 cwd = NULL;
1910 cwdlen = 0;
1911 }
1912
1913 shift = page_size * (head / page_size);
1914 offset += shift;
1915 head -= shift;
1916
1917remap:
1918 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1919 MAP_SHARED, input, offset);
1920 if (buf == MAP_FAILED) {
1921 perror("failed to mmap file");
1922 exit(-1);
1923 }
1924
1925more:
1926 event = (event_t *)(buf + head);
1927
1928 size = event->header.size;
1929 if (!size)
1930 size = 8;
1931
1932 if (head + event->header.size >= page_size * mmap_window) {
1933 int ret;
1934
1935 shift = page_size * (head / page_size);
1936
1937 ret = munmap(buf, page_size * mmap_window);
1938 assert(ret == 0);
1939
1940 offset += shift;
1941 head -= shift;
1942 goto remap;
1943 }
1944
1945 size = event->header.size;
1946
1947 dprintf("\n%p [%p]: event: %d\n",
1948 (void *)(offset + head),
1949 (void *)(long)event->header.size,
1950 event->header.type);
1951
1952 if (!size || process_event(event, offset, head) < 0) {
1953
1954 dprintf("%p [%p]: skipping unknown header type: %d\n",
1955 (void *)(offset + head),
1956 (void *)(long)(event->header.size),
1957 event->header.type);
1958
1959 total_unknown++;
1960
1961 /*
1962 * assume we lost track of the stream, check alignment, and
1963 * increment a single u64 in the hope to catch on again 'soon'.
1964 */
1965
1966 if (unlikely(head & 7))
1967 head &= ~7ULL;
1968
1969 size = 8;
1970 }
1971
1972 head += size;
1973
1974 if (offset + head >= header->data_offset + header->data_size)
1975 goto done;
1976
1977 if (offset + head < (unsigned long)stat.st_size)
1978 goto more;
1979
1980done:
1981 rc = EXIT_SUCCESS;
1982 close(input);
1983
1984 dprintf(" IP events: %10ld\n", total);
1985 dprintf(" mmap events: %10ld\n", total_mmap);
1986 dprintf(" comm events: %10ld\n", total_comm);
1987 dprintf(" fork events: %10ld\n", total_fork);
1988 dprintf(" lost events: %10ld\n", total_lost);
1989 dprintf(" unknown events: %10ld\n", total_unknown);
1990
1991 if (dump_trace)
1992 return 0;
1993
1994 if (verbose >= 3)
1995 threads__fprintf(stdout);
1996
1997 if (verbose >= 2)
1998 dsos__fprintf(stdout);
1999
2000 collapse__resort();
2001 output__resort(total);
2002 output__fprintf(stdout, total);
2003
2004 return rc;
2005}
2006
2007static int
2008parse_callchain_opt(const struct option *opt __used, const char *arg,
2009 int unset __used)
2010{
2011 char *tok;
2012 char *endptr;
2013
2014 callchain = 1;
2015
2016 if (!arg)
2017 return 0;
2018
2019 tok = strtok((char *)arg, ",");
2020 if (!tok)
2021 return -1;
2022
2023 /* get the output mode */
2024 if (!strncmp(tok, "graph", strlen(arg)))
2025 callchain_param.mode = CHAIN_GRAPH_ABS;
2026
2027 else if (!strncmp(tok, "flat", strlen(arg)))
2028 callchain_param.mode = CHAIN_FLAT;
2029
2030 else if (!strncmp(tok, "fractal", strlen(arg)))
2031 callchain_param.mode = CHAIN_GRAPH_REL;
2032
2033 else if (!strncmp(tok, "none", strlen(arg))) {
2034 callchain_param.mode = CHAIN_NONE;
2035 callchain = 0;
2036
2037 return 0;
2038 }
2039
2040 else
2041 return -1;
2042
2043 /* get the min percentage */
2044 tok = strtok(NULL, ",");
2045 if (!tok)
2046 goto setup;
2047
2048 callchain_param.min_percent = strtod(tok, &endptr);
2049 if (tok == endptr)
2050 return -1;
2051
2052setup:
2053 if (register_callchain_param(&callchain_param) < 0) {
2054 fprintf(stderr, "Can't register callchain params\n");
2055 return -1;
2056 }
2057 return 0;
2058}
2059
2060static const char * const report_usage[] = {
2061 "perf report [<options>] <command>",
2062 NULL
2063};
2064
2065static const struct option options[] = {
2066 OPT_STRING('i', "input", &input_name, "file",
2067 "input file name"),
2068 OPT_BOOLEAN('v', "verbose", &verbose,
2069 "be more verbose (show symbol address, etc)"),
2070 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
2071 "dump raw trace in ASCII"),
2072 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
2073 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
2074 OPT_BOOLEAN('m', "modules", &modules,
2075 "load module symbols - WARNING: use only with -k and LIVE kernel"),
2076 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2077 "Show a column with the number of samples"),
2078 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
2079 "sort by key(s): pid, comm, dso, symbol, parent"),
2080 OPT_BOOLEAN('P', "full-paths", &full_paths,
2081 "Don't shorten the pathnames taking into account the cwd"),
2082 OPT_STRING('p', "parent", &parent_pattern, "regex",
2083 "regex filter to identify parent, see: '--sort parent'"),
2084 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
2085 "Only display entries with parent-match"),
2086 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
2087 "Display callchains using output_type and min percent threshold. "
2088 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
2089 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
2090 "only consider symbols in these dsos"),
2091 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
2092 "only consider symbols in these comms"),
2093 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
2094 "only consider these symbols"),
2095 OPT_STRING('w', "column-widths", &col_width_list_str,
2096 "width[,width...]",
2097 "don't try to adjust column width, use these fixed values"),
2098 OPT_STRING('t', "field-separator", &field_sep, "separator",
2099 "separator for columns, no spaces will be added between "
2100 "columns '.' is reserved."),
2101 OPT_END()
2102};
2103
2104static void setup_sorting(void)
2105{
2106 char *tmp, *tok, *str = strdup(sort_order);
2107
2108 for (tok = strtok_r(str, ", ", &tmp);
2109 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2110 if (sort_dimension__add(tok) < 0) {
2111 error("Unknown --sort key: `%s'", tok);
2112 usage_with_options(report_usage, options);
2113 }
2114 }
2115
2116 free(str);
2117}
2118
2119static void setup_list(struct strlist **list, const char *list_str,
2120 struct sort_entry *se, const char *list_name,
2121 FILE *fp)
2122{
2123 if (list_str) {
2124 *list = strlist__new(true, list_str);
2125 if (!*list) {
2126 fprintf(stderr, "problems parsing %s list\n",
2127 list_name);
2128 exit(129);
2129 }
2130 if (strlist__nr_entries(*list) == 1) {
2131 fprintf(fp, "# %s: %s\n", list_name,
2132 strlist__entry(*list, 0)->s);
2133 se->elide = true;
2134 }
2135 }
2136}
2137
2138int cmd_report(int argc, const char **argv, const char *prefix __used)
2139{
2140 symbol__init();
2141
2142 page_size = getpagesize();
2143
2144 argc = parse_options(argc, argv, options, report_usage, 0);
2145
2146 setup_sorting();
2147
2148 if (parent_pattern != default_parent_pattern) {
2149 sort_dimension__add("parent");
2150 sort_parent.elide = 1;
2151 } else
2152 exclude_other = 0;
2153
2154 /*
2155 * Any (unrecognized) arguments left?
2156 */
2157 if (argc)
2158 usage_with_options(report_usage, options);
2159
2160 setup_pager();
2161
2162 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2163 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2164 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
2165
2166 if (field_sep && *field_sep == '.') {
2167 fputs("'.' is the only non valid --field-separator argument\n",
2168 stderr);
2169 exit(129);
2170 }
2171
2172 return __cmd_report();
2173}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
new file mode 100644
index 000000000000..b4b06c7903e1
--- /dev/null
+++ b/tools/perf/builtin-stat.c
@@ -0,0 +1,552 @@
1/*
2 * builtin-stat.c
3 *
4 * Builtin stat command: Give a precise performance counters summary
5 * overview about any workload, CPU or specific PID.
6 *
7 * Sample output:
8
9 $ perf stat ~/hackbench 10
10 Time: 0.104
11
12 Performance counter stats for '/home/mingo/hackbench':
13
14 1255.538611 task clock ticks # 10.143 CPU utilization factor
15 54011 context switches # 0.043 M/sec
16 385 CPU migrations # 0.000 M/sec
17 17755 pagefaults # 0.014 M/sec
18 3808323185 CPU cycles # 3033.219 M/sec
19 1575111190 instructions # 1254.530 M/sec
20 17367895 cache references # 13.833 M/sec
21 7674421 cache misses # 6.112 M/sec
22
23 Wall-clock time elapsed: 123.786620 msecs
24
25 *
26 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
27 *
28 * Improvements and fixes by:
29 *
30 * Arjan van de Ven <arjan@linux.intel.com>
31 * Yanmin Zhang <yanmin.zhang@intel.com>
32 * Wu Fengguang <fengguang.wu@intel.com>
33 * Mike Galbraith <efault@gmx.de>
34 * Paul Mackerras <paulus@samba.org>
35 * Jaswinder Singh Rajput <jaswinder@kernel.org>
36 *
37 * Released under the GPL v2. (and only v2, not any later version)
38 */
39
40#include "perf.h"
41#include "builtin.h"
42#include "util/util.h"
43#include "util/parse-options.h"
44#include "util/parse-events.h"
45
46#include <sys/prctl.h>
47#include <math.h>
48
49static struct perf_counter_attr default_attrs[] = {
50
51 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
52 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
53 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
54 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
55
56 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
57 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
58 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES},
59 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
60
61};
62
63#define MAX_RUN 100
64
65static int system_wide = 0;
66static int verbose = 0;
67static unsigned int nr_cpus = 0;
68static int run_idx = 0;
69
70static int run_count = 1;
71static int inherit = 1;
72static int scale = 1;
73static int target_pid = -1;
74static int null_run = 0;
75
76static int fd[MAX_NR_CPUS][MAX_COUNTERS];
77
78static u64 runtime_nsecs[MAX_RUN];
79static u64 walltime_nsecs[MAX_RUN];
80static u64 runtime_cycles[MAX_RUN];
81
82static u64 event_res[MAX_RUN][MAX_COUNTERS][3];
83static u64 event_scaled[MAX_RUN][MAX_COUNTERS];
84
85static u64 event_res_avg[MAX_COUNTERS][3];
86static u64 event_res_noise[MAX_COUNTERS][3];
87
88static u64 event_scaled_avg[MAX_COUNTERS];
89
90static u64 runtime_nsecs_avg;
91static u64 runtime_nsecs_noise;
92
93static u64 walltime_nsecs_avg;
94static u64 walltime_nsecs_noise;
95
96static u64 runtime_cycles_avg;
97static u64 runtime_cycles_noise;
98
99#define MATCH_EVENT(t, c, counter) \
100 (attrs[counter].type == PERF_TYPE_##t && \
101 attrs[counter].config == PERF_COUNT_##c)
102
103#define ERR_PERF_OPEN \
104"Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n"
105
106static void create_perf_stat_counter(int counter, int pid)
107{
108 struct perf_counter_attr *attr = attrs + counter;
109
110 if (scale)
111 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
112 PERF_FORMAT_TOTAL_TIME_RUNNING;
113
114 if (system_wide) {
115 unsigned int cpu;
116
117 for (cpu = 0; cpu < nr_cpus; cpu++) {
118 fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
119 if (fd[cpu][counter] < 0 && verbose)
120 fprintf(stderr, ERR_PERF_OPEN, counter,
121 fd[cpu][counter], strerror(errno));
122 }
123 } else {
124 attr->inherit = inherit;
125 attr->disabled = 1;
126 attr->enable_on_exec = 1;
127
128 fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0);
129 if (fd[0][counter] < 0 && verbose)
130 fprintf(stderr, ERR_PERF_OPEN, counter,
131 fd[0][counter], strerror(errno));
132 }
133}
134
135/*
136 * Does the counter have nsecs as a unit?
137 */
138static inline int nsec_counter(int counter)
139{
140 if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) ||
141 MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
142 return 1;
143
144 return 0;
145}
146
147/*
148 * Read out the results of a single counter:
149 */
150static void read_counter(int counter)
151{
152 u64 *count, single_count[3];
153 unsigned int cpu;
154 size_t res, nv;
155 int scaled;
156
157 count = event_res[run_idx][counter];
158
159 count[0] = count[1] = count[2] = 0;
160
161 nv = scale ? 3 : 1;
162 for (cpu = 0; cpu < nr_cpus; cpu++) {
163 if (fd[cpu][counter] < 0)
164 continue;
165
166 res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
167 assert(res == nv * sizeof(u64));
168
169 close(fd[cpu][counter]);
170 fd[cpu][counter] = -1;
171
172 count[0] += single_count[0];
173 if (scale) {
174 count[1] += single_count[1];
175 count[2] += single_count[2];
176 }
177 }
178
179 scaled = 0;
180 if (scale) {
181 if (count[2] == 0) {
182 event_scaled[run_idx][counter] = -1;
183 count[0] = 0;
184 return;
185 }
186
187 if (count[2] < count[1]) {
188 event_scaled[run_idx][counter] = 1;
189 count[0] = (unsigned long long)
190 ((double)count[0] * count[1] / count[2] + 0.5);
191 }
192 }
193 /*
194 * Save the full runtime - to allow normalization during printout:
195 */
196 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
197 runtime_nsecs[run_idx] = count[0];
198 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
199 runtime_cycles[run_idx] = count[0];
200}
201
202static int run_perf_stat(int argc __used, const char **argv)
203{
204 unsigned long long t0, t1;
205 int status = 0;
206 int counter;
207 int pid;
208 int child_ready_pipe[2], go_pipe[2];
209 char buf;
210
211 if (!system_wide)
212 nr_cpus = 1;
213
214 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
215 perror("failed to create pipes");
216 exit(1);
217 }
218
219 if ((pid = fork()) < 0)
220 perror("failed to fork");
221
222 if (!pid) {
223 close(child_ready_pipe[0]);
224 close(go_pipe[1]);
225 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
226
227 /*
228 * Do a dummy execvp to get the PLT entry resolved,
229 * so we avoid the resolver overhead on the real
230 * execvp call.
231 */
232 execvp("", (char **)argv);
233
234 /*
235 * Tell the parent we're ready to go
236 */
237 close(child_ready_pipe[1]);
238
239 /*
240 * Wait until the parent tells us to go.
241 */
242 if (read(go_pipe[0], &buf, 1) == -1)
243 perror("unable to read pipe");
244
245 execvp(argv[0], (char **)argv);
246
247 perror(argv[0]);
248 exit(-1);
249 }
250
251 /*
252 * Wait for the child to be ready to exec.
253 */
254 close(child_ready_pipe[1]);
255 close(go_pipe[0]);
256 if (read(child_ready_pipe[0], &buf, 1) == -1)
257 perror("unable to read pipe");
258 close(child_ready_pipe[0]);
259
260 for (counter = 0; counter < nr_counters; counter++)
261 create_perf_stat_counter(counter, pid);
262
263 /*
264 * Enable counters and exec the command:
265 */
266 t0 = rdclock();
267
268 close(go_pipe[1]);
269 wait(&status);
270
271 t1 = rdclock();
272
273 walltime_nsecs[run_idx] = t1 - t0;
274
275 for (counter = 0; counter < nr_counters; counter++)
276 read_counter(counter);
277
278 return WEXITSTATUS(status);
279}
280
281static void print_noise(u64 *count, u64 *noise)
282{
283 if (run_count > 1)
284 fprintf(stderr, " ( +- %7.3f%% )",
285 (double)noise[0]/(count[0]+1)*100.0);
286}
287
288static void nsec_printout(int counter, u64 *count, u64 *noise)
289{
290 double msecs = (double)count[0] / 1000000;
291
292 fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter));
293
294 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
295 if (walltime_nsecs_avg)
296 fprintf(stderr, " # %10.3f CPUs ",
297 (double)count[0] / (double)walltime_nsecs_avg);
298 }
299 print_noise(count, noise);
300}
301
302static void abs_printout(int counter, u64 *count, u64 *noise)
303{
304 fprintf(stderr, " %14Ld %-24s", count[0], event_name(counter));
305
306 if (runtime_cycles_avg &&
307 MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
308 fprintf(stderr, " # %10.3f IPC ",
309 (double)count[0] / (double)runtime_cycles_avg);
310 } else {
311 if (runtime_nsecs_avg) {
312 fprintf(stderr, " # %10.3f M/sec",
313 (double)count[0]/runtime_nsecs_avg*1000.0);
314 }
315 }
316 print_noise(count, noise);
317}
318
319/*
320 * Print out the results of a single counter:
321 */
322static void print_counter(int counter)
323{
324 u64 *count, *noise;
325 int scaled;
326
327 count = event_res_avg[counter];
328 noise = event_res_noise[counter];
329 scaled = event_scaled_avg[counter];
330
331 if (scaled == -1) {
332 fprintf(stderr, " %14s %-24s\n",
333 "<not counted>", event_name(counter));
334 return;
335 }
336
337 if (nsec_counter(counter))
338 nsec_printout(counter, count, noise);
339 else
340 abs_printout(counter, count, noise);
341
342 if (scaled)
343 fprintf(stderr, " (scaled from %.2f%%)",
344 (double) count[2] / count[1] * 100);
345
346 fprintf(stderr, "\n");
347}
348
349/*
350 * normalize_noise noise values down to stddev:
351 */
352static void normalize_noise(u64 *val)
353{
354 double res;
355
356 res = (double)*val / (run_count * sqrt((double)run_count));
357
358 *val = (u64)res;
359}
360
361static void update_avg(const char *name, int idx, u64 *avg, u64 *val)
362{
363 *avg += *val;
364
365 if (verbose > 1)
366 fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val);
367}
368/*
369 * Calculate the averages and noises:
370 */
371static void calc_avg(void)
372{
373 int i, j;
374
375 if (verbose > 1)
376 fprintf(stderr, "\n");
377
378 for (i = 0; i < run_count; i++) {
379 update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i);
380 update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i);
381 update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i);
382
383 for (j = 0; j < nr_counters; j++) {
384 update_avg("counter/0", j,
385 event_res_avg[j]+0, event_res[i][j]+0);
386 update_avg("counter/1", j,
387 event_res_avg[j]+1, event_res[i][j]+1);
388 update_avg("counter/2", j,
389 event_res_avg[j]+2, event_res[i][j]+2);
390 if (event_scaled[i][j] != (u64)-1)
391 update_avg("scaled", j,
392 event_scaled_avg + j, event_scaled[i]+j);
393 else
394 event_scaled_avg[j] = -1;
395 }
396 }
397 runtime_nsecs_avg /= run_count;
398 walltime_nsecs_avg /= run_count;
399 runtime_cycles_avg /= run_count;
400
401 for (j = 0; j < nr_counters; j++) {
402 event_res_avg[j][0] /= run_count;
403 event_res_avg[j][1] /= run_count;
404 event_res_avg[j][2] /= run_count;
405 }
406
407 for (i = 0; i < run_count; i++) {
408 runtime_nsecs_noise +=
409 abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg));
410 walltime_nsecs_noise +=
411 abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg));
412 runtime_cycles_noise +=
413 abs((s64)(runtime_cycles[i] - runtime_cycles_avg));
414
415 for (j = 0; j < nr_counters; j++) {
416 event_res_noise[j][0] +=
417 abs((s64)(event_res[i][j][0] - event_res_avg[j][0]));
418 event_res_noise[j][1] +=
419 abs((s64)(event_res[i][j][1] - event_res_avg[j][1]));
420 event_res_noise[j][2] +=
421 abs((s64)(event_res[i][j][2] - event_res_avg[j][2]));
422 }
423 }
424
425 normalize_noise(&runtime_nsecs_noise);
426 normalize_noise(&walltime_nsecs_noise);
427 normalize_noise(&runtime_cycles_noise);
428
429 for (j = 0; j < nr_counters; j++) {
430 normalize_noise(&event_res_noise[j][0]);
431 normalize_noise(&event_res_noise[j][1]);
432 normalize_noise(&event_res_noise[j][2]);
433 }
434}
435
436static void print_stat(int argc, const char **argv)
437{
438 int i, counter;
439
440 calc_avg();
441
442 fflush(stdout);
443
444 fprintf(stderr, "\n");
445 fprintf(stderr, " Performance counter stats for \'%s", argv[0]);
446
447 for (i = 1; i < argc; i++)
448 fprintf(stderr, " %s", argv[i]);
449
450 fprintf(stderr, "\'");
451 if (run_count > 1)
452 fprintf(stderr, " (%d runs)", run_count);
453 fprintf(stderr, ":\n\n");
454
455 for (counter = 0; counter < nr_counters; counter++)
456 print_counter(counter);
457
458 fprintf(stderr, "\n");
459 fprintf(stderr, " %14.9f seconds time elapsed",
460 (double)walltime_nsecs_avg/1e9);
461 if (run_count > 1) {
462 fprintf(stderr, " ( +- %7.3f%% )",
463 100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg);
464 }
465 fprintf(stderr, "\n\n");
466}
467
468static volatile int signr = -1;
469
470static void skip_signal(int signo)
471{
472 signr = signo;
473}
474
475static void sig_atexit(void)
476{
477 if (signr == -1)
478 return;
479
480 signal(signr, SIG_DFL);
481 kill(getpid(), signr);
482}
483
484static const char * const stat_usage[] = {
485 "perf stat [<options>] <command>",
486 NULL
487};
488
489static const struct option options[] = {
490 OPT_CALLBACK('e', "event", NULL, "event",
491 "event selector. use 'perf list' to list available events",
492 parse_events),
493 OPT_BOOLEAN('i', "inherit", &inherit,
494 "child tasks inherit counters"),
495 OPT_INTEGER('p', "pid", &target_pid,
496 "stat events on existing pid"),
497 OPT_BOOLEAN('a', "all-cpus", &system_wide,
498 "system-wide collection from all CPUs"),
499 OPT_BOOLEAN('c', "scale", &scale,
500 "scale/normalize counters"),
501 OPT_BOOLEAN('v', "verbose", &verbose,
502 "be more verbose (show counter open errors, etc)"),
503 OPT_INTEGER('r', "repeat", &run_count,
504 "repeat command and print average + stddev (max: 100)"),
505 OPT_BOOLEAN('n', "null", &null_run,
506 "null run - dont start any counters"),
507 OPT_END()
508};
509
510int cmd_stat(int argc, const char **argv, const char *prefix __used)
511{
512 int status;
513
514 argc = parse_options(argc, argv, options, stat_usage,
515 PARSE_OPT_STOP_AT_NON_OPTION);
516 if (!argc)
517 usage_with_options(stat_usage, options);
518 if (run_count <= 0 || run_count > MAX_RUN)
519 usage_with_options(stat_usage, options);
520
521 /* Set attrs and nr_counters if no event is selected and !null_run */
522 if (!null_run && !nr_counters) {
523 memcpy(attrs, default_attrs, sizeof(default_attrs));
524 nr_counters = ARRAY_SIZE(default_attrs);
525 }
526
527 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
528 assert(nr_cpus <= MAX_NR_CPUS);
529 assert((int)nr_cpus >= 0);
530
531 /*
532 * We dont want to block the signals - that would cause
533 * child tasks to inherit that and Ctrl-C would not work.
534 * What we want is for Ctrl-C to work in the exec()-ed
535 * task, but being ignored by perf stat itself:
536 */
537 atexit(sig_atexit);
538 signal(SIGINT, skip_signal);
539 signal(SIGALRM, skip_signal);
540 signal(SIGABRT, skip_signal);
541
542 status = 0;
543 for (run_idx = 0; run_idx < run_count; run_idx++) {
544 if (run_count != 1 && verbose)
545 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
546 status = run_perf_stat(argc, argv);
547 }
548
549 print_stat(argc, argv);
550
551 return status;
552}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
new file mode 100644
index 000000000000..7de28ce9ca26
--- /dev/null
+++ b/tools/perf/builtin-top.c
@@ -0,0 +1,1220 @@
1/*
2 * builtin-top.c
3 *
4 * Builtin top command: Display a continuously updated profile of
5 * any workload, CPU or specific PID.
6 *
7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
8 *
9 * Improvements and fixes by:
10 *
11 * Arjan van de Ven <arjan@linux.intel.com>
12 * Yanmin Zhang <yanmin.zhang@intel.com>
13 * Wu Fengguang <fengguang.wu@intel.com>
14 * Mike Galbraith <efault@gmx.de>
15 * Paul Mackerras <paulus@samba.org>
16 *
17 * Released under the GPL v2. (and only v2, not any later version)
18 */
19#include "builtin.h"
20
21#include "perf.h"
22
23#include "util/symbol.h"
24#include "util/color.h"
25#include "util/util.h"
26#include <linux/rbtree.h>
27#include "util/parse-options.h"
28#include "util/parse-events.h"
29
30#include <assert.h>
31#include <fcntl.h>
32
33#include <stdio.h>
34#include <termios.h>
35#include <unistd.h>
36
37#include <errno.h>
38#include <time.h>
39#include <sched.h>
40#include <pthread.h>
41
42#include <sys/syscall.h>
43#include <sys/ioctl.h>
44#include <sys/poll.h>
45#include <sys/prctl.h>
46#include <sys/wait.h>
47#include <sys/uio.h>
48#include <sys/mman.h>
49
50#include <linux/unistd.h>
51#include <linux/types.h>
52
53static int fd[MAX_NR_CPUS][MAX_COUNTERS];
54
55static int system_wide = 0;
56
57static int default_interval = 100000;
58
59static int count_filter = 5;
60static int print_entries = 15;
61
62static int target_pid = -1;
63static int inherit = 0;
64static int profile_cpu = -1;
65static int nr_cpus = 0;
66static unsigned int realtime_prio = 0;
67static int group = 0;
68static unsigned int page_size;
69static unsigned int mmap_pages = 16;
70static int freq = 0;
71static int verbose = 0;
72static char *vmlinux = NULL;
73
74static int delay_secs = 2;
75static int zero;
76static int dump_symtab;
77
78/*
79 * Source
80 */
81
82struct source_line {
83 u64 eip;
84 unsigned long count[MAX_COUNTERS];
85 char *line;
86 struct source_line *next;
87};
88
89static char *sym_filter = NULL;
90struct sym_entry *sym_filter_entry = NULL;
91static int sym_pcnt_filter = 5;
92static int sym_counter = 0;
93static int display_weighted = -1;
94
95/*
96 * Symbols
97 */
98
99static u64 min_ip;
100static u64 max_ip = -1ll;
101
102struct sym_entry {
103 struct rb_node rb_node;
104 struct list_head node;
105 unsigned long count[MAX_COUNTERS];
106 unsigned long snap_count;
107 double weight;
108 int skip;
109 struct source_line *source;
110 struct source_line *lines;
111 struct source_line **lines_tail;
112 pthread_mutex_t source_lock;
113};
114
115/*
116 * Source functions
117 */
118
119static void parse_source(struct sym_entry *syme)
120{
121 struct symbol *sym;
122 struct module *module;
123 struct section *section = NULL;
124 FILE *file;
125 char command[PATH_MAX*2], *path = vmlinux;
126 u64 start, end, len;
127
128 if (!syme)
129 return;
130
131 if (syme->lines) {
132 pthread_mutex_lock(&syme->source_lock);
133 goto out_assign;
134 }
135
136 sym = (struct symbol *)(syme + 1);
137 module = sym->module;
138
139 if (module)
140 path = module->path;
141 if (!path)
142 return;
143
144 start = sym->obj_start;
145 if (!start)
146 start = sym->start;
147
148 if (module) {
149 section = module->sections->find_section(module->sections, ".text");
150 if (section)
151 start -= section->vma;
152 }
153
154 end = start + sym->end - sym->start + 1;
155 len = sym->end - sym->start;
156
157 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path);
158
159 file = popen(command, "r");
160 if (!file)
161 return;
162
163 pthread_mutex_lock(&syme->source_lock);
164 syme->lines_tail = &syme->lines;
165 while (!feof(file)) {
166 struct source_line *src;
167 size_t dummy = 0;
168 char *c;
169
170 src = malloc(sizeof(struct source_line));
171 assert(src != NULL);
172 memset(src, 0, sizeof(struct source_line));
173
174 if (getline(&src->line, &dummy, file) < 0)
175 break;
176 if (!src->line)
177 break;
178
179 c = strchr(src->line, '\n');
180 if (c)
181 *c = 0;
182
183 src->next = NULL;
184 *syme->lines_tail = src;
185 syme->lines_tail = &src->next;
186
187 if (strlen(src->line)>8 && src->line[8] == ':') {
188 src->eip = strtoull(src->line, NULL, 16);
189 if (section)
190 src->eip += section->vma;
191 }
192 if (strlen(src->line)>8 && src->line[16] == ':') {
193 src->eip = strtoull(src->line, NULL, 16);
194 if (section)
195 src->eip += section->vma;
196 }
197 }
198 pclose(file);
199out_assign:
200 sym_filter_entry = syme;
201 pthread_mutex_unlock(&syme->source_lock);
202}
203
204static void __zero_source_counters(struct sym_entry *syme)
205{
206 int i;
207 struct source_line *line;
208
209 line = syme->lines;
210 while (line) {
211 for (i = 0; i < nr_counters; i++)
212 line->count[i] = 0;
213 line = line->next;
214 }
215}
216
217static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
218{
219 struct source_line *line;
220
221 if (syme != sym_filter_entry)
222 return;
223
224 if (pthread_mutex_trylock(&syme->source_lock))
225 return;
226
227 if (!syme->source)
228 goto out_unlock;
229
230 for (line = syme->lines; line; line = line->next) {
231 if (line->eip == ip) {
232 line->count[counter]++;
233 break;
234 }
235 if (line->eip > ip)
236 break;
237 }
238out_unlock:
239 pthread_mutex_unlock(&syme->source_lock);
240}
241
242static void lookup_sym_source(struct sym_entry *syme)
243{
244 struct symbol *symbol = (struct symbol *)(syme + 1);
245 struct source_line *line;
246 char pattern[PATH_MAX];
247 char *idx;
248
249 sprintf(pattern, "<%s>:", symbol->name);
250
251 if (symbol->module) {
252 idx = strstr(pattern, "\t");
253 if (idx)
254 *idx = 0;
255 }
256
257 pthread_mutex_lock(&syme->source_lock);
258 for (line = syme->lines; line; line = line->next) {
259 if (strstr(line->line, pattern)) {
260 syme->source = line;
261 break;
262 }
263 }
264 pthread_mutex_unlock(&syme->source_lock);
265}
266
267static void show_lines(struct source_line *queue, int count, int total)
268{
269 int i;
270 struct source_line *line;
271
272 line = queue;
273 for (i = 0; i < count; i++) {
274 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
275
276 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line);
277 line = line->next;
278 }
279}
280
281#define TRACE_COUNT 3
282
283static void show_details(struct sym_entry *syme)
284{
285 struct symbol *symbol;
286 struct source_line *line;
287 struct source_line *line_queue = NULL;
288 int displayed = 0;
289 int line_queue_count = 0, total = 0, more = 0;
290
291 if (!syme)
292 return;
293
294 if (!syme->source)
295 lookup_sym_source(syme);
296
297 if (!syme->source)
298 return;
299
300 symbol = (struct symbol *)(syme + 1);
301 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
302 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
303
304 pthread_mutex_lock(&syme->source_lock);
305 line = syme->source;
306 while (line) {
307 total += line->count[sym_counter];
308 line = line->next;
309 }
310
311 line = syme->source;
312 while (line) {
313 float pcnt = 0.0;
314
315 if (!line_queue_count)
316 line_queue = line;
317 line_queue_count++;
318
319 if (line->count[sym_counter])
320 pcnt = 100.0 * line->count[sym_counter] / (float)total;
321 if (pcnt >= (float)sym_pcnt_filter) {
322 if (displayed <= print_entries)
323 show_lines(line_queue, line_queue_count, total);
324 else more++;
325 displayed += line_queue_count;
326 line_queue_count = 0;
327 line_queue = NULL;
328 } else if (line_queue_count > TRACE_COUNT) {
329 line_queue = line_queue->next;
330 line_queue_count--;
331 }
332
333 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
334 line = line->next;
335 }
336 pthread_mutex_unlock(&syme->source_lock);
337 if (more)
338 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
339}
340
341struct dso *kernel_dso;
342
343/*
344 * Symbols will be added here in record_ip and will get out
345 * after decayed.
346 */
347static LIST_HEAD(active_symbols);
348static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER;
349
350/*
351 * Ordering weight: count-1 * count-2 * ... / count-n
352 */
353static double sym_weight(const struct sym_entry *sym)
354{
355 double weight = sym->snap_count;
356 int counter;
357
358 if (!display_weighted)
359 return weight;
360
361 for (counter = 1; counter < nr_counters-1; counter++)
362 weight *= sym->count[counter];
363
364 weight /= (sym->count[counter] + 1);
365
366 return weight;
367}
368
369static long samples;
370static long userspace_samples;
371static const char CONSOLE_CLEAR[] = "";
372
373static void __list_insert_active_sym(struct sym_entry *syme)
374{
375 list_add(&syme->node, &active_symbols);
376}
377
378static void list_remove_active_sym(struct sym_entry *syme)
379{
380 pthread_mutex_lock(&active_symbols_lock);
381 list_del_init(&syme->node);
382 pthread_mutex_unlock(&active_symbols_lock);
383}
384
385static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
386{
387 struct rb_node **p = &tree->rb_node;
388 struct rb_node *parent = NULL;
389 struct sym_entry *iter;
390
391 while (*p != NULL) {
392 parent = *p;
393 iter = rb_entry(parent, struct sym_entry, rb_node);
394
395 if (se->weight > iter->weight)
396 p = &(*p)->rb_left;
397 else
398 p = &(*p)->rb_right;
399 }
400
401 rb_link_node(&se->rb_node, parent, p);
402 rb_insert_color(&se->rb_node, tree);
403}
404
405static void print_sym_table(void)
406{
407 int printed = 0, j;
408 int counter, snap = !display_weighted ? sym_counter : 0;
409 float samples_per_sec = samples/delay_secs;
410 float ksamples_per_sec = (samples-userspace_samples)/delay_secs;
411 float sum_ksamples = 0.0;
412 struct sym_entry *syme, *n;
413 struct rb_root tmp = RB_ROOT;
414 struct rb_node *nd;
415
416 samples = userspace_samples = 0;
417
418 /* Sort the active symbols */
419 pthread_mutex_lock(&active_symbols_lock);
420 syme = list_entry(active_symbols.next, struct sym_entry, node);
421 pthread_mutex_unlock(&active_symbols_lock);
422
423 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
424 syme->snap_count = syme->count[snap];
425 if (syme->snap_count != 0) {
426 syme->weight = sym_weight(syme);
427 rb_insert_active_sym(&tmp, syme);
428 sum_ksamples += syme->snap_count;
429
430 for (j = 0; j < nr_counters; j++)
431 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
432 } else
433 list_remove_active_sym(syme);
434 }
435
436 puts(CONSOLE_CLEAR);
437
438 printf(
439"------------------------------------------------------------------------------\n");
440 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [",
441 samples_per_sec,
442 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
443
444 if (nr_counters == 1 || !display_weighted) {
445 printf("%Ld", (u64)attrs[0].sample_period);
446 if (freq)
447 printf("Hz ");
448 else
449 printf(" ");
450 }
451
452 if (!display_weighted)
453 printf("%s", event_name(sym_counter));
454 else for (counter = 0; counter < nr_counters; counter++) {
455 if (counter)
456 printf("/");
457
458 printf("%s", event_name(counter));
459 }
460
461 printf( "], ");
462
463 if (target_pid != -1)
464 printf(" (target_pid: %d", target_pid);
465 else
466 printf(" (all");
467
468 if (profile_cpu != -1)
469 printf(", cpu: %d)\n", profile_cpu);
470 else {
471 if (target_pid != -1)
472 printf(")\n");
473 else
474 printf(", %d CPUs)\n", nr_cpus);
475 }
476
477 printf("------------------------------------------------------------------------------\n\n");
478
479 if (sym_filter_entry) {
480 show_details(sym_filter_entry);
481 return;
482 }
483
484 if (nr_counters == 1)
485 printf(" samples pcnt");
486 else
487 printf(" weight samples pcnt");
488
489 printf(" RIP kernel function\n"
490 " ______ _______ _____ ________________ _______________\n\n"
491 );
492
493 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
494 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
495 struct symbol *sym = (struct symbol *)(syme + 1);
496 double pcnt;
497
498 if (++printed > print_entries || (int)syme->snap_count < count_filter)
499 continue;
500
501 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
502 sum_ksamples));
503
504 if (nr_counters == 1 || !display_weighted)
505 printf("%20.2f - ", syme->weight);
506 else
507 printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
508
509 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
510 printf(" - %016llx : %s", sym->start, sym->name);
511 if (sym->module)
512 printf("\t[%s]", sym->module->name);
513 printf("\n");
514 }
515}
516
517static void prompt_integer(int *target, const char *msg)
518{
519 char *buf = malloc(0), *p;
520 size_t dummy = 0;
521 int tmp;
522
523 fprintf(stdout, "\n%s: ", msg);
524 if (getline(&buf, &dummy, stdin) < 0)
525 return;
526
527 p = strchr(buf, '\n');
528 if (p)
529 *p = 0;
530
531 p = buf;
532 while(*p) {
533 if (!isdigit(*p))
534 goto out_free;
535 p++;
536 }
537 tmp = strtoul(buf, NULL, 10);
538 *target = tmp;
539out_free:
540 free(buf);
541}
542
543static void prompt_percent(int *target, const char *msg)
544{
545 int tmp = 0;
546
547 prompt_integer(&tmp, msg);
548 if (tmp >= 0 && tmp <= 100)
549 *target = tmp;
550}
551
552static void prompt_symbol(struct sym_entry **target, const char *msg)
553{
554 char *buf = malloc(0), *p;
555 struct sym_entry *syme = *target, *n, *found = NULL;
556 size_t dummy = 0;
557
558 /* zero counters of active symbol */
559 if (syme) {
560 pthread_mutex_lock(&syme->source_lock);
561 __zero_source_counters(syme);
562 *target = NULL;
563 pthread_mutex_unlock(&syme->source_lock);
564 }
565
566 fprintf(stdout, "\n%s: ", msg);
567 if (getline(&buf, &dummy, stdin) < 0)
568 goto out_free;
569
570 p = strchr(buf, '\n');
571 if (p)
572 *p = 0;
573
574 pthread_mutex_lock(&active_symbols_lock);
575 syme = list_entry(active_symbols.next, struct sym_entry, node);
576 pthread_mutex_unlock(&active_symbols_lock);
577
578 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
579 struct symbol *sym = (struct symbol *)(syme + 1);
580
581 if (!strcmp(buf, sym->name)) {
582 found = syme;
583 break;
584 }
585 }
586
587 if (!found) {
588 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter);
589 sleep(1);
590 return;
591 } else
592 parse_source(found);
593
594out_free:
595 free(buf);
596}
597
598static void print_mapped_keys(void)
599{
600 char *name = NULL;
601
602 if (sym_filter_entry) {
603 struct symbol *sym = (struct symbol *)(sym_filter_entry+1);
604 name = sym->name;
605 }
606
607 fprintf(stdout, "\nMapped keys:\n");
608 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs);
609 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries);
610
611 if (nr_counters > 1)
612 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter));
613
614 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
615
616 if (vmlinux) {
617 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
618 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
619 fprintf(stdout, "\t[S] stop annotation.\n");
620 }
621
622 if (nr_counters > 1)
623 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
624
625 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0);
626 fprintf(stdout, "\t[qQ] quit.\n");
627}
628
629static int key_mapped(int c)
630{
631 switch (c) {
632 case 'd':
633 case 'e':
634 case 'f':
635 case 'z':
636 case 'q':
637 case 'Q':
638 return 1;
639 case 'E':
640 case 'w':
641 return nr_counters > 1 ? 1 : 0;
642 case 'F':
643 case 's':
644 case 'S':
645 return vmlinux ? 1 : 0;
646 }
647
648 return 0;
649}
650
651static void handle_keypress(int c)
652{
653 if (!key_mapped(c)) {
654 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
655 struct termios tc, save;
656
657 print_mapped_keys();
658 fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
659 fflush(stdout);
660
661 tcgetattr(0, &save);
662 tc = save;
663 tc.c_lflag &= ~(ICANON | ECHO);
664 tc.c_cc[VMIN] = 0;
665 tc.c_cc[VTIME] = 0;
666 tcsetattr(0, TCSANOW, &tc);
667
668 poll(&stdin_poll, 1, -1);
669 c = getc(stdin);
670
671 tcsetattr(0, TCSAFLUSH, &save);
672 if (!key_mapped(c))
673 return;
674 }
675
676 switch (c) {
677 case 'd':
678 prompt_integer(&delay_secs, "Enter display delay");
679 break;
680 case 'e':
681 prompt_integer(&print_entries, "Enter display entries (lines)");
682 break;
683 case 'E':
684 if (nr_counters > 1) {
685 int i;
686
687 fprintf(stderr, "\nAvailable events:");
688 for (i = 0; i < nr_counters; i++)
689 fprintf(stderr, "\n\t%d %s", i, event_name(i));
690
691 prompt_integer(&sym_counter, "Enter details event counter");
692
693 if (sym_counter >= nr_counters) {
694 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0));
695 sym_counter = 0;
696 sleep(1);
697 }
698 } else sym_counter = 0;
699 break;
700 case 'f':
701 prompt_integer(&count_filter, "Enter display event count filter");
702 break;
703 case 'F':
704 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
705 break;
706 case 'q':
707 case 'Q':
708 printf("exiting.\n");
709 exit(0);
710 case 's':
711 prompt_symbol(&sym_filter_entry, "Enter details symbol");
712 break;
713 case 'S':
714 if (!sym_filter_entry)
715 break;
716 else {
717 struct sym_entry *syme = sym_filter_entry;
718
719 pthread_mutex_lock(&syme->source_lock);
720 sym_filter_entry = NULL;
721 __zero_source_counters(syme);
722 pthread_mutex_unlock(&syme->source_lock);
723 }
724 break;
725 case 'w':
726 display_weighted = ~display_weighted;
727 break;
728 case 'z':
729 zero = ~zero;
730 break;
731 }
732}
733
734static void *display_thread(void *arg __used)
735{
736 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
737 struct termios tc, save;
738 int delay_msecs, c;
739
740 tcgetattr(0, &save);
741 tc = save;
742 tc.c_lflag &= ~(ICANON | ECHO);
743 tc.c_cc[VMIN] = 0;
744 tc.c_cc[VTIME] = 0;
745
746repeat:
747 delay_msecs = delay_secs * 1000;
748 tcsetattr(0, TCSANOW, &tc);
749 /* trash return*/
750 getc(stdin);
751
752 do {
753 print_sym_table();
754 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
755
756 c = getc(stdin);
757 tcsetattr(0, TCSAFLUSH, &save);
758
759 handle_keypress(c);
760 goto repeat;
761
762 return NULL;
763}
764
765/* Tag samples to be skipped. */
766static const char *skip_symbols[] = {
767 "default_idle",
768 "cpu_idle",
769 "enter_idle",
770 "exit_idle",
771 "mwait_idle",
772 "mwait_idle_with_hints",
773 "ppc64_runlatch_off",
774 "pseries_dedicated_idle_sleep",
775 NULL
776};
777
778static int symbol_filter(struct dso *self, struct symbol *sym)
779{
780 struct sym_entry *syme;
781 const char *name = sym->name;
782 int i;
783
784 /*
785 * ppc64 uses function descriptors and appends a '.' to the
786 * start of every instruction address. Remove it.
787 */
788 if (name[0] == '.')
789 name++;
790
791 if (!strcmp(name, "_text") ||
792 !strcmp(name, "_etext") ||
793 !strcmp(name, "_sinittext") ||
794 !strncmp("init_module", name, 11) ||
795 !strncmp("cleanup_module", name, 14) ||
796 strstr(name, "_text_start") ||
797 strstr(name, "_text_end"))
798 return 1;
799
800 syme = dso__sym_priv(self, sym);
801 pthread_mutex_init(&syme->source_lock, NULL);
802 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
803 sym_filter_entry = syme;
804
805 for (i = 0; skip_symbols[i]; i++) {
806 if (!strcmp(skip_symbols[i], name)) {
807 syme->skip = 1;
808 break;
809 }
810 }
811
812 return 0;
813}
814
815static int parse_symbols(void)
816{
817 struct rb_node *node;
818 struct symbol *sym;
819 int modules = vmlinux ? 1 : 0;
820
821 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
822 if (kernel_dso == NULL)
823 return -1;
824
825 if (dso__load_kernel(kernel_dso, vmlinux, symbol_filter, verbose, modules) <= 0)
826 goto out_delete_dso;
827
828 node = rb_first(&kernel_dso->syms);
829 sym = rb_entry(node, struct symbol, rb_node);
830 min_ip = sym->start;
831
832 node = rb_last(&kernel_dso->syms);
833 sym = rb_entry(node, struct symbol, rb_node);
834 max_ip = sym->end;
835
836 if (dump_symtab)
837 dso__fprintf(kernel_dso, stderr);
838
839 return 0;
840
841out_delete_dso:
842 dso__delete(kernel_dso);
843 kernel_dso = NULL;
844 return -1;
845}
846
847/*
848 * Binary search in the histogram table and record the hit:
849 */
850static void record_ip(u64 ip, int counter)
851{
852 struct symbol *sym = dso__find_symbol(kernel_dso, ip);
853
854 if (sym != NULL) {
855 struct sym_entry *syme = dso__sym_priv(kernel_dso, sym);
856
857 if (!syme->skip) {
858 syme->count[counter]++;
859 record_precise_ip(syme, counter, ip);
860 pthread_mutex_lock(&active_symbols_lock);
861 if (list_empty(&syme->node) || !syme->node.next)
862 __list_insert_active_sym(syme);
863 pthread_mutex_unlock(&active_symbols_lock);
864 return;
865 }
866 }
867
868 samples--;
869}
870
871static void process_event(u64 ip, int counter, int user)
872{
873 samples++;
874
875 if (user) {
876 userspace_samples++;
877 return;
878 }
879
880 record_ip(ip, counter);
881}
882
883struct mmap_data {
884 int counter;
885 void *base;
886 int mask;
887 unsigned int prev;
888};
889
890static unsigned int mmap_read_head(struct mmap_data *md)
891{
892 struct perf_counter_mmap_page *pc = md->base;
893 int head;
894
895 head = pc->data_head;
896 rmb();
897
898 return head;
899}
900
901struct timeval last_read, this_read;
902
903static void mmap_read_counter(struct mmap_data *md)
904{
905 unsigned int head = mmap_read_head(md);
906 unsigned int old = md->prev;
907 unsigned char *data = md->base + page_size;
908 int diff;
909
910 gettimeofday(&this_read, NULL);
911
912 /*
913 * If we're further behind than half the buffer, there's a chance
914 * the writer will bite our tail and mess up the samples under us.
915 *
916 * If we somehow ended up ahead of the head, we got messed up.
917 *
918 * In either case, truncate and restart at head.
919 */
920 diff = head - old;
921 if (diff > md->mask / 2 || diff < 0) {
922 struct timeval iv;
923 unsigned long msecs;
924
925 timersub(&this_read, &last_read, &iv);
926 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
927
928 fprintf(stderr, "WARNING: failed to keep up with mmap data."
929 " Last read %lu msecs ago.\n", msecs);
930
931 /*
932 * head points to a known good entry, start there.
933 */
934 old = head;
935 }
936
937 last_read = this_read;
938
939 for (; old != head;) {
940 struct ip_event {
941 struct perf_event_header header;
942 u64 ip;
943 u32 pid, target_pid;
944 };
945 struct mmap_event {
946 struct perf_event_header header;
947 u32 pid, target_pid;
948 u64 start;
949 u64 len;
950 u64 pgoff;
951 char filename[PATH_MAX];
952 };
953
954 typedef union event_union {
955 struct perf_event_header header;
956 struct ip_event ip;
957 struct mmap_event mmap;
958 } event_t;
959
960 event_t *event = (event_t *)&data[old & md->mask];
961
962 event_t event_copy;
963
964 size_t size = event->header.size;
965
966 /*
967 * Event straddles the mmap boundary -- header should always
968 * be inside due to u64 alignment of output.
969 */
970 if ((old & md->mask) + size != ((old + size) & md->mask)) {
971 unsigned int offset = old;
972 unsigned int len = min(sizeof(*event), size), cpy;
973 void *dst = &event_copy;
974
975 do {
976 cpy = min(md->mask + 1 - (offset & md->mask), len);
977 memcpy(dst, &data[offset & md->mask], cpy);
978 offset += cpy;
979 dst += cpy;
980 len -= cpy;
981 } while (len);
982
983 event = &event_copy;
984 }
985
986 old += size;
987
988 if (event->header.type == PERF_EVENT_SAMPLE) {
989 int user =
990 (event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER;
991 process_event(event->ip.ip, md->counter, user);
992 }
993 }
994
995 md->prev = old;
996}
997
998static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
999static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1000
1001static void mmap_read(void)
1002{
1003 int i, counter;
1004
1005 for (i = 0; i < nr_cpus; i++) {
1006 for (counter = 0; counter < nr_counters; counter++)
1007 mmap_read_counter(&mmap_array[i][counter]);
1008 }
1009}
1010
1011int nr_poll;
1012int group_fd;
1013
1014static void start_counter(int i, int counter)
1015{
1016 struct perf_counter_attr *attr;
1017 int cpu;
1018
1019 cpu = profile_cpu;
1020 if (target_pid == -1 && profile_cpu == -1)
1021 cpu = i;
1022
1023 attr = attrs + counter;
1024
1025 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1026 attr->freq = freq;
1027 attr->inherit = (cpu < 0) && inherit;
1028
1029try_again:
1030 fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0);
1031
1032 if (fd[i][counter] < 0) {
1033 int err = errno;
1034
1035 if (err == EPERM)
1036 die("No permission - are you root?\n");
1037 /*
1038 * If it's cycles then fall back to hrtimer
1039 * based cpu-clock-tick sw counter, which
1040 * is always available even if no PMU support:
1041 */
1042 if (attr->type == PERF_TYPE_HARDWARE
1043 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1044
1045 if (verbose)
1046 warning(" ... trying to fall back to cpu-clock-ticks\n");
1047
1048 attr->type = PERF_TYPE_SOFTWARE;
1049 attr->config = PERF_COUNT_SW_CPU_CLOCK;
1050 goto try_again;
1051 }
1052 printf("\n");
1053 error("perfcounter syscall returned with %d (%s)\n",
1054 fd[i][counter], strerror(err));
1055 die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n");
1056 exit(-1);
1057 }
1058 assert(fd[i][counter] >= 0);
1059 fcntl(fd[i][counter], F_SETFL, O_NONBLOCK);
1060
1061 /*
1062 * First counter acts as the group leader:
1063 */
1064 if (group && group_fd == -1)
1065 group_fd = fd[i][counter];
1066
1067 event_array[nr_poll].fd = fd[i][counter];
1068 event_array[nr_poll].events = POLLIN;
1069 nr_poll++;
1070
1071 mmap_array[i][counter].counter = counter;
1072 mmap_array[i][counter].prev = 0;
1073 mmap_array[i][counter].mask = mmap_pages*page_size - 1;
1074 mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
1075 PROT_READ, MAP_SHARED, fd[i][counter], 0);
1076 if (mmap_array[i][counter].base == MAP_FAILED)
1077 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1078}
1079
1080static int __cmd_top(void)
1081{
1082 pthread_t thread;
1083 int i, counter;
1084 int ret;
1085
1086 for (i = 0; i < nr_cpus; i++) {
1087 group_fd = -1;
1088 for (counter = 0; counter < nr_counters; counter++)
1089 start_counter(i, counter);
1090 }
1091
1092 /* Wait for a minimal set of events before starting the snapshot */
1093 poll(event_array, nr_poll, 100);
1094
1095 mmap_read();
1096
1097 if (pthread_create(&thread, NULL, display_thread, NULL)) {
1098 printf("Could not create display thread.\n");
1099 exit(-1);
1100 }
1101
1102 if (realtime_prio) {
1103 struct sched_param param;
1104
1105 param.sched_priority = realtime_prio;
1106 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
1107 printf("Could not set realtime priority.\n");
1108 exit(-1);
1109 }
1110 }
1111
1112 while (1) {
1113 int hits = samples;
1114
1115 mmap_read();
1116
1117 if (hits == samples)
1118 ret = poll(event_array, nr_poll, 100);
1119 }
1120
1121 return 0;
1122}
1123
1124static const char * const top_usage[] = {
1125 "perf top [<options>]",
1126 NULL
1127};
1128
1129static const struct option options[] = {
1130 OPT_CALLBACK('e', "event", NULL, "event",
1131 "event selector. use 'perf list' to list available events",
1132 parse_events),
1133 OPT_INTEGER('c', "count", &default_interval,
1134 "event period to sample"),
1135 OPT_INTEGER('p', "pid", &target_pid,
1136 "profile events on existing pid"),
1137 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1138 "system-wide collection from all CPUs"),
1139 OPT_INTEGER('C', "CPU", &profile_cpu,
1140 "CPU to profile on"),
1141 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1142 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
1143 "number of mmap data pages"),
1144 OPT_INTEGER('r', "realtime", &realtime_prio,
1145 "collect data with this RT SCHED_FIFO priority"),
1146 OPT_INTEGER('d', "delay", &delay_secs,
1147 "number of seconds to delay between refreshes"),
1148 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
1149 "dump the symbol table used for profiling"),
1150 OPT_INTEGER('f', "count-filter", &count_filter,
1151 "only display functions with more events than this"),
1152 OPT_BOOLEAN('g', "group", &group,
1153 "put the counters into a counter group"),
1154 OPT_BOOLEAN('i', "inherit", &inherit,
1155 "child tasks inherit counters"),
1156 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1157 "symbol to annotate - requires -k option"),
1158 OPT_BOOLEAN('z', "zero", &zero,
1159 "zero history across updates"),
1160 OPT_INTEGER('F', "freq", &freq,
1161 "profile at this frequency"),
1162 OPT_INTEGER('E', "entries", &print_entries,
1163 "display this many functions"),
1164 OPT_BOOLEAN('v', "verbose", &verbose,
1165 "be more verbose (show counter open errors, etc)"),
1166 OPT_END()
1167};
1168
1169int cmd_top(int argc, const char **argv, const char *prefix __used)
1170{
1171 int counter;
1172
1173 symbol__init();
1174
1175 page_size = sysconf(_SC_PAGE_SIZE);
1176
1177 argc = parse_options(argc, argv, options, top_usage, 0);
1178 if (argc)
1179 usage_with_options(top_usage, options);
1180
1181 if (freq) {
1182 default_interval = freq;
1183 freq = 1;
1184 }
1185
1186 /* CPU and PID are mutually exclusive */
1187 if (target_pid != -1 && profile_cpu != -1) {
1188 printf("WARNING: PID switch overriding CPU\n");
1189 sleep(1);
1190 profile_cpu = -1;
1191 }
1192
1193 if (!nr_counters)
1194 nr_counters = 1;
1195
1196 if (delay_secs < 1)
1197 delay_secs = 1;
1198
1199 parse_symbols();
1200 parse_source(sym_filter_entry);
1201
1202 /*
1203 * Fill in the ones not specifically initialized via -c:
1204 */
1205 for (counter = 0; counter < nr_counters; counter++) {
1206 if (attrs[counter].sample_period)
1207 continue;
1208
1209 attrs[counter].sample_period = default_interval;
1210 }
1211
1212 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
1213 assert(nr_cpus <= MAX_NR_CPUS);
1214 assert(nr_cpus >= 0);
1215
1216 if (target_pid != -1 || profile_cpu != -1)
1217 nr_cpus = 1;
1218
1219 return __cmd_top();
1220}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
new file mode 100644
index 000000000000..51d168230ee7
--- /dev/null
+++ b/tools/perf/builtin.h
@@ -0,0 +1,26 @@
1#ifndef BUILTIN_H
2#define BUILTIN_H
3
4#include "util/util.h"
5#include "util/strbuf.h"
6
7extern const char perf_version_string[];
8extern const char perf_usage_string[];
9extern const char perf_more_info_string[];
10
11extern void list_common_cmds_help(void);
12extern const char *help_unknown_cmd(const char *cmd);
13extern void prune_packed_objects(int);
14extern int read_line_with_nul(char *buf, int size, FILE *file);
15extern int check_pager_config(const char *cmd);
16
17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_help(int argc, const char **argv, const char *prefix);
19extern int cmd_record(int argc, const char **argv, const char *prefix);
20extern int cmd_report(int argc, const char **argv, const char *prefix);
21extern int cmd_stat(int argc, const char **argv, const char *prefix);
22extern int cmd_top(int argc, const char **argv, const char *prefix);
23extern int cmd_version(int argc, const char **argv, const char *prefix);
24extern int cmd_list(int argc, const char **argv, const char *prefix);
25
26#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
new file mode 100644
index 000000000000..eebce30afbc0
--- /dev/null
+++ b/tools/perf/command-list.txt
@@ -0,0 +1,10 @@
1#
2# List of known perf commands.
3# command name category [deprecated] [common]
4#
5perf-annotate mainporcelain common
6perf-list mainporcelain common
7perf-record mainporcelain common
8perf-report mainporcelain common
9perf-stat mainporcelain common
10perf-top mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
new file mode 100644
index 000000000000..f71e0d245cba
--- /dev/null
+++ b/tools/perf/design.txt
@@ -0,0 +1,457 @@
1
2Performance Counters for Linux
3------------------------------
4
5Performance counters are special hardware registers available on most modern
6CPUs. These registers count the number of certain types of hw events: such
7as instructions executed, cachemisses suffered, or branches mis-predicted -
8without slowing down the kernel or applications. These registers can also
9trigger interrupts when a threshold number of events have passed - and can
10thus be used to profile the code that runs on that CPU.
11
12The Linux Performance Counter subsystem provides an abstraction of these
13hardware capabilities. It provides per task and per CPU counters, counter
14groups, and it provides event capabilities on top of those. It
15provides "virtual" 64-bit counters, regardless of the width of the
16underlying hardware counters.
17
18Performance counters are accessed via special file descriptors.
19There's one file descriptor per virtual counter used.
20
21The special file descriptor is opened via the perf_counter_open()
22system call:
23
24 int sys_perf_counter_open(struct perf_counter_hw_event *hw_event_uptr,
25 pid_t pid, int cpu, int group_fd,
26 unsigned long flags);
27
28The syscall returns the new fd. The fd can be used via the normal
29VFS system calls: read() can be used to read the counter, fcntl()
30can be used to set the blocking mode, etc.
31
32Multiple counters can be kept open at a time, and the counters
33can be poll()ed.
34
35When creating a new counter fd, 'perf_counter_hw_event' is:
36
37struct perf_counter_hw_event {
38 /*
39 * The MSB of the config word signifies if the rest contains cpu
40 * specific (raw) counter configuration data, if unset, the next
41 * 7 bits are an event type and the rest of the bits are the event
42 * identifier.
43 */
44 __u64 config;
45
46 __u64 irq_period;
47 __u32 record_type;
48 __u32 read_format;
49
50 __u64 disabled : 1, /* off by default */
51 inherit : 1, /* children inherit it */
52 pinned : 1, /* must always be on PMU */
53 exclusive : 1, /* only group on PMU */
54 exclude_user : 1, /* don't count user */
55 exclude_kernel : 1, /* ditto kernel */
56 exclude_hv : 1, /* ditto hypervisor */
57 exclude_idle : 1, /* don't count when idle */
58 mmap : 1, /* include mmap data */
59 munmap : 1, /* include munmap data */
60 comm : 1, /* include comm data */
61
62 __reserved_1 : 52;
63
64 __u32 extra_config_len;
65 __u32 wakeup_events; /* wakeup every n events */
66
67 __u64 __reserved_2;
68 __u64 __reserved_3;
69};
70
71The 'config' field specifies what the counter should count. It
72is divided into 3 bit-fields:
73
74raw_type: 1 bit (most significant bit) 0x8000_0000_0000_0000
75type: 7 bits (next most significant) 0x7f00_0000_0000_0000
76event_id: 56 bits (least significant) 0x00ff_ffff_ffff_ffff
77
78If 'raw_type' is 1, then the counter will count a hardware event
79specified by the remaining 63 bits of event_config. The encoding is
80machine-specific.
81
82If 'raw_type' is 0, then the 'type' field says what kind of counter
83this is, with the following encoding:
84
85enum perf_event_types {
86 PERF_TYPE_HARDWARE = 0,
87 PERF_TYPE_SOFTWARE = 1,
88 PERF_TYPE_TRACEPOINT = 2,
89};
90
91A counter of PERF_TYPE_HARDWARE will count the hardware event
92specified by 'event_id':
93
94/*
95 * Generalized performance counter event types, used by the hw_event.event_id
96 * parameter of the sys_perf_counter_open() syscall:
97 */
98enum hw_event_ids {
99 /*
100 * Common hardware events, generalized by the kernel:
101 */
102 PERF_COUNT_HW_CPU_CYCLES = 0,
103 PERF_COUNT_HW_INSTRUCTIONS = 1,
104 PERF_COUNT_HW_CACHE_REFERENCES = 2,
105 PERF_COUNT_HW_CACHE_MISSES = 3,
106 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
107 PERF_COUNT_HW_BRANCH_MISSES = 5,
108 PERF_COUNT_HW_BUS_CYCLES = 6,
109};
110
111These are standardized types of events that work relatively uniformly
112on all CPUs that implement Performance Counters support under Linux,
113although there may be variations (e.g., different CPUs might count
114cache references and misses at different levels of the cache hierarchy).
115If a CPU is not able to count the selected event, then the system call
116will return -EINVAL.
117
118More hw_event_types are supported as well, but they are CPU-specific
119and accessed as raw events. For example, to count "External bus
120cycles while bus lock signal asserted" events on Intel Core CPUs, pass
121in a 0x4064 event_id value and set hw_event.raw_type to 1.
122
123A counter of type PERF_TYPE_SOFTWARE will count one of the available
124software events, selected by 'event_id':
125
126/*
127 * Special "software" counters provided by the kernel, even if the hardware
128 * does not support performance counters. These counters measure various
129 * physical and sw events of the kernel (and allow the profiling of them as
130 * well):
131 */
132enum sw_event_ids {
133 PERF_COUNT_SW_CPU_CLOCK = 0,
134 PERF_COUNT_SW_TASK_CLOCK = 1,
135 PERF_COUNT_SW_PAGE_FAULTS = 2,
136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
137 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
139 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
140};
141
142Counters of the type PERF_TYPE_TRACEPOINT are available when the ftrace event
143tracer is available, and event_id values can be obtained from
144/debug/tracing/events/*/*/id
145
146
147Counters come in two flavours: counting counters and sampling
148counters. A "counting" counter is one that is used for counting the
149number of events that occur, and is characterised by having
150irq_period = 0.
151
152
153A read() on a counter returns the current value of the counter and possible
154additional values as specified by 'read_format', each value is a u64 (8 bytes)
155in size.
156
157/*
158 * Bits that can be set in hw_event.read_format to request that
159 * reads on the counter should return the indicated quantities,
160 * in increasing order of bit value, after the counter value.
161 */
162enum perf_counter_read_format {
163 PERF_FORMAT_TOTAL_TIME_ENABLED = 1,
164 PERF_FORMAT_TOTAL_TIME_RUNNING = 2,
165};
166
167Using these additional values one can establish the overcommit ratio for a
168particular counter allowing one to take the round-robin scheduling effect
169into account.
170
171
172A "sampling" counter is one that is set up to generate an interrupt
173every N events, where N is given by 'irq_period'. A sampling counter
174has irq_period > 0. The record_type controls what data is recorded on each
175interrupt:
176
177/*
178 * Bits that can be set in hw_event.record_type to request information
179 * in the overflow packets.
180 */
181enum perf_counter_record_format {
182 PERF_RECORD_IP = 1U << 0,
183 PERF_RECORD_TID = 1U << 1,
184 PERF_RECORD_TIME = 1U << 2,
185 PERF_RECORD_ADDR = 1U << 3,
186 PERF_RECORD_GROUP = 1U << 4,
187 PERF_RECORD_CALLCHAIN = 1U << 5,
188};
189
190Such (and other) events will be recorded in a ring-buffer, which is
191available to user-space using mmap() (see below).
192
193The 'disabled' bit specifies whether the counter starts out disabled
194or enabled. If it is initially disabled, it can be enabled by ioctl
195or prctl (see below).
196
197The 'inherit' bit, if set, specifies that this counter should count
198events on descendant tasks as well as the task specified. This only
199applies to new descendents, not to any existing descendents at the
200time the counter is created (nor to any new descendents of existing
201descendents).
202
203The 'pinned' bit, if set, specifies that the counter should always be
204on the CPU if at all possible. It only applies to hardware counters
205and only to group leaders. If a pinned counter cannot be put onto the
206CPU (e.g. because there are not enough hardware counters or because of
207a conflict with some other event), then the counter goes into an
208'error' state, where reads return end-of-file (i.e. read() returns 0)
209until the counter is subsequently enabled or disabled.
210
211The 'exclusive' bit, if set, specifies that when this counter's group
212is on the CPU, it should be the only group using the CPU's counters.
213In future, this will allow sophisticated monitoring programs to supply
214extra configuration information via 'extra_config_len' to exploit
215advanced features of the CPU's Performance Monitor Unit (PMU) that are
216not otherwise accessible and that might disrupt other hardware
217counters.
218
219The 'exclude_user', 'exclude_kernel' and 'exclude_hv' bits provide a
220way to request that counting of events be restricted to times when the
221CPU is in user, kernel and/or hypervisor mode.
222
223The 'mmap' and 'munmap' bits allow recording of PROT_EXEC mmap/munmap
224operations, these can be used to relate userspace IP addresses to actual
225code, even after the mapping (or even the whole process) is gone,
226these events are recorded in the ring-buffer (see below).
227
228The 'comm' bit allows tracking of process comm data on process creation.
229This too is recorded in the ring-buffer (see below).
230
231The 'pid' parameter to the perf_counter_open() system call allows the
232counter to be specific to a task:
233
234 pid == 0: if the pid parameter is zero, the counter is attached to the
235 current task.
236
237 pid > 0: the counter is attached to a specific task (if the current task
238 has sufficient privilege to do so)
239
240 pid < 0: all tasks are counted (per cpu counters)
241
242The 'cpu' parameter allows a counter to be made specific to a CPU:
243
244 cpu >= 0: the counter is restricted to a specific CPU
245 cpu == -1: the counter counts on all CPUs
246
247(Note: the combination of 'pid == -1' and 'cpu == -1' is not valid.)
248
249A 'pid > 0' and 'cpu == -1' counter is a per task counter that counts
250events of that task and 'follows' that task to whatever CPU the task
251gets schedule to. Per task counters can be created by any user, for
252their own tasks.
253
254A 'pid == -1' and 'cpu == x' counter is a per CPU counter that counts
255all events on CPU-x. Per CPU counters need CAP_SYS_ADMIN privilege.
256
257The 'flags' parameter is currently unused and must be zero.
258
259The 'group_fd' parameter allows counter "groups" to be set up. A
260counter group has one counter which is the group "leader". The leader
261is created first, with group_fd = -1 in the perf_counter_open call
262that creates it. The rest of the group members are created
263subsequently, with group_fd giving the fd of the group leader.
264(A single counter on its own is created with group_fd = -1 and is
265considered to be a group with only 1 member.)
266
267A counter group is scheduled onto the CPU as a unit, that is, it will
268only be put onto the CPU if all of the counters in the group can be
269put onto the CPU. This means that the values of the member counters
270can be meaningfully compared, added, divided (to get ratios), etc.,
271with each other, since they have counted events for the same set of
272executed instructions.
273
274
275Like stated, asynchronous events, like counter overflow or PROT_EXEC mmap
276tracking are logged into a ring-buffer. This ring-buffer is created and
277accessed through mmap().
278
279The mmap size should be 1+2^n pages, where the first page is a meta-data page
280(struct perf_counter_mmap_page) that contains various bits of information such
281as where the ring-buffer head is.
282
283/*
284 * Structure of the page that can be mapped via mmap
285 */
286struct perf_counter_mmap_page {
287 __u32 version; /* version number of this structure */
288 __u32 compat_version; /* lowest version this is compat with */
289
290 /*
291 * Bits needed to read the hw counters in user-space.
292 *
293 * u32 seq;
294 * s64 count;
295 *
296 * do {
297 * seq = pc->lock;
298 *
299 * barrier()
300 * if (pc->index) {
301 * count = pmc_read(pc->index - 1);
302 * count += pc->offset;
303 * } else
304 * goto regular_read;
305 *
306 * barrier();
307 * } while (pc->lock != seq);
308 *
309 * NOTE: for obvious reason this only works on self-monitoring
310 * processes.
311 */
312 __u32 lock; /* seqlock for synchronization */
313 __u32 index; /* hardware counter identifier */
314 __s64 offset; /* add to hardware counter value */
315
316 /*
317 * Control data for the mmap() data buffer.
318 *
319 * User-space reading this value should issue an rmb(), on SMP capable
320 * platforms, after reading this value -- see perf_counter_wakeup().
321 */
322 __u32 data_head; /* head in the data section */
323};
324
325NOTE: the hw-counter userspace bits are arch specific and are currently only
326 implemented on powerpc.
327
328The following 2^n pages are the ring-buffer which contains events of the form:
329
330#define PERF_EVENT_MISC_KERNEL (1 << 0)
331#define PERF_EVENT_MISC_USER (1 << 1)
332#define PERF_EVENT_MISC_OVERFLOW (1 << 2)
333
334struct perf_event_header {
335 __u32 type;
336 __u16 misc;
337 __u16 size;
338};
339
340enum perf_event_type {
341
342 /*
343 * The MMAP events record the PROT_EXEC mappings so that we can
344 * correlate userspace IPs to code. They have the following structure:
345 *
346 * struct {
347 * struct perf_event_header header;
348 *
349 * u32 pid, tid;
350 * u64 addr;
351 * u64 len;
352 * u64 pgoff;
353 * char filename[];
354 * };
355 */
356 PERF_EVENT_MMAP = 1,
357 PERF_EVENT_MUNMAP = 2,
358
359 /*
360 * struct {
361 * struct perf_event_header header;
362 *
363 * u32 pid, tid;
364 * char comm[];
365 * };
366 */
367 PERF_EVENT_COMM = 3,
368
369 /*
370 * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field
371 * will be PERF_RECORD_*
372 *
373 * struct {
374 * struct perf_event_header header;
375 *
376 * { u64 ip; } && PERF_RECORD_IP
377 * { u32 pid, tid; } && PERF_RECORD_TID
378 * { u64 time; } && PERF_RECORD_TIME
379 * { u64 addr; } && PERF_RECORD_ADDR
380 *
381 * { u64 nr;
382 * { u64 event, val; } cnt[nr]; } && PERF_RECORD_GROUP
383 *
384 * { u16 nr,
385 * hv,
386 * kernel,
387 * user;
388 * u64 ips[nr]; } && PERF_RECORD_CALLCHAIN
389 * };
390 */
391};
392
393NOTE: PERF_RECORD_CALLCHAIN is arch specific and currently only implemented
394 on x86.
395
396Notification of new events is possible through poll()/select()/epoll() and
397fcntl() managing signals.
398
399Normally a notification is generated for every page filled, however one can
400additionally set perf_counter_hw_event.wakeup_events to generate one every
401so many counter overflow events.
402
403Future work will include a splice() interface to the ring-buffer.
404
405
406Counters can be enabled and disabled in two ways: via ioctl and via
407prctl. When a counter is disabled, it doesn't count or generate
408events but does continue to exist and maintain its count value.
409
410An individual counter or counter group can be enabled with
411
412 ioctl(fd, PERF_COUNTER_IOC_ENABLE);
413
414or disabled with
415
416 ioctl(fd, PERF_COUNTER_IOC_DISABLE);
417
418Enabling or disabling the leader of a group enables or disables the
419whole group; that is, while the group leader is disabled, none of the
420counters in the group will count. Enabling or disabling a member of a
421group other than the leader only affects that counter - disabling an
422non-leader stops that counter from counting but doesn't affect any
423other counter.
424
425Additionally, non-inherited overflow counters can use
426
427 ioctl(fd, PERF_COUNTER_IOC_REFRESH, nr);
428
429to enable a counter for 'nr' events, after which it gets disabled again.
430
431A process can enable or disable all the counter groups that are
432attached to it, using prctl:
433
434 prctl(PR_TASK_PERF_COUNTERS_ENABLE);
435
436 prctl(PR_TASK_PERF_COUNTERS_DISABLE);
437
438This applies to all counters on the current process, whether created
439by this process or by another, and doesn't affect any counters that
440this process has created on other processes. It only enables or
441disables the group leaders, not any other members in the groups.
442
443
444Arch requirements
445-----------------
446
447If your architecture does not have hardware performance metrics, you can
448still use the generic software counters based on hrtimers for sampling.
449
450So to start with, in order to add HAVE_PERF_COUNTERS to your Kconfig, you
451will need at least this:
452 - asm/perf_counter.h - a basic stub will suffice at first
453 - support for atomic64 types (and associated helper functions)
454 - set_perf_counter_pending() implemented
455
456If your architecture does have hardware capabilities, you can override the
457weak stub hw_perf_counter_init() to register hardware counters.
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
new file mode 100644
index 000000000000..31982ad064b4
--- /dev/null
+++ b/tools/perf/perf.c
@@ -0,0 +1,500 @@
1/*
2 * perf.c
3 *
4 * Performance analysis utility.
5 *
6 * This is the main hub from which the sub-commands (perf stat,
7 * perf top, perf record, perf report, etc.) are started.
8 */
9#include "builtin.h"
10
11#include "util/exec_cmd.h"
12#include "util/cache.h"
13#include "util/quote.h"
14#include "util/run-command.h"
15#include "util/parse-events.h"
16#include "util/string.h"
17
18const char perf_usage_string[] =
19 "perf [--version] [--help] COMMAND [ARGS]";
20
21const char perf_more_info_string[] =
22 "See 'perf help COMMAND' for more information on a specific command.";
23
24static int use_pager = -1;
25struct pager_config {
26 const char *cmd;
27 int val;
28};
29
30static char debugfs_mntpt[MAXPATHLEN];
31
32static int pager_command_config(const char *var, const char *value, void *data)
33{
34 struct pager_config *c = data;
35 if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd))
36 c->val = perf_config_bool(var, value);
37 return 0;
38}
39
40/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
41int check_pager_config(const char *cmd)
42{
43 struct pager_config c;
44 c.cmd = cmd;
45 c.val = -1;
46 perf_config(pager_command_config, &c);
47 return c.val;
48}
49
50static void commit_pager_choice(void) {
51 switch (use_pager) {
52 case 0:
53 setenv("PERF_PAGER", "cat", 1);
54 break;
55 case 1:
56 /* setup_pager(); */
57 break;
58 default:
59 break;
60 }
61}
62
63static void set_debugfs_path(void)
64{
65 char *path;
66
67 path = getenv(PERF_DEBUGFS_ENVIRONMENT);
68 snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt,
69 "tracing/events");
70}
71
72static int handle_options(const char*** argv, int* argc, int* envchanged)
73{
74 int handled = 0;
75
76 while (*argc > 0) {
77 const char *cmd = (*argv)[0];
78 if (cmd[0] != '-')
79 break;
80
81 /*
82 * For legacy reasons, the "version" and "help"
83 * commands can be written with "--" prepended
84 * to make them look like flags.
85 */
86 if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
87 break;
88
89 /*
90 * Check remaining flags.
91 */
92 if (!prefixcmp(cmd, "--exec-path")) {
93 cmd += 11;
94 if (*cmd == '=')
95 perf_set_argv_exec_path(cmd + 1);
96 else {
97 puts(perf_exec_path());
98 exit(0);
99 }
100 } else if (!strcmp(cmd, "--html-path")) {
101 puts(system_path(PERF_HTML_PATH));
102 exit(0);
103 } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
104 use_pager = 1;
105 } else if (!strcmp(cmd, "--no-pager")) {
106 use_pager = 0;
107 if (envchanged)
108 *envchanged = 1;
109 } else if (!strcmp(cmd, "--perf-dir")) {
110 if (*argc < 2) {
111 fprintf(stderr, "No directory given for --perf-dir.\n" );
112 usage(perf_usage_string);
113 }
114 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1);
115 if (envchanged)
116 *envchanged = 1;
117 (*argv)++;
118 (*argc)--;
119 handled++;
120 } else if (!prefixcmp(cmd, "--perf-dir=")) {
121 setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1);
122 if (envchanged)
123 *envchanged = 1;
124 } else if (!strcmp(cmd, "--work-tree")) {
125 if (*argc < 2) {
126 fprintf(stderr, "No directory given for --work-tree.\n" );
127 usage(perf_usage_string);
128 }
129 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
130 if (envchanged)
131 *envchanged = 1;
132 (*argv)++;
133 (*argc)--;
134 } else if (!prefixcmp(cmd, "--work-tree=")) {
135 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
136 if (envchanged)
137 *envchanged = 1;
138 } else if (!strcmp(cmd, "--debugfs-dir")) {
139 if (*argc < 2) {
140 fprintf(stderr, "No directory given for --debugfs-dir.\n");
141 usage(perf_usage_string);
142 }
143 strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN);
144 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
145 if (envchanged)
146 *envchanged = 1;
147 (*argv)++;
148 (*argc)--;
149 } else if (!prefixcmp(cmd, "--debugfs-dir=")) {
150 strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN);
151 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
152 if (envchanged)
153 *envchanged = 1;
154 } else {
155 fprintf(stderr, "Unknown option: %s\n", cmd);
156 usage(perf_usage_string);
157 }
158
159 (*argv)++;
160 (*argc)--;
161 handled++;
162 }
163 return handled;
164}
165
166static int handle_alias(int *argcp, const char ***argv)
167{
168 int envchanged = 0, ret = 0, saved_errno = errno;
169 int count, option_count;
170 const char** new_argv;
171 const char *alias_command;
172 char *alias_string;
173
174 alias_command = (*argv)[0];
175 alias_string = alias_lookup(alias_command);
176 if (alias_string) {
177 if (alias_string[0] == '!') {
178 if (*argcp > 1) {
179 struct strbuf buf;
180
181 strbuf_init(&buf, PATH_MAX);
182 strbuf_addstr(&buf, alias_string);
183 sq_quote_argv(&buf, (*argv) + 1, PATH_MAX);
184 free(alias_string);
185 alias_string = buf.buf;
186 }
187 ret = system(alias_string + 1);
188 if (ret >= 0 && WIFEXITED(ret) &&
189 WEXITSTATUS(ret) != 127)
190 exit(WEXITSTATUS(ret));
191 die("Failed to run '%s' when expanding alias '%s'",
192 alias_string + 1, alias_command);
193 }
194 count = split_cmdline(alias_string, &new_argv);
195 if (count < 0)
196 die("Bad alias.%s string", alias_command);
197 option_count = handle_options(&new_argv, &count, &envchanged);
198 if (envchanged)
199 die("alias '%s' changes environment variables\n"
200 "You can use '!perf' in the alias to do this.",
201 alias_command);
202 memmove(new_argv - option_count, new_argv,
203 count * sizeof(char *));
204 new_argv -= option_count;
205
206 if (count < 1)
207 die("empty alias for %s", alias_command);
208
209 if (!strcmp(alias_command, new_argv[0]))
210 die("recursive alias: %s", alias_command);
211
212 new_argv = realloc(new_argv, sizeof(char*) *
213 (count + *argcp + 1));
214 /* insert after command name */
215 memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp);
216 new_argv[count+*argcp] = NULL;
217
218 *argv = new_argv;
219 *argcp += count - 1;
220
221 ret = 1;
222 }
223
224 errno = saved_errno;
225
226 return ret;
227}
228
229const char perf_version_string[] = PERF_VERSION;
230
231#define RUN_SETUP (1<<0)
232#define USE_PAGER (1<<1)
233/*
234 * require working tree to be present -- anything uses this needs
235 * RUN_SETUP for reading from the configuration file.
236 */
237#define NEED_WORK_TREE (1<<2)
238
239struct cmd_struct {
240 const char *cmd;
241 int (*fn)(int, const char **, const char *);
242 int option;
243};
244
245static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
246{
247 int status;
248 struct stat st;
249 const char *prefix;
250
251 prefix = NULL;
252 if (p->option & RUN_SETUP)
253 prefix = NULL; /* setup_perf_directory(); */
254
255 if (use_pager == -1 && p->option & RUN_SETUP)
256 use_pager = check_pager_config(p->cmd);
257 if (use_pager == -1 && p->option & USE_PAGER)
258 use_pager = 1;
259 commit_pager_choice();
260 set_debugfs_path();
261
262 status = p->fn(argc, argv, prefix);
263 if (status)
264 return status & 0xff;
265
266 /* Somebody closed stdout? */
267 if (fstat(fileno(stdout), &st))
268 return 0;
269 /* Ignore write errors for pipes and sockets.. */
270 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
271 return 0;
272
273 /* Check for ENOSPC and EIO errors.. */
274 if (fflush(stdout))
275 die("write failure on standard output: %s", strerror(errno));
276 if (ferror(stdout))
277 die("unknown write failure on standard output");
278 if (fclose(stdout))
279 die("close failed on standard output: %s", strerror(errno));
280 return 0;
281}
282
283static void handle_internal_command(int argc, const char **argv)
284{
285 const char *cmd = argv[0];
286 static struct cmd_struct commands[] = {
287 { "help", cmd_help, 0 },
288 { "list", cmd_list, 0 },
289 { "record", cmd_record, 0 },
290 { "report", cmd_report, 0 },
291 { "stat", cmd_stat, 0 },
292 { "top", cmd_top, 0 },
293 { "annotate", cmd_annotate, 0 },
294 { "version", cmd_version, 0 },
295 };
296 unsigned int i;
297 static const char ext[] = STRIP_EXTENSION;
298
299 if (sizeof(ext) > 1) {
300 i = strlen(argv[0]) - strlen(ext);
301 if (i > 0 && !strcmp(argv[0] + i, ext)) {
302 char *argv0 = strdup(argv[0]);
303 argv[0] = cmd = argv0;
304 argv0[i] = '\0';
305 }
306 }
307
308 /* Turn "perf cmd --help" into "perf help cmd" */
309 if (argc > 1 && !strcmp(argv[1], "--help")) {
310 argv[1] = argv[0];
311 argv[0] = cmd = "help";
312 }
313
314 for (i = 0; i < ARRAY_SIZE(commands); i++) {
315 struct cmd_struct *p = commands+i;
316 if (strcmp(p->cmd, cmd))
317 continue;
318 exit(run_builtin(p, argc, argv));
319 }
320}
321
322static void execv_dashed_external(const char **argv)
323{
324 struct strbuf cmd = STRBUF_INIT;
325 const char *tmp;
326 int status;
327
328 strbuf_addf(&cmd, "perf-%s", argv[0]);
329
330 /*
331 * argv[0] must be the perf command, but the argv array
332 * belongs to the caller, and may be reused in
333 * subsequent loop iterations. Save argv[0] and
334 * restore it on error.
335 */
336 tmp = argv[0];
337 argv[0] = cmd.buf;
338
339 /*
340 * if we fail because the command is not found, it is
341 * OK to return. Otherwise, we just pass along the status code.
342 */
343 status = run_command_v_opt(argv, 0);
344 if (status != -ERR_RUN_COMMAND_EXEC) {
345 if (IS_RUN_COMMAND_ERR(status))
346 die("unable to run '%s'", argv[0]);
347 exit(-status);
348 }
349 errno = ENOENT; /* as if we called execvp */
350
351 argv[0] = tmp;
352
353 strbuf_release(&cmd);
354}
355
356static int run_argv(int *argcp, const char ***argv)
357{
358 int done_alias = 0;
359
360 while (1) {
361 /* See if it's an internal command */
362 handle_internal_command(*argcp, *argv);
363
364 /* .. then try the external ones */
365 execv_dashed_external(*argv);
366
367 /* It could be an alias -- this works around the insanity
368 * of overriding "perf log" with "perf show" by having
369 * alias.log = show
370 */
371 if (done_alias || !handle_alias(argcp, argv))
372 break;
373 done_alias = 1;
374 }
375
376 return done_alias;
377}
378
379/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
380static void get_debugfs_mntpt(void)
381{
382 FILE *file;
383 char fs_type[100];
384 char debugfs[MAXPATHLEN];
385
386 /*
387 * try the standard location
388 */
389 if (valid_debugfs_mount("/sys/kernel/debug/") == 0) {
390 strcpy(debugfs_mntpt, "/sys/kernel/debug/");
391 return;
392 }
393
394 /*
395 * try the sane location
396 */
397 if (valid_debugfs_mount("/debug/") == 0) {
398 strcpy(debugfs_mntpt, "/debug/");
399 return;
400 }
401
402 /*
403 * give up and parse /proc/mounts
404 */
405 file = fopen("/proc/mounts", "r");
406 if (file == NULL)
407 return;
408
409 while (fscanf(file, "%*s %"
410 STR(MAXPATHLEN)
411 "s %99s %*s %*d %*d\n",
412 debugfs, fs_type) == 2) {
413 if (strcmp(fs_type, "debugfs") == 0)
414 break;
415 }
416 fclose(file);
417 if (strcmp(fs_type, "debugfs") == 0) {
418 strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
419 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
420 }
421}
422
423int main(int argc, const char **argv)
424{
425 const char *cmd;
426
427 cmd = perf_extract_argv0_path(argv[0]);
428 if (!cmd)
429 cmd = "perf-help";
430 /* get debugfs mount point from /proc/mounts */
431 get_debugfs_mntpt();
432 /*
433 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
434 *
435 * - cannot take flags in between the "perf" and the "xxxx".
436 * - cannot execute it externally (since it would just do
437 * the same thing over again)
438 *
439 * So we just directly call the internal command handler, and
440 * die if that one cannot handle it.
441 */
442 if (!prefixcmp(cmd, "perf-")) {
443 cmd += 5;
444 argv[0] = cmd;
445 handle_internal_command(argc, argv);
446 die("cannot handle %s internally", cmd);
447 }
448
449 /* Look for flags.. */
450 argv++;
451 argc--;
452 handle_options(&argv, &argc, NULL);
453 commit_pager_choice();
454 set_debugfs_path();
455 if (argc > 0) {
456 if (!prefixcmp(argv[0], "--"))
457 argv[0] += 2;
458 } else {
459 /* The user didn't specify a command; give them help */
460 printf("\n usage: %s\n\n", perf_usage_string);
461 list_common_cmds_help();
462 printf("\n %s\n\n", perf_more_info_string);
463 exit(1);
464 }
465 cmd = argv[0];
466
467 /*
468 * We use PATH to find perf commands, but we prepend some higher
469 * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH
470 * environment, and the $(perfexecdir) from the Makefile at build
471 * time.
472 */
473 setup_path();
474
475 while (1) {
476 static int done_help = 0;
477 static int was_alias = 0;
478
479 was_alias = run_argv(&argc, &argv);
480 if (errno != ENOENT)
481 break;
482
483 if (was_alias) {
484 fprintf(stderr, "Expansion of alias '%s' failed; "
485 "'%s' is not a perf-command\n",
486 cmd, argv[0]);
487 exit(1);
488 }
489 if (!done_help) {
490 cmd = argv[0] = help_unknown_cmd(cmd);
491 done_help = 1;
492 } else
493 break;
494 }
495
496 fprintf(stderr, "Failed to run command '%s': %s\n",
497 cmd, strerror(errno));
498
499 return 1;
500}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
new file mode 100644
index 000000000000..e5148e2b6134
--- /dev/null
+++ b/tools/perf/perf.h
@@ -0,0 +1,104 @@
1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H
3
4#if defined(__i386__)
5#include "../../arch/x86/include/asm/unistd.h"
6#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
7#define cpu_relax() asm volatile("rep; nop" ::: "memory");
8#endif
9
10#if defined(__x86_64__)
11#include "../../arch/x86/include/asm/unistd.h"
12#define rmb() asm volatile("lfence" ::: "memory")
13#define cpu_relax() asm volatile("rep; nop" ::: "memory");
14#endif
15
16#ifdef __powerpc__
17#include "../../arch/powerpc/include/asm/unistd.h"
18#define rmb() asm volatile ("sync" ::: "memory")
19#define cpu_relax() asm volatile ("" ::: "memory");
20#endif
21
22#ifdef __s390__
23#include "../../arch/s390/include/asm/unistd.h"
24#define rmb() asm volatile("bcr 15,0" ::: "memory")
25#define cpu_relax() asm volatile("" ::: "memory");
26#endif
27
28#ifdef __sh__
29#include "../../arch/sh/include/asm/unistd.h"
30#if defined(__SH4A__) || defined(__SH5__)
31# define rmb() asm volatile("synco" ::: "memory")
32#else
33# define rmb() asm volatile("" ::: "memory")
34#endif
35#define cpu_relax() asm volatile("" ::: "memory")
36#endif
37
38#ifdef __hppa__
39#include "../../arch/parisc/include/asm/unistd.h"
40#define rmb() asm volatile("" ::: "memory")
41#define cpu_relax() asm volatile("" ::: "memory");
42#endif
43
44#include <time.h>
45#include <unistd.h>
46#include <sys/types.h>
47#include <sys/syscall.h>
48
49#include "../../include/linux/perf_counter.h"
50#include "util/types.h"
51
52/*
53 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
54 * counters in the current task.
55 */
56#define PR_TASK_PERF_COUNTERS_DISABLE 31
57#define PR_TASK_PERF_COUNTERS_ENABLE 32
58
59#ifndef NSEC_PER_SEC
60# define NSEC_PER_SEC 1000000000ULL
61#endif
62
63static inline unsigned long long rdclock(void)
64{
65 struct timespec ts;
66
67 clock_gettime(CLOCK_MONOTONIC, &ts);
68 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
69}
70
71/*
72 * Pick up some kernel type conventions:
73 */
74#define __user
75#define asmlinkage
76
77#define __used __attribute__((__unused__))
78
79#define unlikely(x) __builtin_expect(!!(x), 0)
80#define min(x, y) ({ \
81 typeof(x) _min1 = (x); \
82 typeof(y) _min2 = (y); \
83 (void) (&_min1 == &_min2); \
84 _min1 < _min2 ? _min1 : _min2; })
85
86static inline int
87sys_perf_counter_open(struct perf_counter_attr *attr,
88 pid_t pid, int cpu, int group_fd,
89 unsigned long flags)
90{
91 attr->size = sizeof(*attr);
92 return syscall(__NR_perf_counter_open, attr, pid, cpu,
93 group_fd, flags);
94}
95
96#define MAX_COUNTERS 256
97#define MAX_NR_CPUS 256
98
99struct ip_callchain {
100 u64 nr;
101 u64 ips[0];
102};
103
104#endif
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
new file mode 100755
index 000000000000..c561d1538c03
--- /dev/null
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -0,0 +1,42 @@
1#!/bin/sh
2
3GVF=PERF-VERSION-FILE
4DEF_VER=v0.0.1.PERF
5
6LF='
7'
8
9# First see if there is a version file (included in release tarballs),
10# then try git-describe, then default.
11if test -f version
12then
13 VN=$(cat version) || VN="$DEF_VER"
14elif test -d .git -o -f .git &&
15 VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
16 case "$VN" in
17 *$LF*) (exit 1) ;;
18 v[0-9]*)
19 git update-index -q --refresh
20 test -z "$(git diff-index --name-only HEAD --)" ||
21 VN="$VN-dirty" ;;
22 esac
23then
24 VN=$(echo "$VN" | sed -e 's/-/./g');
25else
26 VN="$DEF_VER"
27fi
28
29VN=$(expr "$VN" : v*'\(.*\)')
30
31if test -r $GVF
32then
33 VC=$(sed -e 's/^PERF_VERSION = //' <$GVF)
34else
35 VC=unset
36fi
37test "$VN" = "$VC" || {
38 echo >&2 "PERF_VERSION = $VN"
39 echo "PERF_VERSION = $VN" >$GVF
40}
41
42
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
new file mode 100644
index 000000000000..61d33b81fc97
--- /dev/null
+++ b/tools/perf/util/abspath.c
@@ -0,0 +1,117 @@
1#include "cache.h"
2
3/*
4 * Do not use this for inspecting *tracked* content. When path is a
5 * symlink to a directory, we do not want to say it is a directory when
6 * dealing with tracked content in the working tree.
7 */
8static int is_directory(const char *path)
9{
10 struct stat st;
11 return (!stat(path, &st) && S_ISDIR(st.st_mode));
12}
13
14/* We allow "recursive" symbolic links. Only within reason, though. */
15#define MAXDEPTH 5
16
17const char *make_absolute_path(const char *path)
18{
19 static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
20 char cwd[1024] = "";
21 int buf_index = 1, len;
22
23 int depth = MAXDEPTH;
24 char *last_elem = NULL;
25 struct stat st;
26
27 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
28 die ("Too long path: %.*s", 60, path);
29
30 while (depth--) {
31 if (!is_directory(buf)) {
32 char *last_slash = strrchr(buf, '/');
33 if (last_slash) {
34 *last_slash = '\0';
35 last_elem = xstrdup(last_slash + 1);
36 } else {
37 last_elem = xstrdup(buf);
38 *buf = '\0';
39 }
40 }
41
42 if (*buf) {
43 if (!*cwd && !getcwd(cwd, sizeof(cwd)))
44 die ("Could not get current working directory");
45
46 if (chdir(buf))
47 die ("Could not switch to '%s'", buf);
48 }
49 if (!getcwd(buf, PATH_MAX))
50 die ("Could not get current working directory");
51
52 if (last_elem) {
53 int len = strlen(buf);
54 if (len + strlen(last_elem) + 2 > PATH_MAX)
55 die ("Too long path name: '%s/%s'",
56 buf, last_elem);
57 buf[len] = '/';
58 strcpy(buf + len + 1, last_elem);
59 free(last_elem);
60 last_elem = NULL;
61 }
62
63 if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
64 len = readlink(buf, next_buf, PATH_MAX);
65 if (len < 0)
66 die ("Invalid symlink: %s", buf);
67 if (PATH_MAX <= len)
68 die("symbolic link too long: %s", buf);
69 next_buf[len] = '\0';
70 buf = next_buf;
71 buf_index = 1 - buf_index;
72 next_buf = bufs[buf_index];
73 } else
74 break;
75 }
76
77 if (*cwd && chdir(cwd))
78 die ("Could not change back to '%s'", cwd);
79
80 return buf;
81}
82
83static const char *get_pwd_cwd(void)
84{
85 static char cwd[PATH_MAX + 1];
86 char *pwd;
87 struct stat cwd_stat, pwd_stat;
88 if (getcwd(cwd, PATH_MAX) == NULL)
89 return NULL;
90 pwd = getenv("PWD");
91 if (pwd && strcmp(pwd, cwd)) {
92 stat(cwd, &cwd_stat);
93 if (!stat(pwd, &pwd_stat) &&
94 pwd_stat.st_dev == cwd_stat.st_dev &&
95 pwd_stat.st_ino == cwd_stat.st_ino) {
96 strlcpy(cwd, pwd, PATH_MAX);
97 }
98 }
99 return cwd;
100}
101
102const char *make_nonrelative_path(const char *path)
103{
104 static char buf[PATH_MAX + 1];
105
106 if (is_absolute_path(path)) {
107 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
108 die("Too long path: %.*s", 60, path);
109 } else {
110 const char *cwd = get_pwd_cwd();
111 if (!cwd)
112 die("Cannot determine the current working directory");
113 if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
114 die("Too long path: %.*s", 60, path);
115 }
116 return buf;
117}
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
new file mode 100644
index 000000000000..b8144e80bb1e
--- /dev/null
+++ b/tools/perf/util/alias.c
@@ -0,0 +1,77 @@
1#include "cache.h"
2
3static const char *alias_key;
4static char *alias_val;
5
6static int alias_lookup_cb(const char *k, const char *v, void *cb __used)
7{
8 if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
9 if (!v)
10 return config_error_nonbool(k);
11 alias_val = strdup(v);
12 return 0;
13 }
14 return 0;
15}
16
17char *alias_lookup(const char *alias)
18{
19 alias_key = alias;
20 alias_val = NULL;
21 perf_config(alias_lookup_cb, NULL);
22 return alias_val;
23}
24
25int split_cmdline(char *cmdline, const char ***argv)
26{
27 int src, dst, count = 0, size = 16;
28 char quoted = 0;
29
30 *argv = malloc(sizeof(char*) * size);
31
32 /* split alias_string */
33 (*argv)[count++] = cmdline;
34 for (src = dst = 0; cmdline[src];) {
35 char c = cmdline[src];
36 if (!quoted && isspace(c)) {
37 cmdline[dst++] = 0;
38 while (cmdline[++src]
39 && isspace(cmdline[src]))
40 ; /* skip */
41 if (count >= size) {
42 size += 16;
43 *argv = realloc(*argv, sizeof(char*) * size);
44 }
45 (*argv)[count++] = cmdline + dst;
46 } else if (!quoted && (c == '\'' || c == '"')) {
47 quoted = c;
48 src++;
49 } else if (c == quoted) {
50 quoted = 0;
51 src++;
52 } else {
53 if (c == '\\' && quoted != '\'') {
54 src++;
55 c = cmdline[src];
56 if (!c) {
57 free(*argv);
58 *argv = NULL;
59 return error("cmdline ends with \\");
60 }
61 }
62 cmdline[dst++] = c;
63 src++;
64 }
65 }
66
67 cmdline[dst] = 0;
68
69 if (quoted) {
70 free(*argv);
71 *argv = NULL;
72 return error("unclosed quote");
73 }
74
75 return count;
76}
77
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
new file mode 100644
index 000000000000..4b50c412b9c5
--- /dev/null
+++ b/tools/perf/util/cache.h
@@ -0,0 +1,121 @@
1#ifndef CACHE_H
2#define CACHE_H
3
4#include "util.h"
5#include "strbuf.h"
6#include "../perf.h"
7
8#define PERF_DIR_ENVIRONMENT "PERF_DIR"
9#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
10#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
11#define DB_ENVIRONMENT "PERF_OBJECT_DIRECTORY"
12#define INDEX_ENVIRONMENT "PERF_INDEX_FILE"
13#define GRAFT_ENVIRONMENT "PERF_GRAFT_FILE"
14#define TEMPLATE_DIR_ENVIRONMENT "PERF_TEMPLATE_DIR"
15#define CONFIG_ENVIRONMENT "PERF_CONFIG"
16#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH"
17#define CEILING_DIRECTORIES_ENVIRONMENT "PERF_CEILING_DIRECTORIES"
18#define PERFATTRIBUTES_FILE ".perfattributes"
19#define INFOATTRIBUTES_FILE "info/attributes"
20#define ATTRIBUTE_MACRO_PREFIX "[attr]"
21#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
22
23typedef int (*config_fn_t)(const char *, const char *, void *);
24extern int perf_default_config(const char *, const char *, void *);
25extern int perf_config_from_file(config_fn_t fn, const char *, void *);
26extern int perf_config(config_fn_t fn, void *);
27extern int perf_parse_ulong(const char *, unsigned long *);
28extern int perf_config_int(const char *, const char *);
29extern unsigned long perf_config_ulong(const char *, const char *);
30extern int perf_config_bool_or_int(const char *, const char *, int *);
31extern int perf_config_bool(const char *, const char *);
32extern int perf_config_string(const char **, const char *, const char *);
33extern int perf_config_set(const char *, const char *);
34extern int perf_config_set_multivar(const char *, const char *, const char *, int);
35extern int perf_config_rename_section(const char *, const char *);
36extern const char *perf_etc_perfconfig(void);
37extern int check_repository_format_version(const char *var, const char *value, void *cb);
38extern int perf_config_system(void);
39extern int perf_config_global(void);
40extern int config_error_nonbool(const char *);
41extern const char *config_exclusive_filename;
42
43#define MAX_PERFNAME (1000)
44extern char perf_default_email[MAX_PERFNAME];
45extern char perf_default_name[MAX_PERFNAME];
46extern int user_ident_explicitly_given;
47
48extern const char *perf_log_output_encoding;
49extern const char *perf_mailmap_file;
50
51/* IO helper functions */
52extern void maybe_flush_or_die(FILE *, const char *);
53extern int copy_fd(int ifd, int ofd);
54extern int copy_file(const char *dst, const char *src, int mode);
55extern ssize_t read_in_full(int fd, void *buf, size_t count);
56extern ssize_t write_in_full(int fd, const void *buf, size_t count);
57extern void write_or_die(int fd, const void *buf, size_t count);
58extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
59extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
60extern void fsync_or_die(int fd, const char *);
61
62/* pager.c */
63extern void setup_pager(void);
64extern const char *pager_program;
65extern int pager_in_use(void);
66extern int pager_use_color;
67
68extern const char *editor_program;
69extern const char *excludes_file;
70
71char *alias_lookup(const char *alias);
72int split_cmdline(char *cmdline, const char ***argv);
73
74#define alloc_nr(x) (((x)+16)*3/2)
75
76/*
77 * Realloc the buffer pointed at by variable 'x' so that it can hold
78 * at least 'nr' entries; the number of entries currently allocated
79 * is 'alloc', using the standard growing factor alloc_nr() macro.
80 *
81 * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
82 */
83#define ALLOC_GROW(x, nr, alloc) \
84 do { \
85 if ((nr) > alloc) { \
86 if (alloc_nr(alloc) < (nr)) \
87 alloc = (nr); \
88 else \
89 alloc = alloc_nr(alloc); \
90 x = xrealloc((x), alloc * sizeof(*(x))); \
91 } \
92 } while(0)
93
94
95static inline int is_absolute_path(const char *path)
96{
97 return path[0] == '/';
98}
99
100const char *make_absolute_path(const char *path);
101const char *make_nonrelative_path(const char *path);
102const char *make_relative_path(const char *abs, const char *base);
103int normalize_path_copy(char *dst, const char *src);
104int longest_ancestor_length(const char *path, const char *prefix_list);
105char *strip_path_suffix(const char *path, const char *suffix);
106
107extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
108extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
109/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
110extern int perf_mkstemp(char *path, size_t len, const char *template);
111
112extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
113 __attribute__((format (printf, 3, 4)));
114extern char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
115 __attribute__((format (printf, 3, 4)));
116extern char *perf_pathdup(const char *fmt, ...)
117 __attribute__((format (printf, 1, 2)));
118
119extern size_t strlcpy(char *dest, const char *src, size_t size);
120
121#endif /* CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
new file mode 100644
index 000000000000..011473411642
--- /dev/null
+++ b/tools/perf/util/callchain.c
@@ -0,0 +1,343 @@
1/*
2 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree.
6 *
7 * Using a radix for code path provides a fast retrieval and factorizes
8 * memory use. Also that lets us use the paths in a hierarchical graph view.
9 *
10 */
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <errno.h>
16#include <math.h>
17
18#include "callchain.h"
19
20#define chain_for_each_child(child, parent) \
21 list_for_each_entry(child, &parent->children, brothers)
22
23static void
24rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
25 enum chain_mode mode)
26{
27 struct rb_node **p = &root->rb_node;
28 struct rb_node *parent = NULL;
29 struct callchain_node *rnode;
30 u64 chain_cumul = cumul_hits(chain);
31
32 while (*p) {
33 u64 rnode_cumul;
34
35 parent = *p;
36 rnode = rb_entry(parent, struct callchain_node, rb_node);
37 rnode_cumul = cumul_hits(rnode);
38
39 switch (mode) {
40 case CHAIN_FLAT:
41 if (rnode->hit < chain->hit)
42 p = &(*p)->rb_left;
43 else
44 p = &(*p)->rb_right;
45 break;
46 case CHAIN_GRAPH_ABS: /* Falldown */
47 case CHAIN_GRAPH_REL:
48 if (rnode_cumul < chain_cumul)
49 p = &(*p)->rb_left;
50 else
51 p = &(*p)->rb_right;
52 break;
53 default:
54 break;
55 }
56 }
57
58 rb_link_node(&chain->rb_node, parent, p);
59 rb_insert_color(&chain->rb_node, root);
60}
61
62static void
63__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
64 u64 min_hit)
65{
66 struct callchain_node *child;
67
68 chain_for_each_child(child, node)
69 __sort_chain_flat(rb_root, child, min_hit);
70
71 if (node->hit && node->hit >= min_hit)
72 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
73}
74
75/*
76 * Once we get every callchains from the stream, we can now
77 * sort them by hit
78 */
79static void
80sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
81 u64 min_hit, struct callchain_param *param __used)
82{
83 __sort_chain_flat(rb_root, node, min_hit);
84}
85
86static void __sort_chain_graph_abs(struct callchain_node *node,
87 u64 min_hit)
88{
89 struct callchain_node *child;
90
91 node->rb_root = RB_ROOT;
92
93 chain_for_each_child(child, node) {
94 __sort_chain_graph_abs(child, min_hit);
95 if (cumul_hits(child) >= min_hit)
96 rb_insert_callchain(&node->rb_root, child,
97 CHAIN_GRAPH_ABS);
98 }
99}
100
101static void
102sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
103 u64 min_hit, struct callchain_param *param __used)
104{
105 __sort_chain_graph_abs(chain_root, min_hit);
106 rb_root->rb_node = chain_root->rb_root.rb_node;
107}
108
109static void __sort_chain_graph_rel(struct callchain_node *node,
110 double min_percent)
111{
112 struct callchain_node *child;
113 u64 min_hit;
114
115 node->rb_root = RB_ROOT;
116 min_hit = ceil(node->children_hit * min_percent);
117
118 chain_for_each_child(child, node) {
119 __sort_chain_graph_rel(child, min_percent);
120 if (cumul_hits(child) >= min_hit)
121 rb_insert_callchain(&node->rb_root, child,
122 CHAIN_GRAPH_REL);
123 }
124}
125
126static void
127sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
128 u64 min_hit __used, struct callchain_param *param)
129{
130 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0);
131 rb_root->rb_node = chain_root->rb_root.rb_node;
132}
133
134int register_callchain_param(struct callchain_param *param)
135{
136 switch (param->mode) {
137 case CHAIN_GRAPH_ABS:
138 param->sort = sort_chain_graph_abs;
139 break;
140 case CHAIN_GRAPH_REL:
141 param->sort = sort_chain_graph_rel;
142 break;
143 case CHAIN_FLAT:
144 param->sort = sort_chain_flat;
145 break;
146 default:
147 return -1;
148 }
149 return 0;
150}
151
152/*
153 * Create a child for a parent. If inherit_children, then the new child
154 * will become the new parent of it's parent children
155 */
156static struct callchain_node *
157create_child(struct callchain_node *parent, bool inherit_children)
158{
159 struct callchain_node *new;
160
161 new = malloc(sizeof(*new));
162 if (!new) {
163 perror("not enough memory to create child for code path tree");
164 return NULL;
165 }
166 new->parent = parent;
167 INIT_LIST_HEAD(&new->children);
168 INIT_LIST_HEAD(&new->val);
169
170 if (inherit_children) {
171 struct callchain_node *next;
172
173 list_splice(&parent->children, &new->children);
174 INIT_LIST_HEAD(&parent->children);
175
176 chain_for_each_child(next, new)
177 next->parent = new;
178 }
179 list_add_tail(&new->brothers, &parent->children);
180
181 return new;
182}
183
184/*
185 * Fill the node with callchain values
186 */
187static void
188fill_node(struct callchain_node *node, struct ip_callchain *chain,
189 int start, struct symbol **syms)
190{
191 unsigned int i;
192
193 for (i = start; i < chain->nr; i++) {
194 struct callchain_list *call;
195
196 call = malloc(sizeof(*call));
197 if (!call) {
198 perror("not enough memory for the code path tree");
199 return;
200 }
201 call->ip = chain->ips[i];
202 call->sym = syms[i];
203 list_add_tail(&call->list, &node->val);
204 }
205 node->val_nr = chain->nr - start;
206 if (!node->val_nr)
207 printf("Warning: empty node in callchain tree\n");
208}
209
210static void
211add_child(struct callchain_node *parent, struct ip_callchain *chain,
212 int start, struct symbol **syms)
213{
214 struct callchain_node *new;
215
216 new = create_child(parent, false);
217 fill_node(new, chain, start, syms);
218
219 new->children_hit = 0;
220 new->hit = 1;
221}
222
223/*
224 * Split the parent in two parts (a new child is created) and
225 * give a part of its callchain to the created child.
226 * Then create another child to host the given callchain of new branch
227 */
228static void
229split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
230 struct callchain_list *to_split, int idx_parents, int idx_local,
231 struct symbol **syms)
232{
233 struct callchain_node *new;
234 struct list_head *old_tail;
235 unsigned int idx_total = idx_parents + idx_local;
236
237 /* split */
238 new = create_child(parent, true);
239
240 /* split the callchain and move a part to the new child */
241 old_tail = parent->val.prev;
242 list_del_range(&to_split->list, old_tail);
243 new->val.next = &to_split->list;
244 new->val.prev = old_tail;
245 to_split->list.prev = &new->val;
246 old_tail->next = &new->val;
247
248 /* split the hits */
249 new->hit = parent->hit;
250 new->children_hit = parent->children_hit;
251 parent->children_hit = cumul_hits(new);
252 new->val_nr = parent->val_nr - idx_local;
253 parent->val_nr = idx_local;
254
255 /* create a new child for the new branch if any */
256 if (idx_total < chain->nr) {
257 parent->hit = 0;
258 add_child(parent, chain, idx_total, syms);
259 parent->children_hit++;
260 } else {
261 parent->hit = 1;
262 }
263}
264
265static int
266__append_chain(struct callchain_node *root, struct ip_callchain *chain,
267 unsigned int start, struct symbol **syms);
268
269static void
270__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
271 struct symbol **syms, unsigned int start)
272{
273 struct callchain_node *rnode;
274
275 /* lookup in childrens */
276 chain_for_each_child(rnode, root) {
277 unsigned int ret = __append_chain(rnode, chain, start, syms);
278
279 if (!ret)
280 goto inc_children_hit;
281 }
282 /* nothing in children, add to the current node */
283 add_child(root, chain, start, syms);
284
285inc_children_hit:
286 root->children_hit++;
287}
288
289static int
290__append_chain(struct callchain_node *root, struct ip_callchain *chain,
291 unsigned int start, struct symbol **syms)
292{
293 struct callchain_list *cnode;
294 unsigned int i = start;
295 bool found = false;
296
297 /*
298 * Lookup in the current node
299 * If we have a symbol, then compare the start to match
300 * anywhere inside a function.
301 */
302 list_for_each_entry(cnode, &root->val, list) {
303 if (i == chain->nr)
304 break;
305 if (cnode->sym && syms[i]) {
306 if (cnode->sym->start != syms[i]->start)
307 break;
308 } else if (cnode->ip != chain->ips[i])
309 break;
310 if (!found)
311 found = true;
312 i++;
313 }
314
315 /* matches not, relay on the parent */
316 if (!found)
317 return -1;
318
319 /* we match only a part of the node. Split it and add the new chain */
320 if (i - start < root->val_nr) {
321 split_add_child(root, chain, cnode, start, i - start, syms);
322 return 0;
323 }
324
325 /* we match 100% of the path, increment the hit */
326 if (i - start == root->val_nr && i == chain->nr) {
327 root->hit++;
328 return 0;
329 }
330
331 /* We match the node and still have a part remaining */
332 __append_chain_children(root, chain, syms, i);
333
334 return 0;
335}
336
337void append_chain(struct callchain_node *root, struct ip_callchain *chain,
338 struct symbol **syms)
339{
340 if (!chain->nr)
341 return;
342 __append_chain_children(root, chain, syms, 0);
343}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
new file mode 100644
index 000000000000..a926ae4f5a16
--- /dev/null
+++ b/tools/perf/util/callchain.h
@@ -0,0 +1,60 @@
1#ifndef __PERF_CALLCHAIN_H
2#define __PERF_CALLCHAIN_H
3
4#include "../perf.h"
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include "symbol.h"
8
9enum chain_mode {
10 CHAIN_NONE,
11 CHAIN_FLAT,
12 CHAIN_GRAPH_ABS,
13 CHAIN_GRAPH_REL
14};
15
16struct callchain_node {
17 struct callchain_node *parent;
18 struct list_head brothers;
19 struct list_head children;
20 struct list_head val;
21 struct rb_node rb_node; /* to sort nodes in an rbtree */
22 struct rb_root rb_root; /* sorted tree of children */
23 unsigned int val_nr;
24 u64 hit;
25 u64 children_hit;
26};
27
28struct callchain_param;
29
30typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
31 u64, struct callchain_param *);
32
33struct callchain_param {
34 enum chain_mode mode;
35 double min_percent;
36 sort_chain_func_t sort;
37};
38
39struct callchain_list {
40 u64 ip;
41 struct symbol *sym;
42 struct list_head list;
43};
44
45static inline void callchain_init(struct callchain_node *node)
46{
47 INIT_LIST_HEAD(&node->brothers);
48 INIT_LIST_HEAD(&node->children);
49 INIT_LIST_HEAD(&node->val);
50}
51
52static inline u64 cumul_hits(struct callchain_node *node)
53{
54 return node->hit + node->children_hit;
55}
56
57int register_callchain_param(struct callchain_param *param);
58void append_chain(struct callchain_node *root, struct ip_callchain *chain,
59 struct symbol **syms);
60#endif
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
new file mode 100644
index 000000000000..90a044d1fe7d
--- /dev/null
+++ b/tools/perf/util/color.c
@@ -0,0 +1,272 @@
1#include "cache.h"
2#include "color.h"
3
4int perf_use_color_default = -1;
5
6static int parse_color(const char *name, int len)
7{
8 static const char * const color_names[] = {
9 "normal", "black", "red", "green", "yellow",
10 "blue", "magenta", "cyan", "white"
11 };
12 char *end;
13 int i;
14
15 for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) {
16 const char *str = color_names[i];
17 if (!strncasecmp(name, str, len) && !str[len])
18 return i - 1;
19 }
20 i = strtol(name, &end, 10);
21 if (end - name == len && i >= -1 && i <= 255)
22 return i;
23 return -2;
24}
25
26static int parse_attr(const char *name, int len)
27{
28 static const int attr_values[] = { 1, 2, 4, 5, 7 };
29 static const char * const attr_names[] = {
30 "bold", "dim", "ul", "blink", "reverse"
31 };
32 unsigned int i;
33
34 for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
35 const char *str = attr_names[i];
36 if (!strncasecmp(name, str, len) && !str[len])
37 return attr_values[i];
38 }
39 return -1;
40}
41
42void color_parse(const char *value, const char *var, char *dst)
43{
44 color_parse_mem(value, strlen(value), var, dst);
45}
46
47void color_parse_mem(const char *value, int value_len, const char *var,
48 char *dst)
49{
50 const char *ptr = value;
51 int len = value_len;
52 int attr = -1;
53 int fg = -2;
54 int bg = -2;
55
56 if (!strncasecmp(value, "reset", len)) {
57 strcpy(dst, PERF_COLOR_RESET);
58 return;
59 }
60
61 /* [fg [bg]] [attr] */
62 while (len > 0) {
63 const char *word = ptr;
64 int val, wordlen = 0;
65
66 while (len > 0 && !isspace(word[wordlen])) {
67 wordlen++;
68 len--;
69 }
70
71 ptr = word + wordlen;
72 while (len > 0 && isspace(*ptr)) {
73 ptr++;
74 len--;
75 }
76
77 val = parse_color(word, wordlen);
78 if (val >= -1) {
79 if (fg == -2) {
80 fg = val;
81 continue;
82 }
83 if (bg == -2) {
84 bg = val;
85 continue;
86 }
87 goto bad;
88 }
89 val = parse_attr(word, wordlen);
90 if (val < 0 || attr != -1)
91 goto bad;
92 attr = val;
93 }
94
95 if (attr >= 0 || fg >= 0 || bg >= 0) {
96 int sep = 0;
97
98 *dst++ = '\033';
99 *dst++ = '[';
100 if (attr >= 0) {
101 *dst++ = '0' + attr;
102 sep++;
103 }
104 if (fg >= 0) {
105 if (sep++)
106 *dst++ = ';';
107 if (fg < 8) {
108 *dst++ = '3';
109 *dst++ = '0' + fg;
110 } else {
111 dst += sprintf(dst, "38;5;%d", fg);
112 }
113 }
114 if (bg >= 0) {
115 if (sep++)
116 *dst++ = ';';
117 if (bg < 8) {
118 *dst++ = '4';
119 *dst++ = '0' + bg;
120 } else {
121 dst += sprintf(dst, "48;5;%d", bg);
122 }
123 }
124 *dst++ = 'm';
125 }
126 *dst = 0;
127 return;
128bad:
129 die("bad color value '%.*s' for variable '%s'", value_len, value, var);
130}
131
132int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
133{
134 if (value) {
135 if (!strcasecmp(value, "never"))
136 return 0;
137 if (!strcasecmp(value, "always"))
138 return 1;
139 if (!strcasecmp(value, "auto"))
140 goto auto_color;
141 }
142
143 /* Missing or explicit false to turn off colorization */
144 if (!perf_config_bool(var, value))
145 return 0;
146
147 /* any normal truth value defaults to 'auto' */
148 auto_color:
149 if (stdout_is_tty < 0)
150 stdout_is_tty = isatty(1);
151 if (stdout_is_tty || (pager_in_use() && pager_use_color)) {
152 char *term = getenv("TERM");
153 if (term && strcmp(term, "dumb"))
154 return 1;
155 }
156 return 0;
157}
158
159int perf_color_default_config(const char *var, const char *value, void *cb)
160{
161 if (!strcmp(var, "color.ui")) {
162 perf_use_color_default = perf_config_colorbool(var, value, -1);
163 return 0;
164 }
165
166 return perf_default_config(var, value, cb);
167}
168
169static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
170 va_list args, const char *trail)
171{
172 int r = 0;
173
174 /*
175 * Auto-detect:
176 */
177 if (perf_use_color_default < 0) {
178 if (isatty(1) || pager_in_use())
179 perf_use_color_default = 1;
180 else
181 perf_use_color_default = 0;
182 }
183
184 if (perf_use_color_default && *color)
185 r += fprintf(fp, "%s", color);
186 r += vfprintf(fp, fmt, args);
187 if (perf_use_color_default && *color)
188 r += fprintf(fp, "%s", PERF_COLOR_RESET);
189 if (trail)
190 r += fprintf(fp, "%s", trail);
191 return r;
192}
193
194
195
196int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
197{
198 va_list args;
199 int r;
200
201 va_start(args, fmt);
202 r = color_vfprintf(fp, color, fmt, args, NULL);
203 va_end(args);
204 return r;
205}
206
207int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
208{
209 va_list args;
210 int r;
211 va_start(args, fmt);
212 r = color_vfprintf(fp, color, fmt, args, "\n");
213 va_end(args);
214 return r;
215}
216
217/*
218 * This function splits the buffer by newlines and colors the lines individually.
219 *
220 * Returns 0 on success.
221 */
222int color_fwrite_lines(FILE *fp, const char *color,
223 size_t count, const char *buf)
224{
225 if (!*color)
226 return fwrite(buf, count, 1, fp) != 1;
227
228 while (count) {
229 char *p = memchr(buf, '\n', count);
230
231 if (p != buf && (fputs(color, fp) < 0 ||
232 fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
233 fputs(PERF_COLOR_RESET, fp) < 0))
234 return -1;
235 if (!p)
236 return 0;
237 if (fputc('\n', fp) < 0)
238 return -1;
239 count -= p + 1 - buf;
240 buf = p + 1;
241 }
242 return 0;
243}
244
245char *get_percent_color(double percent)
246{
247 char *color = PERF_COLOR_NORMAL;
248
249 /*
250 * We color high-overhead entries in red, mid-overhead
251 * entries in green - and keep the low overhead places
252 * normal:
253 */
254 if (percent >= MIN_RED)
255 color = PERF_COLOR_RED;
256 else {
257 if (percent > MIN_GREEN)
258 color = PERF_COLOR_GREEN;
259 }
260 return color;
261}
262
263int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
264{
265 int r;
266 char *color;
267
268 color = get_percent_color(percent);
269 r = color_fprintf(fp, color, fmt, percent);
270
271 return r;
272}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
new file mode 100644
index 000000000000..706cec50bd25
--- /dev/null
+++ b/tools/perf/util/color.h
@@ -0,0 +1,41 @@
1#ifndef COLOR_H
2#define COLOR_H
3
4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
5#define COLOR_MAXLEN 24
6
7#define PERF_COLOR_NORMAL ""
8#define PERF_COLOR_RESET "\033[m"
9#define PERF_COLOR_BOLD "\033[1m"
10#define PERF_COLOR_RED "\033[31m"
11#define PERF_COLOR_GREEN "\033[32m"
12#define PERF_COLOR_YELLOW "\033[33m"
13#define PERF_COLOR_BLUE "\033[34m"
14#define PERF_COLOR_MAGENTA "\033[35m"
15#define PERF_COLOR_CYAN "\033[36m"
16#define PERF_COLOR_BG_RED "\033[41m"
17
18#define MIN_GREEN 0.5
19#define MIN_RED 5.0
20
21/*
22 * This variable stores the value of color.ui
23 */
24extern int perf_use_color_default;
25
26
27/*
28 * Use this instead of perf_default_config if you need the value of color.ui.
29 */
30int perf_color_default_config(const char *var, const char *value, void *cb);
31
32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
33void color_parse(const char *value, const char *var, char *dst);
34void color_parse_mem(const char *value, int len, const char *var, char *dst);
35int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
36int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
37int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
38int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
39char *get_percent_color(double percent);
40
41#endif /* COLOR_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
new file mode 100644
index 000000000000..780df541006d
--- /dev/null
+++ b/tools/perf/util/config.c
@@ -0,0 +1,875 @@
1/*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 * Copyright (C) Johannes Schindelin, 2005
6 *
7 */
8#include "util.h"
9#include "cache.h"
10#include "exec_cmd.h"
11
12#define MAXNAME (256)
13
14static FILE *config_file;
15static const char *config_file_name;
16static int config_linenr;
17static int config_file_eof;
18
19const char *config_exclusive_filename = NULL;
20
21static int get_next_char(void)
22{
23 int c;
24 FILE *f;
25
26 c = '\n';
27 if ((f = config_file) != NULL) {
28 c = fgetc(f);
29 if (c == '\r') {
30 /* DOS like systems */
31 c = fgetc(f);
32 if (c != '\n') {
33 ungetc(c, f);
34 c = '\r';
35 }
36 }
37 if (c == '\n')
38 config_linenr++;
39 if (c == EOF) {
40 config_file_eof = 1;
41 c = '\n';
42 }
43 }
44 return c;
45}
46
47static char *parse_value(void)
48{
49 static char value[1024];
50 int quote = 0, comment = 0, space = 0;
51 size_t len = 0;
52
53 for (;;) {
54 int c = get_next_char();
55
56 if (len >= sizeof(value) - 1)
57 return NULL;
58 if (c == '\n') {
59 if (quote)
60 return NULL;
61 value[len] = 0;
62 return value;
63 }
64 if (comment)
65 continue;
66 if (isspace(c) && !quote) {
67 space = 1;
68 continue;
69 }
70 if (!quote) {
71 if (c == ';' || c == '#') {
72 comment = 1;
73 continue;
74 }
75 }
76 if (space) {
77 if (len)
78 value[len++] = ' ';
79 space = 0;
80 }
81 if (c == '\\') {
82 c = get_next_char();
83 switch (c) {
84 case '\n':
85 continue;
86 case 't':
87 c = '\t';
88 break;
89 case 'b':
90 c = '\b';
91 break;
92 case 'n':
93 c = '\n';
94 break;
95 /* Some characters escape as themselves */
96 case '\\': case '"':
97 break;
98 /* Reject unknown escape sequences */
99 default:
100 return NULL;
101 }
102 value[len++] = c;
103 continue;
104 }
105 if (c == '"') {
106 quote = 1-quote;
107 continue;
108 }
109 value[len++] = c;
110 }
111}
112
113static inline int iskeychar(int c)
114{
115 return isalnum(c) || c == '-';
116}
117
118static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
119{
120 int c;
121 char *value;
122
123 /* Get the full name */
124 for (;;) {
125 c = get_next_char();
126 if (config_file_eof)
127 break;
128 if (!iskeychar(c))
129 break;
130 name[len++] = tolower(c);
131 if (len >= MAXNAME)
132 return -1;
133 }
134 name[len] = 0;
135 while (c == ' ' || c == '\t')
136 c = get_next_char();
137
138 value = NULL;
139 if (c != '\n') {
140 if (c != '=')
141 return -1;
142 value = parse_value();
143 if (!value)
144 return -1;
145 }
146 return fn(name, value, data);
147}
148
149static int get_extended_base_var(char *name, int baselen, int c)
150{
151 do {
152 if (c == '\n')
153 return -1;
154 c = get_next_char();
155 } while (isspace(c));
156
157 /* We require the format to be '[base "extension"]' */
158 if (c != '"')
159 return -1;
160 name[baselen++] = '.';
161
162 for (;;) {
163 int c = get_next_char();
164 if (c == '\n')
165 return -1;
166 if (c == '"')
167 break;
168 if (c == '\\') {
169 c = get_next_char();
170 if (c == '\n')
171 return -1;
172 }
173 name[baselen++] = c;
174 if (baselen > MAXNAME / 2)
175 return -1;
176 }
177
178 /* Final ']' */
179 if (get_next_char() != ']')
180 return -1;
181 return baselen;
182}
183
184static int get_base_var(char *name)
185{
186 int baselen = 0;
187
188 for (;;) {
189 int c = get_next_char();
190 if (config_file_eof)
191 return -1;
192 if (c == ']')
193 return baselen;
194 if (isspace(c))
195 return get_extended_base_var(name, baselen, c);
196 if (!iskeychar(c) && c != '.')
197 return -1;
198 if (baselen > MAXNAME / 2)
199 return -1;
200 name[baselen++] = tolower(c);
201 }
202}
203
204static int perf_parse_file(config_fn_t fn, void *data)
205{
206 int comment = 0;
207 int baselen = 0;
208 static char var[MAXNAME];
209
210 /* U+FEFF Byte Order Mark in UTF8 */
211 static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
212 const unsigned char *bomptr = utf8_bom;
213
214 for (;;) {
215 int c = get_next_char();
216 if (bomptr && *bomptr) {
217 /* We are at the file beginning; skip UTF8-encoded BOM
218 * if present. Sane editors won't put this in on their
219 * own, but e.g. Windows Notepad will do it happily. */
220 if ((unsigned char) c == *bomptr) {
221 bomptr++;
222 continue;
223 } else {
224 /* Do not tolerate partial BOM. */
225 if (bomptr != utf8_bom)
226 break;
227 /* No BOM at file beginning. Cool. */
228 bomptr = NULL;
229 }
230 }
231 if (c == '\n') {
232 if (config_file_eof)
233 return 0;
234 comment = 0;
235 continue;
236 }
237 if (comment || isspace(c))
238 continue;
239 if (c == '#' || c == ';') {
240 comment = 1;
241 continue;
242 }
243 if (c == '[') {
244 baselen = get_base_var(var);
245 if (baselen <= 0)
246 break;
247 var[baselen++] = '.';
248 var[baselen] = 0;
249 continue;
250 }
251 if (!isalpha(c))
252 break;
253 var[baselen] = tolower(c);
254 if (get_value(fn, data, var, baselen+1) < 0)
255 break;
256 }
257 die("bad config file line %d in %s", config_linenr, config_file_name);
258}
259
260static int parse_unit_factor(const char *end, unsigned long *val)
261{
262 if (!*end)
263 return 1;
264 else if (!strcasecmp(end, "k")) {
265 *val *= 1024;
266 return 1;
267 }
268 else if (!strcasecmp(end, "m")) {
269 *val *= 1024 * 1024;
270 return 1;
271 }
272 else if (!strcasecmp(end, "g")) {
273 *val *= 1024 * 1024 * 1024;
274 return 1;
275 }
276 return 0;
277}
278
279static int perf_parse_long(const char *value, long *ret)
280{
281 if (value && *value) {
282 char *end;
283 long val = strtol(value, &end, 0);
284 unsigned long factor = 1;
285 if (!parse_unit_factor(end, &factor))
286 return 0;
287 *ret = val * factor;
288 return 1;
289 }
290 return 0;
291}
292
293int perf_parse_ulong(const char *value, unsigned long *ret)
294{
295 if (value && *value) {
296 char *end;
297 unsigned long val = strtoul(value, &end, 0);
298 if (!parse_unit_factor(end, &val))
299 return 0;
300 *ret = val;
301 return 1;
302 }
303 return 0;
304}
305
306static void die_bad_config(const char *name)
307{
308 if (config_file_name)
309 die("bad config value for '%s' in %s", name, config_file_name);
310 die("bad config value for '%s'", name);
311}
312
313int perf_config_int(const char *name, const char *value)
314{
315 long ret = 0;
316 if (!perf_parse_long(value, &ret))
317 die_bad_config(name);
318 return ret;
319}
320
321unsigned long perf_config_ulong(const char *name, const char *value)
322{
323 unsigned long ret;
324 if (!perf_parse_ulong(value, &ret))
325 die_bad_config(name);
326 return ret;
327}
328
329int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
330{
331 *is_bool = 1;
332 if (!value)
333 return 1;
334 if (!*value)
335 return 0;
336 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
337 return 1;
338 if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
339 return 0;
340 *is_bool = 0;
341 return perf_config_int(name, value);
342}
343
344int perf_config_bool(const char *name, const char *value)
345{
346 int discard;
347 return !!perf_config_bool_or_int(name, value, &discard);
348}
349
350int perf_config_string(const char **dest, const char *var, const char *value)
351{
352 if (!value)
353 return config_error_nonbool(var);
354 *dest = strdup(value);
355 return 0;
356}
357
358static int perf_default_core_config(const char *var __used, const char *value __used)
359{
360 /* Add other config variables here and to Documentation/config.txt. */
361 return 0;
362}
363
364int perf_default_config(const char *var, const char *value, void *dummy __used)
365{
366 if (!prefixcmp(var, "core."))
367 return perf_default_core_config(var, value);
368
369 /* Add other config variables here and to Documentation/config.txt. */
370 return 0;
371}
372
373int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
374{
375 int ret;
376 FILE *f = fopen(filename, "r");
377
378 ret = -1;
379 if (f) {
380 config_file = f;
381 config_file_name = filename;
382 config_linenr = 1;
383 config_file_eof = 0;
384 ret = perf_parse_file(fn, data);
385 fclose(f);
386 config_file_name = NULL;
387 }
388 return ret;
389}
390
391const char *perf_etc_perfconfig(void)
392{
393 static const char *system_wide;
394 if (!system_wide)
395 system_wide = system_path(ETC_PERFCONFIG);
396 return system_wide;
397}
398
399static int perf_env_bool(const char *k, int def)
400{
401 const char *v = getenv(k);
402 return v ? perf_config_bool(k, v) : def;
403}
404
405int perf_config_system(void)
406{
407 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
408}
409
410int perf_config_global(void)
411{
412 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
413}
414
415int perf_config(config_fn_t fn, void *data)
416{
417 int ret = 0, found = 0;
418 char *repo_config = NULL;
419 const char *home = NULL;
420
421 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
422 if (config_exclusive_filename)
423 return perf_config_from_file(fn, config_exclusive_filename, data);
424 if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
425 ret += perf_config_from_file(fn, perf_etc_perfconfig(),
426 data);
427 found += 1;
428 }
429
430 home = getenv("HOME");
431 if (perf_config_global() && home) {
432 char *user_config = strdup(mkpath("%s/.perfconfig", home));
433 if (!access(user_config, R_OK)) {
434 ret += perf_config_from_file(fn, user_config, data);
435 found += 1;
436 }
437 free(user_config);
438 }
439
440 repo_config = perf_pathdup("config");
441 if (!access(repo_config, R_OK)) {
442 ret += perf_config_from_file(fn, repo_config, data);
443 found += 1;
444 }
445 free(repo_config);
446 if (found == 0)
447 return -1;
448 return ret;
449}
450
451/*
452 * Find all the stuff for perf_config_set() below.
453 */
454
455#define MAX_MATCHES 512
456
457static struct {
458 int baselen;
459 char* key;
460 int do_not_match;
461 regex_t* value_regex;
462 int multi_replace;
463 size_t offset[MAX_MATCHES];
464 enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
465 int seen;
466} store;
467
468static int matches(const char* key, const char* value)
469{
470 return !strcmp(key, store.key) &&
471 (store.value_regex == NULL ||
472 (store.do_not_match ^
473 !regexec(store.value_regex, value, 0, NULL, 0)));
474}
475
476static int store_aux(const char* key, const char* value, void *cb __used)
477{
478 int section_len;
479 const char *ep;
480
481 switch (store.state) {
482 case KEY_SEEN:
483 if (matches(key, value)) {
484 if (store.seen == 1 && store.multi_replace == 0) {
485 warning("%s has multiple values", key);
486 } else if (store.seen >= MAX_MATCHES) {
487 error("too many matches for %s", key);
488 return 1;
489 }
490
491 store.offset[store.seen] = ftell(config_file);
492 store.seen++;
493 }
494 break;
495 case SECTION_SEEN:
496 /*
497 * What we are looking for is in store.key (both
498 * section and var), and its section part is baselen
499 * long. We found key (again, both section and var).
500 * We would want to know if this key is in the same
501 * section as what we are looking for. We already
502 * know we are in the same section as what should
503 * hold store.key.
504 */
505 ep = strrchr(key, '.');
506 section_len = ep - key;
507
508 if ((section_len != store.baselen) ||
509 memcmp(key, store.key, section_len+1)) {
510 store.state = SECTION_END_SEEN;
511 break;
512 }
513
514 /*
515 * Do not increment matches: this is no match, but we
516 * just made sure we are in the desired section.
517 */
518 store.offset[store.seen] = ftell(config_file);
519 /* fallthru */
520 case SECTION_END_SEEN:
521 case START:
522 if (matches(key, value)) {
523 store.offset[store.seen] = ftell(config_file);
524 store.state = KEY_SEEN;
525 store.seen++;
526 } else {
527 if (strrchr(key, '.') - key == store.baselen &&
528 !strncmp(key, store.key, store.baselen)) {
529 store.state = SECTION_SEEN;
530 store.offset[store.seen] = ftell(config_file);
531 }
532 }
533 }
534 return 0;
535}
536
537static int store_write_section(int fd, const char* key)
538{
539 const char *dot;
540 int i, success;
541 struct strbuf sb = STRBUF_INIT;
542
543 dot = memchr(key, '.', store.baselen);
544 if (dot) {
545 strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
546 for (i = dot - key + 1; i < store.baselen; i++) {
547 if (key[i] == '"' || key[i] == '\\')
548 strbuf_addch(&sb, '\\');
549 strbuf_addch(&sb, key[i]);
550 }
551 strbuf_addstr(&sb, "\"]\n");
552 } else {
553 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
554 }
555
556 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
557 strbuf_release(&sb);
558
559 return success;
560}
561
562static int store_write_pair(int fd, const char* key, const char* value)
563{
564 int i, success;
565 int length = strlen(key + store.baselen + 1);
566 const char *quote = "";
567 struct strbuf sb = STRBUF_INIT;
568
569 /*
570 * Check to see if the value needs to be surrounded with a dq pair.
571 * Note that problematic characters are always backslash-quoted; this
572 * check is about not losing leading or trailing SP and strings that
573 * follow beginning-of-comment characters (i.e. ';' and '#') by the
574 * configuration parser.
575 */
576 if (value[0] == ' ')
577 quote = "\"";
578 for (i = 0; value[i]; i++)
579 if (value[i] == ';' || value[i] == '#')
580 quote = "\"";
581 if (i && value[i - 1] == ' ')
582 quote = "\"";
583
584 strbuf_addf(&sb, "\t%.*s = %s",
585 length, key + store.baselen + 1, quote);
586
587 for (i = 0; value[i]; i++)
588 switch (value[i]) {
589 case '\n':
590 strbuf_addstr(&sb, "\\n");
591 break;
592 case '\t':
593 strbuf_addstr(&sb, "\\t");
594 break;
595 case '"':
596 case '\\':
597 strbuf_addch(&sb, '\\');
598 default:
599 strbuf_addch(&sb, value[i]);
600 break;
601 }
602 strbuf_addf(&sb, "%s\n", quote);
603
604 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
605 strbuf_release(&sb);
606
607 return success;
608}
609
610static ssize_t find_beginning_of_line(const char* contents, size_t size,
611 size_t offset_, int* found_bracket)
612{
613 size_t equal_offset = size, bracket_offset = size;
614 ssize_t offset;
615
616contline:
617 for (offset = offset_-2; offset > 0
618 && contents[offset] != '\n'; offset--)
619 switch (contents[offset]) {
620 case '=': equal_offset = offset; break;
621 case ']': bracket_offset = offset; break;
622 }
623 if (offset > 0 && contents[offset-1] == '\\') {
624 offset_ = offset;
625 goto contline;
626 }
627 if (bracket_offset < equal_offset) {
628 *found_bracket = 1;
629 offset = bracket_offset+1;
630 } else
631 offset++;
632
633 return offset;
634}
635
636int perf_config_set(const char* key, const char* value)
637{
638 return perf_config_set_multivar(key, value, NULL, 0);
639}
640
641/*
642 * If value==NULL, unset in (remove from) config,
643 * if value_regex!=NULL, disregard key/value pairs where value does not match.
644 * if multi_replace==0, nothing, or only one matching key/value is replaced,
645 * else all matching key/values (regardless how many) are removed,
646 * before the new pair is written.
647 *
648 * Returns 0 on success.
649 *
650 * This function does this:
651 *
652 * - it locks the config file by creating ".perf/config.lock"
653 *
654 * - it then parses the config using store_aux() as validator to find
655 * the position on the key/value pair to replace. If it is to be unset,
656 * it must be found exactly once.
657 *
658 * - the config file is mmap()ed and the part before the match (if any) is
659 * written to the lock file, then the changed part and the rest.
660 *
661 * - the config file is removed and the lock file rename()d to it.
662 *
663 */
664int perf_config_set_multivar(const char* key, const char* value,
665 const char* value_regex, int multi_replace)
666{
667 int i, dot;
668 int fd = -1, in_fd;
669 int ret = 0;
670 char* config_filename;
671 const char* last_dot = strrchr(key, '.');
672
673 if (config_exclusive_filename)
674 config_filename = strdup(config_exclusive_filename);
675 else
676 config_filename = perf_pathdup("config");
677
678 /*
679 * Since "key" actually contains the section name and the real
680 * key name separated by a dot, we have to know where the dot is.
681 */
682
683 if (last_dot == NULL) {
684 error("key does not contain a section: %s", key);
685 ret = 2;
686 goto out_free;
687 }
688 store.baselen = last_dot - key;
689
690 store.multi_replace = multi_replace;
691
692 /*
693 * Validate the key and while at it, lower case it for matching.
694 */
695 store.key = malloc(strlen(key) + 1);
696 dot = 0;
697 for (i = 0; key[i]; i++) {
698 unsigned char c = key[i];
699 if (c == '.')
700 dot = 1;
701 /* Leave the extended basename untouched.. */
702 if (!dot || i > store.baselen) {
703 if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
704 error("invalid key: %s", key);
705 free(store.key);
706 ret = 1;
707 goto out_free;
708 }
709 c = tolower(c);
710 } else if (c == '\n') {
711 error("invalid key (newline): %s", key);
712 free(store.key);
713 ret = 1;
714 goto out_free;
715 }
716 store.key[i] = c;
717 }
718 store.key[i] = 0;
719
720 /*
721 * If .perf/config does not exist yet, write a minimal version.
722 */
723 in_fd = open(config_filename, O_RDONLY);
724 if ( in_fd < 0 ) {
725 free(store.key);
726
727 if ( ENOENT != errno ) {
728 error("opening %s: %s", config_filename,
729 strerror(errno));
730 ret = 3; /* same as "invalid config file" */
731 goto out_free;
732 }
733 /* if nothing to unset, error out */
734 if (value == NULL) {
735 ret = 5;
736 goto out_free;
737 }
738
739 store.key = (char*)key;
740 if (!store_write_section(fd, key) ||
741 !store_write_pair(fd, key, value))
742 goto write_err_out;
743 } else {
744 struct stat st;
745 char* contents;
746 ssize_t contents_sz, copy_begin, copy_end;
747 int i, new_line = 0;
748
749 if (value_regex == NULL)
750 store.value_regex = NULL;
751 else {
752 if (value_regex[0] == '!') {
753 store.do_not_match = 1;
754 value_regex++;
755 } else
756 store.do_not_match = 0;
757
758 store.value_regex = (regex_t*)malloc(sizeof(regex_t));
759 if (regcomp(store.value_regex, value_regex,
760 REG_EXTENDED)) {
761 error("invalid pattern: %s", value_regex);
762 free(store.value_regex);
763 ret = 6;
764 goto out_free;
765 }
766 }
767
768 store.offset[0] = 0;
769 store.state = START;
770 store.seen = 0;
771
772 /*
773 * After this, store.offset will contain the *end* offset
774 * of the last match, or remain at 0 if no match was found.
775 * As a side effect, we make sure to transform only a valid
776 * existing config file.
777 */
778 if (perf_config_from_file(store_aux, config_filename, NULL)) {
779 error("invalid config file %s", config_filename);
780 free(store.key);
781 if (store.value_regex != NULL) {
782 regfree(store.value_regex);
783 free(store.value_regex);
784 }
785 ret = 3;
786 goto out_free;
787 }
788
789 free(store.key);
790 if (store.value_regex != NULL) {
791 regfree(store.value_regex);
792 free(store.value_regex);
793 }
794
795 /* if nothing to unset, or too many matches, error out */
796 if ((store.seen == 0 && value == NULL) ||
797 (store.seen > 1 && multi_replace == 0)) {
798 ret = 5;
799 goto out_free;
800 }
801
802 fstat(in_fd, &st);
803 contents_sz = xsize_t(st.st_size);
804 contents = mmap(NULL, contents_sz, PROT_READ,
805 MAP_PRIVATE, in_fd, 0);
806 close(in_fd);
807
808 if (store.seen == 0)
809 store.seen = 1;
810
811 for (i = 0, copy_begin = 0; i < store.seen; i++) {
812 if (store.offset[i] == 0) {
813 store.offset[i] = copy_end = contents_sz;
814 } else if (store.state != KEY_SEEN) {
815 copy_end = store.offset[i];
816 } else
817 copy_end = find_beginning_of_line(
818 contents, contents_sz,
819 store.offset[i]-2, &new_line);
820
821 if (copy_end > 0 && contents[copy_end-1] != '\n')
822 new_line = 1;
823
824 /* write the first part of the config */
825 if (copy_end > copy_begin) {
826 if (write_in_full(fd, contents + copy_begin,
827 copy_end - copy_begin) <
828 copy_end - copy_begin)
829 goto write_err_out;
830 if (new_line &&
831 write_in_full(fd, "\n", 1) != 1)
832 goto write_err_out;
833 }
834 copy_begin = store.offset[i];
835 }
836
837 /* write the pair (value == NULL means unset) */
838 if (value != NULL) {
839 if (store.state == START) {
840 if (!store_write_section(fd, key))
841 goto write_err_out;
842 }
843 if (!store_write_pair(fd, key, value))
844 goto write_err_out;
845 }
846
847 /* write the rest of the config */
848 if (copy_begin < contents_sz)
849 if (write_in_full(fd, contents + copy_begin,
850 contents_sz - copy_begin) <
851 contents_sz - copy_begin)
852 goto write_err_out;
853
854 munmap(contents, contents_sz);
855 }
856
857 ret = 0;
858
859out_free:
860 free(config_filename);
861 return ret;
862
863write_err_out:
864 goto out_free;
865
866}
867
868/*
869 * Call this to report error for your variable that should not
870 * get a boolean value (i.e. "[my] var" means "true").
871 */
872int config_error_nonbool(const char *var)
873{
874 return error("Missing value for '%s'", var);
875}
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
new file mode 100644
index 000000000000..0b791bd346bc
--- /dev/null
+++ b/tools/perf/util/ctype.c
@@ -0,0 +1,31 @@
1/*
2 * Sane locale-independent, ASCII ctype.
3 *
4 * No surprises, and works with signed and unsigned chars.
5 */
6#include "cache.h"
7
8enum {
9 S = GIT_SPACE,
10 A = GIT_ALPHA,
11 D = GIT_DIGIT,
12 G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */
13 R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */
14 P = GIT_PRINT_EXTRA, /* printable - alpha - digit - glob - regex */
15
16 PS = GIT_SPACE | GIT_PRINT_EXTRA,
17};
18
19unsigned char sane_ctype[256] = {
20/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
21
22 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */
23 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */
24 PS,P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */
25 D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */
26 P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */
27 A, A, A, A, A, A, A, A, A, A, A, G, G, P, R, P, /* 80.. 95 */
28 P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */
29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */
30 /* Nothing in the 128.. range */
31};
diff --git a/tools/perf/util/environment.c b/tools/perf/util/environment.c
new file mode 100644
index 000000000000..275b0ee345f5
--- /dev/null
+++ b/tools/perf/util/environment.c
@@ -0,0 +1,9 @@
1/*
2 * We put all the perf config variables in this same object
3 * file, so that programs can link against the config parser
4 * without having to link against all the rest of perf.
5 */
6#include "cache.h"
7
8const char *pager_program;
9int pager_use_color = 1;
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
new file mode 100644
index 000000000000..34a352867382
--- /dev/null
+++ b/tools/perf/util/exec_cmd.c
@@ -0,0 +1,168 @@
1#include "cache.h"
2#include "exec_cmd.h"
3#include "quote.h"
4
5#include <string.h>
6
7#define MAX_ARGS 32
8
9extern char **environ;
10static const char *argv_exec_path;
11static const char *argv0_path;
12
13const char *system_path(const char *path)
14{
15#ifdef RUNTIME_PREFIX
16 static const char *prefix;
17#else
18 static const char *prefix = PREFIX;
19#endif
20 struct strbuf d = STRBUF_INIT;
21
22 if (is_absolute_path(path))
23 return path;
24
25#ifdef RUNTIME_PREFIX
26 assert(argv0_path);
27 assert(is_absolute_path(argv0_path));
28
29 if (!prefix &&
30 !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) &&
31 !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
32 !(prefix = strip_path_suffix(argv0_path, "perf"))) {
33 prefix = PREFIX;
34 fprintf(stderr, "RUNTIME_PREFIX requested, "
35 "but prefix computation failed. "
36 "Using static fallback '%s'.\n", prefix);
37 }
38#endif
39
40 strbuf_addf(&d, "%s/%s", prefix, path);
41 path = strbuf_detach(&d, NULL);
42 return path;
43}
44
45const char *perf_extract_argv0_path(const char *argv0)
46{
47 const char *slash;
48
49 if (!argv0 || !*argv0)
50 return NULL;
51 slash = argv0 + strlen(argv0);
52
53 while (argv0 <= slash && !is_dir_sep(*slash))
54 slash--;
55
56 if (slash >= argv0) {
57 argv0_path = xstrndup(argv0, slash - argv0);
58 return slash + 1;
59 }
60
61 return argv0;
62}
63
64void perf_set_argv_exec_path(const char *exec_path)
65{
66 argv_exec_path = exec_path;
67 /*
68 * Propagate this setting to external programs.
69 */
70 setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
71}
72
73
74/* Returns the highest-priority, location to look for perf programs. */
75const char *perf_exec_path(void)
76{
77 const char *env;
78
79 if (argv_exec_path)
80 return argv_exec_path;
81
82 env = getenv(EXEC_PATH_ENVIRONMENT);
83 if (env && *env) {
84 return env;
85 }
86
87 return system_path(PERF_EXEC_PATH);
88}
89
90static void add_path(struct strbuf *out, const char *path)
91{
92 if (path && *path) {
93 if (is_absolute_path(path))
94 strbuf_addstr(out, path);
95 else
96 strbuf_addstr(out, make_nonrelative_path(path));
97
98 strbuf_addch(out, PATH_SEP);
99 }
100}
101
102void setup_path(void)
103{
104 const char *old_path = getenv("PATH");
105 struct strbuf new_path = STRBUF_INIT;
106
107 add_path(&new_path, perf_exec_path());
108 add_path(&new_path, argv0_path);
109
110 if (old_path)
111 strbuf_addstr(&new_path, old_path);
112 else
113 strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
114
115 setenv("PATH", new_path.buf, 1);
116
117 strbuf_release(&new_path);
118}
119
120const char **prepare_perf_cmd(const char **argv)
121{
122 int argc;
123 const char **nargv;
124
125 for (argc = 0; argv[argc]; argc++)
126 ; /* just counting */
127 nargv = malloc(sizeof(*nargv) * (argc + 2));
128
129 nargv[0] = "perf";
130 for (argc = 0; argv[argc]; argc++)
131 nargv[argc + 1] = argv[argc];
132 nargv[argc + 1] = NULL;
133 return nargv;
134}
135
136int execv_perf_cmd(const char **argv) {
137 const char **nargv = prepare_perf_cmd(argv);
138
139 /* execvp() can only ever return if it fails */
140 execvp("perf", (char **)nargv);
141
142 free(nargv);
143 return -1;
144}
145
146
147int execl_perf_cmd(const char *cmd,...)
148{
149 int argc;
150 const char *argv[MAX_ARGS + 1];
151 const char *arg;
152 va_list param;
153
154 va_start(param, cmd);
155 argv[0] = cmd;
156 argc = 1;
157 while (argc < MAX_ARGS) {
158 arg = argv[argc++] = va_arg(param, char *);
159 if (!arg)
160 break;
161 }
162 va_end(param);
163 if (MAX_ARGS <= argc)
164 return error("too many args to run %s", cmd);
165
166 argv[argc] = NULL;
167 return execv_perf_cmd(argv);
168}
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
new file mode 100644
index 000000000000..effe25eb1545
--- /dev/null
+++ b/tools/perf/util/exec_cmd.h
@@ -0,0 +1,13 @@
1#ifndef PERF_EXEC_CMD_H
2#define PERF_EXEC_CMD_H
3
4extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path);
6extern const char *perf_exec_path(void);
7extern void setup_path(void);
8extern const char **prepare_perf_cmd(const char **argv);
9extern int execv_perf_cmd(const char **argv); /* NULL terminated */
10extern int execl_perf_cmd(const char *cmd, ...);
11extern const char *system_path(const char *path);
12
13#endif /* PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
new file mode 100755
index 000000000000..f06f6fd148f8
--- /dev/null
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -0,0 +1,24 @@
1#!/bin/sh
2
3echo "/* Automatically generated by $0 */
4struct cmdname_help
5{
6 char name[16];
7 char help[80];
8};
9
10static struct cmdname_help common_cmds[] = {"
11
12sed -n -e 's/^perf-\([^ ]*\)[ ].* common.*/\1/p' command-list.txt |
13sort |
14while read cmd
15do
16 sed -n '
17 /^NAME/,/perf-'"$cmd"'/H
18 ${
19 x
20 s/.*perf-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/
21 p
22 }' "Documentation/perf-$cmd.txt"
23done
24echo "};"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
new file mode 100644
index 000000000000..b92a457ca32e
--- /dev/null
+++ b/tools/perf/util/header.c
@@ -0,0 +1,245 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5
6#include "util.h"
7#include "header.h"
8
9/*
10 *
11 */
12
13struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr)
14{
15 struct perf_header_attr *self = malloc(sizeof(*self));
16
17 if (!self)
18 die("nomem");
19
20 self->attr = *attr;
21 self->ids = 0;
22 self->size = 1;
23 self->id = malloc(sizeof(u64));
24
25 if (!self->id)
26 die("nomem");
27
28 return self;
29}
30
31void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
32{
33 int pos = self->ids;
34
35 self->ids++;
36 if (self->ids > self->size) {
37 self->size *= 2;
38 self->id = realloc(self->id, self->size * sizeof(u64));
39 if (!self->id)
40 die("nomem");
41 }
42 self->id[pos] = id;
43}
44
45/*
46 *
47 */
48
49struct perf_header *perf_header__new(void)
50{
51 struct perf_header *self = malloc(sizeof(*self));
52
53 if (!self)
54 die("nomem");
55
56 self->frozen = 0;
57
58 self->attrs = 0;
59 self->size = 1;
60 self->attr = malloc(sizeof(void *));
61
62 if (!self->attr)
63 die("nomem");
64
65 self->data_offset = 0;
66 self->data_size = 0;
67
68 return self;
69}
70
71void perf_header__add_attr(struct perf_header *self,
72 struct perf_header_attr *attr)
73{
74 int pos = self->attrs;
75
76 if (self->frozen)
77 die("frozen");
78
79 self->attrs++;
80 if (self->attrs > self->size) {
81 self->size *= 2;
82 self->attr = realloc(self->attr, self->size * sizeof(void *));
83 if (!self->attr)
84 die("nomem");
85 }
86 self->attr[pos] = attr;
87}
88
89static const char *__perf_magic = "PERFFILE";
90
91#define PERF_MAGIC (*(u64 *)__perf_magic)
92
93struct perf_file_section {
94 u64 offset;
95 u64 size;
96};
97
98struct perf_file_attr {
99 struct perf_counter_attr attr;
100 struct perf_file_section ids;
101};
102
103struct perf_file_header {
104 u64 magic;
105 u64 size;
106 u64 attr_size;
107 struct perf_file_section attrs;
108 struct perf_file_section data;
109};
110
111static void do_write(int fd, void *buf, size_t size)
112{
113 while (size) {
114 int ret = write(fd, buf, size);
115
116 if (ret < 0)
117 die("failed to write");
118
119 size -= ret;
120 buf += ret;
121 }
122}
123
124void perf_header__write(struct perf_header *self, int fd)
125{
126 struct perf_file_header f_header;
127 struct perf_file_attr f_attr;
128 struct perf_header_attr *attr;
129 int i;
130
131 lseek(fd, sizeof(f_header), SEEK_SET);
132
133
134 for (i = 0; i < self->attrs; i++) {
135 attr = self->attr[i];
136
137 attr->id_offset = lseek(fd, 0, SEEK_CUR);
138 do_write(fd, attr->id, attr->ids * sizeof(u64));
139 }
140
141
142 self->attr_offset = lseek(fd, 0, SEEK_CUR);
143
144 for (i = 0; i < self->attrs; i++) {
145 attr = self->attr[i];
146
147 f_attr = (struct perf_file_attr){
148 .attr = attr->attr,
149 .ids = {
150 .offset = attr->id_offset,
151 .size = attr->ids * sizeof(u64),
152 }
153 };
154 do_write(fd, &f_attr, sizeof(f_attr));
155 }
156
157
158 self->data_offset = lseek(fd, 0, SEEK_CUR);
159
160 f_header = (struct perf_file_header){
161 .magic = PERF_MAGIC,
162 .size = sizeof(f_header),
163 .attr_size = sizeof(f_attr),
164 .attrs = {
165 .offset = self->attr_offset,
166 .size = self->attrs * sizeof(f_attr),
167 },
168 .data = {
169 .offset = self->data_offset,
170 .size = self->data_size,
171 },
172 };
173
174 lseek(fd, 0, SEEK_SET);
175 do_write(fd, &f_header, sizeof(f_header));
176 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
177
178 self->frozen = 1;
179}
180
181static void do_read(int fd, void *buf, size_t size)
182{
183 while (size) {
184 int ret = read(fd, buf, size);
185
186 if (ret < 0)
187 die("failed to read");
188 if (ret == 0)
189 die("failed to read: missing data");
190
191 size -= ret;
192 buf += ret;
193 }
194}
195
196struct perf_header *perf_header__read(int fd)
197{
198 struct perf_header *self = perf_header__new();
199 struct perf_file_header f_header;
200 struct perf_file_attr f_attr;
201 u64 f_id;
202
203 int nr_attrs, nr_ids, i, j;
204
205 lseek(fd, 0, SEEK_SET);
206 do_read(fd, &f_header, sizeof(f_header));
207
208 if (f_header.magic != PERF_MAGIC ||
209 f_header.size != sizeof(f_header) ||
210 f_header.attr_size != sizeof(f_attr))
211 die("incompatible file format");
212
213 nr_attrs = f_header.attrs.size / sizeof(f_attr);
214 lseek(fd, f_header.attrs.offset, SEEK_SET);
215
216 for (i = 0; i < nr_attrs; i++) {
217 struct perf_header_attr *attr;
218 off_t tmp;
219
220 do_read(fd, &f_attr, sizeof(f_attr));
221 tmp = lseek(fd, 0, SEEK_CUR);
222
223 attr = perf_header_attr__new(&f_attr.attr);
224
225 nr_ids = f_attr.ids.size / sizeof(u64);
226 lseek(fd, f_attr.ids.offset, SEEK_SET);
227
228 for (j = 0; j < nr_ids; j++) {
229 do_read(fd, &f_id, sizeof(f_id));
230
231 perf_header_attr__add_id(attr, f_id);
232 }
233 perf_header__add_attr(self, attr);
234 lseek(fd, tmp, SEEK_SET);
235 }
236
237 self->data_offset = f_header.data.offset;
238 self->data_size = f_header.data.size;
239
240 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
241
242 self->frozen = 1;
243
244 return self;
245}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
new file mode 100644
index 000000000000..bf280449fcfd
--- /dev/null
+++ b/tools/perf/util/header.h
@@ -0,0 +1,37 @@
1#ifndef _PERF_HEADER_H
2#define _PERF_HEADER_H
3
4#include "../../../include/linux/perf_counter.h"
5#include <sys/types.h>
6#include "types.h"
7
8struct perf_header_attr {
9 struct perf_counter_attr attr;
10 int ids, size;
11 u64 *id;
12 off_t id_offset;
13};
14
15struct perf_header {
16 int frozen;
17 int attrs, size;
18 struct perf_header_attr **attr;
19 s64 attr_offset;
20 u64 data_offset;
21 u64 data_size;
22};
23
24struct perf_header *perf_header__read(int fd);
25void perf_header__write(struct perf_header *self, int fd);
26
27void perf_header__add_attr(struct perf_header *self,
28 struct perf_header_attr *attr);
29
30struct perf_header_attr *
31perf_header_attr__new(struct perf_counter_attr *attr);
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
33
34
35struct perf_header *perf_header__new(void);
36
37#endif /* _PERF_HEADER_H */
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
new file mode 100644
index 000000000000..fbb00978b2e2
--- /dev/null
+++ b/tools/perf/util/help.c
@@ -0,0 +1,356 @@
1#include "cache.h"
2#include "../builtin.h"
3#include "exec_cmd.h"
4#include "levenshtein.h"
5#include "help.h"
6
7/* most GUI terminals set COLUMNS (although some don't export it) */
8static int term_columns(void)
9{
10 char *col_string = getenv("COLUMNS");
11 int n_cols;
12
13 if (col_string && (n_cols = atoi(col_string)) > 0)
14 return n_cols;
15
16#ifdef TIOCGWINSZ
17 {
18 struct winsize ws;
19 if (!ioctl(1, TIOCGWINSZ, &ws)) {
20 if (ws.ws_col)
21 return ws.ws_col;
22 }
23 }
24#endif
25
26 return 80;
27}
28
29void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
30{
31 struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
32
33 ent->len = len;
34 memcpy(ent->name, name, len);
35 ent->name[len] = 0;
36
37 ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);
38 cmds->names[cmds->cnt++] = ent;
39}
40
41static void clean_cmdnames(struct cmdnames *cmds)
42{
43 unsigned int i;
44
45 for (i = 0; i < cmds->cnt; ++i)
46 free(cmds->names[i]);
47 free(cmds->names);
48 cmds->cnt = 0;
49 cmds->alloc = 0;
50}
51
52static int cmdname_compare(const void *a_, const void *b_)
53{
54 struct cmdname *a = *(struct cmdname **)a_;
55 struct cmdname *b = *(struct cmdname **)b_;
56 return strcmp(a->name, b->name);
57}
58
59static void uniq(struct cmdnames *cmds)
60{
61 unsigned int i, j;
62
63 if (!cmds->cnt)
64 return;
65
66 for (i = j = 1; i < cmds->cnt; i++)
67 if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
68 cmds->names[j++] = cmds->names[i];
69
70 cmds->cnt = j;
71}
72
73void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
74{
75 size_t ci, cj, ei;
76 int cmp;
77
78 ci = cj = ei = 0;
79 while (ci < cmds->cnt && ei < excludes->cnt) {
80 cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
81 if (cmp < 0)
82 cmds->names[cj++] = cmds->names[ci++];
83 else if (cmp == 0)
84 ci++, ei++;
85 else if (cmp > 0)
86 ei++;
87 }
88
89 while (ci < cmds->cnt)
90 cmds->names[cj++] = cmds->names[ci++];
91
92 cmds->cnt = cj;
93}
94
95static void pretty_print_string_list(struct cmdnames *cmds, int longest)
96{
97 int cols = 1, rows;
98 int space = longest + 1; /* min 1 SP between words */
99 int max_cols = term_columns() - 1; /* don't print *on* the edge */
100 int i, j;
101
102 if (space < max_cols)
103 cols = max_cols / space;
104 rows = (cmds->cnt + cols - 1) / cols;
105
106 for (i = 0; i < rows; i++) {
107 printf(" ");
108
109 for (j = 0; j < cols; j++) {
110 unsigned int n = j * rows + i;
111 unsigned int size = space;
112
113 if (n >= cmds->cnt)
114 break;
115 if (j == cols-1 || n + rows >= cmds->cnt)
116 size = 1;
117 printf("%-*s", size, cmds->names[n]->name);
118 }
119 putchar('\n');
120 }
121}
122
123static int is_executable(const char *name)
124{
125 struct stat st;
126
127 if (stat(name, &st) || /* stat, not lstat */
128 !S_ISREG(st.st_mode))
129 return 0;
130
131 return st.st_mode & S_IXUSR;
132}
133
134static void list_commands_in_dir(struct cmdnames *cmds,
135 const char *path,
136 const char *prefix)
137{
138 int prefix_len;
139 DIR *dir = opendir(path);
140 struct dirent *de;
141 struct strbuf buf = STRBUF_INIT;
142 int len;
143
144 if (!dir)
145 return;
146 if (!prefix)
147 prefix = "perf-";
148 prefix_len = strlen(prefix);
149
150 strbuf_addf(&buf, "%s/", path);
151 len = buf.len;
152
153 while ((de = readdir(dir)) != NULL) {
154 int entlen;
155
156 if (prefixcmp(de->d_name, prefix))
157 continue;
158
159 strbuf_setlen(&buf, len);
160 strbuf_addstr(&buf, de->d_name);
161 if (!is_executable(buf.buf))
162 continue;
163
164 entlen = strlen(de->d_name) - prefix_len;
165 if (has_extension(de->d_name, ".exe"))
166 entlen -= 4;
167
168 add_cmdname(cmds, de->d_name + prefix_len, entlen);
169 }
170 closedir(dir);
171 strbuf_release(&buf);
172}
173
174void load_command_list(const char *prefix,
175 struct cmdnames *main_cmds,
176 struct cmdnames *other_cmds)
177{
178 const char *env_path = getenv("PATH");
179 const char *exec_path = perf_exec_path();
180
181 if (exec_path) {
182 list_commands_in_dir(main_cmds, exec_path, prefix);
183 qsort(main_cmds->names, main_cmds->cnt,
184 sizeof(*main_cmds->names), cmdname_compare);
185 uniq(main_cmds);
186 }
187
188 if (env_path) {
189 char *paths, *path, *colon;
190 path = paths = strdup(env_path);
191 while (1) {
192 if ((colon = strchr(path, PATH_SEP)))
193 *colon = 0;
194 if (!exec_path || strcmp(path, exec_path))
195 list_commands_in_dir(other_cmds, path, prefix);
196
197 if (!colon)
198 break;
199 path = colon + 1;
200 }
201 free(paths);
202
203 qsort(other_cmds->names, other_cmds->cnt,
204 sizeof(*other_cmds->names), cmdname_compare);
205 uniq(other_cmds);
206 }
207 exclude_cmds(other_cmds, main_cmds);
208}
209
210void list_commands(const char *title, struct cmdnames *main_cmds,
211 struct cmdnames *other_cmds)
212{
213 unsigned int i, longest = 0;
214
215 for (i = 0; i < main_cmds->cnt; i++)
216 if (longest < main_cmds->names[i]->len)
217 longest = main_cmds->names[i]->len;
218 for (i = 0; i < other_cmds->cnt; i++)
219 if (longest < other_cmds->names[i]->len)
220 longest = other_cmds->names[i]->len;
221
222 if (main_cmds->cnt) {
223 const char *exec_path = perf_exec_path();
224 printf("available %s in '%s'\n", title, exec_path);
225 printf("----------------");
226 mput_char('-', strlen(title) + strlen(exec_path));
227 putchar('\n');
228 pretty_print_string_list(main_cmds, longest);
229 putchar('\n');
230 }
231
232 if (other_cmds->cnt) {
233 printf("%s available from elsewhere on your $PATH\n", title);
234 printf("---------------------------------------");
235 mput_char('-', strlen(title));
236 putchar('\n');
237 pretty_print_string_list(other_cmds, longest);
238 putchar('\n');
239 }
240}
241
242int is_in_cmdlist(struct cmdnames *c, const char *s)
243{
244 unsigned int i;
245
246 for (i = 0; i < c->cnt; i++)
247 if (!strcmp(s, c->names[i]->name))
248 return 1;
249 return 0;
250}
251
252static int autocorrect;
253static struct cmdnames aliases;
254
255static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
256{
257 if (!strcmp(var, "help.autocorrect"))
258 autocorrect = perf_config_int(var,value);
259 /* Also use aliases for command lookup */
260 if (!prefixcmp(var, "alias."))
261 add_cmdname(&aliases, var + 6, strlen(var + 6));
262
263 return perf_default_config(var, value, cb);
264}
265
266static int levenshtein_compare(const void *p1, const void *p2)
267{
268 const struct cmdname *const *c1 = p1, *const *c2 = p2;
269 const char *s1 = (*c1)->name, *s2 = (*c2)->name;
270 int l1 = (*c1)->len;
271 int l2 = (*c2)->len;
272 return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
273}
274
275static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
276{
277 unsigned int i;
278
279 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
280
281 for (i = 0; i < old->cnt; i++)
282 cmds->names[cmds->cnt++] = old->names[i];
283 free(old->names);
284 old->cnt = 0;
285 old->names = NULL;
286}
287
288const char *help_unknown_cmd(const char *cmd)
289{
290 unsigned int i, n = 0, best_similarity = 0;
291 struct cmdnames main_cmds, other_cmds;
292
293 memset(&main_cmds, 0, sizeof(main_cmds));
294 memset(&other_cmds, 0, sizeof(main_cmds));
295 memset(&aliases, 0, sizeof(aliases));
296
297 perf_config(perf_unknown_cmd_config, NULL);
298
299 load_command_list("perf-", &main_cmds, &other_cmds);
300
301 add_cmd_list(&main_cmds, &aliases);
302 add_cmd_list(&main_cmds, &other_cmds);
303 qsort(main_cmds.names, main_cmds.cnt,
304 sizeof(main_cmds.names), cmdname_compare);
305 uniq(&main_cmds);
306
307 if (main_cmds.cnt) {
308 /* This reuses cmdname->len for similarity index */
309 for (i = 0; i < main_cmds.cnt; ++i)
310 main_cmds.names[i]->len =
311 levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
312
313 qsort(main_cmds.names, main_cmds.cnt,
314 sizeof(*main_cmds.names), levenshtein_compare);
315
316 best_similarity = main_cmds.names[0]->len;
317 n = 1;
318 while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
319 ++n;
320 }
321
322 if (autocorrect && n == 1) {
323 const char *assumed = main_cmds.names[0]->name;
324
325 main_cmds.names[0] = NULL;
326 clean_cmdnames(&main_cmds);
327 fprintf(stderr, "WARNING: You called a Git program named '%s', "
328 "which does not exist.\n"
329 "Continuing under the assumption that you meant '%s'\n",
330 cmd, assumed);
331 if (autocorrect > 0) {
332 fprintf(stderr, "in %0.1f seconds automatically...\n",
333 (float)autocorrect/10.0);
334 poll(NULL, 0, autocorrect * 100);
335 }
336 return assumed;
337 }
338
339 fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
340
341 if (main_cmds.cnt && best_similarity < 6) {
342 fprintf(stderr, "\nDid you mean %s?\n",
343 n < 2 ? "this": "one of these");
344
345 for (i = 0; i < n; i++)
346 fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
347 }
348
349 exit(1);
350}
351
352int cmd_version(int argc __used, const char **argv __used, const char *prefix __used)
353{
354 printf("perf version %s\n", perf_version_string);
355 return 0;
356}
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
new file mode 100644
index 000000000000..7128783637b4
--- /dev/null
+++ b/tools/perf/util/help.h
@@ -0,0 +1,29 @@
1#ifndef HELP_H
2#define HELP_H
3
4struct cmdnames {
5 size_t alloc;
6 size_t cnt;
7 struct cmdname {
8 size_t len; /* also used for similarity index in help.c */
9 char name[FLEX_ARRAY];
10 } **names;
11};
12
13static inline void mput_char(char c, unsigned int num)
14{
15 while(num--)
16 putchar(c);
17}
18
19void load_command_list(const char *prefix,
20 struct cmdnames *main_cmds,
21 struct cmdnames *other_cmds);
22void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
23/* Here we require that excludes is a sorted list. */
24void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
25int is_in_cmdlist(struct cmdnames *c, const char *s);
26void list_commands(const char *title, struct cmdnames *main_cmds,
27 struct cmdnames *other_cmds);
28
29#endif /* HELP_H */
diff --git a/tools/perf/util/include/asm/system.h b/tools/perf/util/include/asm/system.h
new file mode 100644
index 000000000000..710cecca972d
--- /dev/null
+++ b/tools/perf/util/include/asm/system.h
@@ -0,0 +1 @@
/* Empty */
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
new file mode 100644
index 000000000000..a6b87390cb52
--- /dev/null
+++ b/tools/perf/util/include/linux/kernel.h
@@ -0,0 +1,29 @@
1#ifndef PERF_LINUX_KERNEL_H_
2#define PERF_LINUX_KERNEL_H_
3
4#ifndef offsetof
5#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
6#endif
7
8#ifndef container_of
9/**
10 * container_of - cast a member of a structure out to the containing structure
11 * @ptr: the pointer to the member.
12 * @type: the type of the container struct this is embedded in.
13 * @member: the name of the member within the struct.
14 *
15 */
16#define container_of(ptr, type, member) ({ \
17 const typeof(((type *)0)->member) * __mptr = (ptr); \
18 (type *)((char *)__mptr - offsetof(type, member)); })
19#endif
20
21#ifndef max
22#define max(x, y) ({ \
23 typeof(x) _max1 = (x); \
24 typeof(y) _max2 = (y); \
25 (void) (&_max1 == &_max2); \
26 _max1 > _max2 ? _max1 : _max2; })
27#endif
28
29#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
new file mode 100644
index 000000000000..dbe4b814382a
--- /dev/null
+++ b/tools/perf/util/include/linux/list.h
@@ -0,0 +1,18 @@
1#include "../../../../include/linux/list.h"
2
3#ifndef PERF_LIST_H
4#define PERF_LIST_H
5/**
6 * list_del_range - deletes range of entries from list.
7 * @begin: first element in the range to delete from the list.
8 * @end: last element in the range to delete from the list.
9 * Note: list_empty on the range of entries does not return true after this,
10 * the entries is in an undefined state.
11 */
12static inline void list_del_range(struct list_head *begin,
13 struct list_head *end)
14{
15 begin->prev->next = end->next;
16 end->next->prev = begin->prev;
17}
18#endif
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/module.h
new file mode 100644
index 000000000000..b43e2dc21e04
--- /dev/null
+++ b/tools/perf/util/include/linux/module.h
@@ -0,0 +1,6 @@
1#ifndef PERF_LINUX_MODULE_H
2#define PERF_LINUX_MODULE_H
3
4#define EXPORT_SYMBOL(name)
5
6#endif
diff --git a/tools/perf/util/include/linux/poison.h b/tools/perf/util/include/linux/poison.h
new file mode 100644
index 000000000000..fef6dbc9ce13
--- /dev/null
+++ b/tools/perf/util/include/linux/poison.h
@@ -0,0 +1 @@
#include "../../../../include/linux/poison.h"
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
new file mode 100644
index 000000000000..7841e485d8c3
--- /dev/null
+++ b/tools/perf/util/include/linux/prefetch.h
@@ -0,0 +1,6 @@
1#ifndef PERF_LINUX_PREFETCH_H
2#define PERF_LINUX_PREFETCH_H
3
4static inline void prefetch(void *a __attribute__((unused))) { }
5
6#endif
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
new file mode 100644
index 000000000000..7a243a143037
--- /dev/null
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -0,0 +1 @@
#include "../../../../include/linux/rbtree.h"
diff --git a/tools/perf/util/levenshtein.c b/tools/perf/util/levenshtein.c
new file mode 100644
index 000000000000..e521d1516df6
--- /dev/null
+++ b/tools/perf/util/levenshtein.c
@@ -0,0 +1,84 @@
1#include "cache.h"
2#include "levenshtein.h"
3
4/*
5 * This function implements the Damerau-Levenshtein algorithm to
6 * calculate a distance between strings.
7 *
8 * Basically, it says how many letters need to be swapped, substituted,
9 * deleted from, or added to string1, at least, to get string2.
10 *
11 * The idea is to build a distance matrix for the substrings of both
12 * strings. To avoid a large space complexity, only the last three rows
13 * are kept in memory (if swaps had the same or higher cost as one deletion
14 * plus one insertion, only two rows would be needed).
15 *
16 * At any stage, "i + 1" denotes the length of the current substring of
17 * string1 that the distance is calculated for.
18 *
19 * row2 holds the current row, row1 the previous row (i.e. for the substring
20 * of string1 of length "i"), and row0 the row before that.
21 *
22 * In other words, at the start of the big loop, row2[j + 1] contains the
23 * Damerau-Levenshtein distance between the substring of string1 of length
24 * "i" and the substring of string2 of length "j + 1".
25 *
26 * All the big loop does is determine the partial minimum-cost paths.
27 *
28 * It does so by calculating the costs of the path ending in characters
29 * i (in string1) and j (in string2), respectively, given that the last
30 * operation is a substition, a swap, a deletion, or an insertion.
31 *
32 * This implementation allows the costs to be weighted:
33 *
34 * - w (as in "sWap")
35 * - s (as in "Substitution")
36 * - a (for insertion, AKA "Add")
37 * - d (as in "Deletion")
38 *
39 * Note that this algorithm calculates a distance _iff_ d == a.
40 */
41int levenshtein(const char *string1, const char *string2,
42 int w, int s, int a, int d)
43{
44 int len1 = strlen(string1), len2 = strlen(string2);
45 int *row0 = malloc(sizeof(int) * (len2 + 1));
46 int *row1 = malloc(sizeof(int) * (len2 + 1));
47 int *row2 = malloc(sizeof(int) * (len2 + 1));
48 int i, j;
49
50 for (j = 0; j <= len2; j++)
51 row1[j] = j * a;
52 for (i = 0; i < len1; i++) {
53 int *dummy;
54
55 row2[0] = (i + 1) * d;
56 for (j = 0; j < len2; j++) {
57 /* substitution */
58 row2[j + 1] = row1[j] + s * (string1[i] != string2[j]);
59 /* swap */
60 if (i > 0 && j > 0 && string1[i - 1] == string2[j] &&
61 string1[i] == string2[j - 1] &&
62 row2[j + 1] > row0[j - 1] + w)
63 row2[j + 1] = row0[j - 1] + w;
64 /* deletion */
65 if (row2[j + 1] > row1[j + 1] + d)
66 row2[j + 1] = row1[j + 1] + d;
67 /* insertion */
68 if (row2[j + 1] > row2[j] + a)
69 row2[j + 1] = row2[j] + a;
70 }
71
72 dummy = row0;
73 row0 = row1;
74 row1 = row2;
75 row2 = dummy;
76 }
77
78 i = row1[len2];
79 free(row0);
80 free(row1);
81 free(row2);
82
83 return i;
84}
diff --git a/tools/perf/util/levenshtein.h b/tools/perf/util/levenshtein.h
new file mode 100644
index 000000000000..0173abeef52c
--- /dev/null
+++ b/tools/perf/util/levenshtein.h
@@ -0,0 +1,8 @@
1#ifndef LEVENSHTEIN_H
2#define LEVENSHTEIN_H
3
4int levenshtein(const char *string1, const char *string2,
5 int swap_penalty, int substition_penalty,
6 int insertion_penalty, int deletion_penalty);
7
8#endif
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
new file mode 100644
index 000000000000..ddabe925d65d
--- /dev/null
+++ b/tools/perf/util/module.c
@@ -0,0 +1,509 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <gelf.h>
8#include <elf.h>
9#include <dirent.h>
10#include <sys/utsname.h>
11
12static unsigned int crc32(const char *p, unsigned int len)
13{
14 int i;
15 unsigned int crc = 0;
16
17 while (len--) {
18 crc ^= *p++;
19 for (i = 0; i < 8; i++)
20 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
21 }
22 return crc;
23}
24
25/* module section methods */
26
27struct sec_dso *sec_dso__new_dso(const char *name)
28{
29 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
30
31 if (self != NULL) {
32 strcpy(self->name, name);
33 self->secs = RB_ROOT;
34 self->find_section = sec_dso__find_section;
35 }
36
37 return self;
38}
39
40static void sec_dso__delete_section(struct section *self)
41{
42 free(((void *)self));
43}
44
45void sec_dso__delete_sections(struct sec_dso *self)
46{
47 struct section *pos;
48 struct rb_node *next = rb_first(&self->secs);
49
50 while (next) {
51 pos = rb_entry(next, struct section, rb_node);
52 next = rb_next(&pos->rb_node);
53 rb_erase(&pos->rb_node, &self->secs);
54 sec_dso__delete_section(pos);
55 }
56}
57
58void sec_dso__delete_self(struct sec_dso *self)
59{
60 sec_dso__delete_sections(self);
61 free(self);
62}
63
64static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
65{
66 struct rb_node **p = &self->secs.rb_node;
67 struct rb_node *parent = NULL;
68 const u64 hash = sec->hash;
69 struct section *s;
70
71 while (*p != NULL) {
72 parent = *p;
73 s = rb_entry(parent, struct section, rb_node);
74 if (hash < s->hash)
75 p = &(*p)->rb_left;
76 else
77 p = &(*p)->rb_right;
78 }
79 rb_link_node(&sec->rb_node, parent, p);
80 rb_insert_color(&sec->rb_node, &self->secs);
81}
82
83struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
84{
85 struct rb_node *n;
86 u64 hash;
87 int len;
88
89 if (self == NULL)
90 return NULL;
91
92 len = strlen(name);
93 hash = crc32(name, len);
94
95 n = self->secs.rb_node;
96
97 while (n) {
98 struct section *s = rb_entry(n, struct section, rb_node);
99
100 if (hash < s->hash)
101 n = n->rb_left;
102 else if (hash > s->hash)
103 n = n->rb_right;
104 else {
105 if (!strcmp(name, s->name))
106 return s;
107 else
108 n = rb_next(&s->rb_node);
109 }
110 }
111
112 return NULL;
113}
114
115static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
116{
117 return fprintf(fp, "name:%s vma:%llx path:%s\n",
118 self->name, self->vma, self->path);
119}
120
121size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
122{
123 size_t ret = fprintf(fp, "dso: %s\n", self->name);
124
125 struct rb_node *nd;
126 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
127 struct section *pos = rb_entry(nd, struct section, rb_node);
128 ret += sec_dso__fprintf_section(pos, fp);
129 }
130
131 return ret;
132}
133
134static struct section *section__new(const char *name, const char *path)
135{
136 struct section *self = calloc(1, sizeof(*self));
137
138 if (!self)
139 goto out_failure;
140
141 self->name = calloc(1, strlen(name) + 1);
142 if (!self->name)
143 goto out_failure;
144
145 self->path = calloc(1, strlen(path) + 1);
146 if (!self->path)
147 goto out_failure;
148
149 strcpy(self->name, name);
150 strcpy(self->path, path);
151 self->hash = crc32(self->name, strlen(name));
152
153 return self;
154
155out_failure:
156 if (self) {
157 if (self->name)
158 free(self->name);
159 if (self->path)
160 free(self->path);
161 free(self);
162 }
163
164 return NULL;
165}
166
167/* module methods */
168
169struct mod_dso *mod_dso__new_dso(const char *name)
170{
171 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
172
173 if (self != NULL) {
174 strcpy(self->name, name);
175 self->mods = RB_ROOT;
176 self->find_module = mod_dso__find_module;
177 }
178
179 return self;
180}
181
182static void mod_dso__delete_module(struct module *self)
183{
184 free(((void *)self));
185}
186
187void mod_dso__delete_modules(struct mod_dso *self)
188{
189 struct module *pos;
190 struct rb_node *next = rb_first(&self->mods);
191
192 while (next) {
193 pos = rb_entry(next, struct module, rb_node);
194 next = rb_next(&pos->rb_node);
195 rb_erase(&pos->rb_node, &self->mods);
196 mod_dso__delete_module(pos);
197 }
198}
199
200void mod_dso__delete_self(struct mod_dso *self)
201{
202 mod_dso__delete_modules(self);
203 free(self);
204}
205
206static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
207{
208 struct rb_node **p = &self->mods.rb_node;
209 struct rb_node *parent = NULL;
210 const u64 hash = mod->hash;
211 struct module *m;
212
213 while (*p != NULL) {
214 parent = *p;
215 m = rb_entry(parent, struct module, rb_node);
216 if (hash < m->hash)
217 p = &(*p)->rb_left;
218 else
219 p = &(*p)->rb_right;
220 }
221 rb_link_node(&mod->rb_node, parent, p);
222 rb_insert_color(&mod->rb_node, &self->mods);
223}
224
225struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
226{
227 struct rb_node *n;
228 u64 hash;
229 int len;
230
231 if (self == NULL)
232 return NULL;
233
234 len = strlen(name);
235 hash = crc32(name, len);
236
237 n = self->mods.rb_node;
238
239 while (n) {
240 struct module *m = rb_entry(n, struct module, rb_node);
241
242 if (hash < m->hash)
243 n = n->rb_left;
244 else if (hash > m->hash)
245 n = n->rb_right;
246 else {
247 if (!strcmp(name, m->name))
248 return m;
249 else
250 n = rb_next(&m->rb_node);
251 }
252 }
253
254 return NULL;
255}
256
257static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
258{
259 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
260}
261
262size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
263{
264 struct rb_node *nd;
265 size_t ret;
266
267 ret = fprintf(fp, "dso: %s\n", self->name);
268
269 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
270 struct module *pos = rb_entry(nd, struct module, rb_node);
271
272 ret += mod_dso__fprintf_module(pos, fp);
273 }
274
275 return ret;
276}
277
278static struct module *module__new(const char *name, const char *path)
279{
280 struct module *self = calloc(1, sizeof(*self));
281
282 if (!self)
283 goto out_failure;
284
285 self->name = calloc(1, strlen(name) + 1);
286 if (!self->name)
287 goto out_failure;
288
289 self->path = calloc(1, strlen(path) + 1);
290 if (!self->path)
291 goto out_failure;
292
293 strcpy(self->name, name);
294 strcpy(self->path, path);
295 self->hash = crc32(self->name, strlen(name));
296
297 return self;
298
299out_failure:
300 if (self) {
301 if (self->name)
302 free(self->name);
303 if (self->path)
304 free(self->path);
305 free(self);
306 }
307
308 return NULL;
309}
310
311static int mod_dso__load_sections(struct module *mod)
312{
313 int count = 0, path_len;
314 struct dirent *entry;
315 char *line = NULL;
316 char *dir_path;
317 DIR *dir;
318 size_t n;
319
320 path_len = strlen("/sys/module/");
321 path_len += strlen(mod->name);
322 path_len += strlen("/sections/");
323
324 dir_path = calloc(1, path_len + 1);
325 if (dir_path == NULL)
326 goto out_failure;
327
328 strcat(dir_path, "/sys/module/");
329 strcat(dir_path, mod->name);
330 strcat(dir_path, "/sections/");
331
332 dir = opendir(dir_path);
333 if (dir == NULL)
334 goto out_free;
335
336 while ((entry = readdir(dir))) {
337 struct section *section;
338 char *path, *vma;
339 int line_len;
340 FILE *file;
341
342 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
343 continue;
344
345 path = calloc(1, path_len + strlen(entry->d_name) + 1);
346 if (path == NULL)
347 break;
348 strcat(path, dir_path);
349 strcat(path, entry->d_name);
350
351 file = fopen(path, "r");
352 if (file == NULL) {
353 free(path);
354 break;
355 }
356
357 line_len = getline(&line, &n, file);
358 if (line_len < 0) {
359 free(path);
360 fclose(file);
361 break;
362 }
363
364 if (!line) {
365 free(path);
366 fclose(file);
367 break;
368 }
369
370 line[--line_len] = '\0'; /* \n */
371
372 vma = strstr(line, "0x");
373 if (!vma) {
374 free(path);
375 fclose(file);
376 break;
377 }
378 vma += 2;
379
380 section = section__new(entry->d_name, path);
381 if (!section) {
382 fprintf(stderr, "load_sections: allocation error\n");
383 free(path);
384 fclose(file);
385 break;
386 }
387
388 hex2u64(vma, &section->vma);
389 sec_dso__insert_section(mod->sections, section);
390
391 free(path);
392 fclose(file);
393 count++;
394 }
395
396 closedir(dir);
397 free(line);
398 free(dir_path);
399
400 return count;
401
402out_free:
403 free(dir_path);
404
405out_failure:
406 return count;
407}
408
409static int mod_dso__load_module_paths(struct mod_dso *self)
410{
411 struct utsname uts;
412 int count = 0, len;
413 char *line = NULL;
414 FILE *file;
415 char *path;
416 size_t n;
417
418 if (uname(&uts) < 0)
419 goto out_failure;
420
421 len = strlen("/lib/modules/");
422 len += strlen(uts.release);
423 len += strlen("/modules.dep");
424
425 path = calloc(1, len);
426 if (path == NULL)
427 goto out_failure;
428
429 strcat(path, "/lib/modules/");
430 strcat(path, uts.release);
431 strcat(path, "/modules.dep");
432
433 file = fopen(path, "r");
434 free(path);
435 if (file == NULL)
436 goto out_failure;
437
438 while (!feof(file)) {
439 char *path, *name, *tmp;
440 struct module *module;
441 int line_len, len;
442
443 line_len = getline(&line, &n, file);
444 if (line_len < 0)
445 break;
446
447 if (!line)
448 goto out_failure;
449
450 line[--line_len] = '\0'; /* \n */
451
452 path = strtok(line, ":");
453 if (!path)
454 goto out_failure;
455
456 name = strdup(path);
457 name = strtok(name, "/");
458
459 tmp = name;
460
461 while (tmp) {
462 tmp = strtok(NULL, "/");
463 if (tmp)
464 name = tmp;
465 }
466 name = strsep(&name, ".");
467
468 /* Quirk: replace '-' with '_' in sound modules */
469 for (len = strlen(name); len; len--) {
470 if (*(name+len) == '-')
471 *(name+len) = '_';
472 }
473
474 module = module__new(name, path);
475 if (!module) {
476 fprintf(stderr, "load_module_paths: allocation error\n");
477 goto out_failure;
478 }
479 mod_dso__insert_module(self, module);
480
481 module->sections = sec_dso__new_dso("sections");
482 if (!module->sections) {
483 fprintf(stderr, "load_module_paths: allocation error\n");
484 goto out_failure;
485 }
486
487 module->active = mod_dso__load_sections(module);
488
489 if (module->active > 0)
490 count++;
491 }
492
493 free(line);
494 fclose(file);
495
496 return count;
497
498out_failure:
499 return -1;
500}
501
502int mod_dso__load_modules(struct mod_dso *dso)
503{
504 int err;
505
506 err = mod_dso__load_module_paths(dso);
507
508 return err;
509}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
new file mode 100644
index 000000000000..8a592ef641ca
--- /dev/null
+++ b/tools/perf/util/module.h
@@ -0,0 +1,53 @@
1#ifndef _PERF_MODULE_
2#define _PERF_MODULE_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8
9struct section {
10 struct rb_node rb_node;
11 u64 hash;
12 u64 vma;
13 char *name;
14 char *path;
15};
16
17struct sec_dso {
18 struct list_head node;
19 struct rb_root secs;
20 struct section *(*find_section)(struct sec_dso *, const char *name);
21 char name[0];
22};
23
24struct module {
25 struct rb_node rb_node;
26 u64 hash;
27 char *name;
28 char *path;
29 struct sec_dso *sections;
30 int active;
31};
32
33struct mod_dso {
34 struct list_head node;
35 struct rb_root mods;
36 struct module *(*find_module)(struct mod_dso *, const char *name);
37 char name[0];
38};
39
40struct sec_dso *sec_dso__new_dso(const char *name);
41void sec_dso__delete_sections(struct sec_dso *self);
42void sec_dso__delete_self(struct sec_dso *self);
43size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
44struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
45
46struct mod_dso *mod_dso__new_dso(const char *name);
47void mod_dso__delete_modules(struct mod_dso *self);
48void mod_dso__delete_self(struct mod_dso *self);
49size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
50struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
51int mod_dso__load_modules(struct mod_dso *dso);
52
53#endif /* _PERF_MODULE_ */
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
new file mode 100644
index 000000000000..1915de20dcac
--- /dev/null
+++ b/tools/perf/util/pager.c
@@ -0,0 +1,96 @@
1#include "cache.h"
2#include "run-command.h"
3#include "sigchain.h"
4
5/*
6 * This is split up from the rest of git so that we can do
7 * something different on Windows.
8 */
9
10static int spawned_pager;
11
12static void pager_preexec(void)
13{
14 /*
15 * Work around bug in "less" by not starting it until we
16 * have real input
17 */
18 fd_set in;
19
20 FD_ZERO(&in);
21 FD_SET(0, &in);
22 select(1, &in, NULL, &in, NULL);
23
24 setenv("LESS", "FRSX", 0);
25}
26
27static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
28static struct child_process pager_process;
29
30static void wait_for_pager(void)
31{
32 fflush(stdout);
33 fflush(stderr);
34 /* signal EOF to pager */
35 close(1);
36 close(2);
37 finish_command(&pager_process);
38}
39
40static void wait_for_pager_signal(int signo)
41{
42 wait_for_pager();
43 sigchain_pop(signo);
44 raise(signo);
45}
46
47void setup_pager(void)
48{
49 const char *pager = getenv("PERF_PAGER");
50
51 if (!isatty(1))
52 return;
53 if (!pager) {
54 if (!pager_program)
55 perf_config(perf_default_config, NULL);
56 pager = pager_program;
57 }
58 if (!pager)
59 pager = getenv("PAGER");
60 if (!pager)
61 pager = "less";
62 else if (!*pager || !strcmp(pager, "cat"))
63 return;
64
65 spawned_pager = 1; /* means we are emitting to terminal */
66
67 /* spawn the pager */
68 pager_argv[2] = pager;
69 pager_process.argv = pager_argv;
70 pager_process.in = -1;
71 pager_process.preexec_cb = pager_preexec;
72
73 if (start_command(&pager_process))
74 return;
75
76 /* original process continues, but writes to the pipe */
77 dup2(pager_process.in, 1);
78 if (isatty(2))
79 dup2(pager_process.in, 2);
80 close(pager_process.in);
81
82 /* this makes sure that the parent terminates after the pager */
83 sigchain_push_common(wait_for_pager_signal);
84 atexit(wait_for_pager);
85}
86
87int pager_in_use(void)
88{
89 const char *env;
90
91 if (spawned_pager)
92 return 1;
93
94 env = getenv("PERF_PAGER_IN_USE");
95 return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
96}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
new file mode 100644
index 000000000000..044178408783
--- /dev/null
+++ b/tools/perf/util/parse-events.c
@@ -0,0 +1,682 @@
1
2#include "../perf.h"
3#include "util.h"
4#include "parse-options.h"
5#include "parse-events.h"
6#include "exec_cmd.h"
7#include "string.h"
8#include "cache.h"
9
10extern char *strcasestr(const char *haystack, const char *needle);
11
12int nr_counters;
13
14struct perf_counter_attr attrs[MAX_COUNTERS];
15
16struct event_symbol {
17 u8 type;
18 u64 config;
19 char *symbol;
20 char *alias;
21};
22
23char debugfs_path[MAXPATHLEN];
24
25#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
26#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
27
28static struct event_symbol event_symbols[] = {
29 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
30 { CHW(INSTRUCTIONS), "instructions", "" },
31 { CHW(CACHE_REFERENCES), "cache-references", "" },
32 { CHW(CACHE_MISSES), "cache-misses", "" },
33 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
34 { CHW(BRANCH_MISSES), "branch-misses", "" },
35 { CHW(BUS_CYCLES), "bus-cycles", "" },
36
37 { CSW(CPU_CLOCK), "cpu-clock", "" },
38 { CSW(TASK_CLOCK), "task-clock", "" },
39 { CSW(PAGE_FAULTS), "page-faults", "faults" },
40 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
41 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
42 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
43 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
44};
45
46#define __PERF_COUNTER_FIELD(config, name) \
47 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
48
49#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
50#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
51#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
52#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
53
54static char *hw_event_names[] = {
55 "cycles",
56 "instructions",
57 "cache-references",
58 "cache-misses",
59 "branches",
60 "branch-misses",
61 "bus-cycles",
62};
63
64static char *sw_event_names[] = {
65 "cpu-clock-msecs",
66 "task-clock-msecs",
67 "page-faults",
68 "context-switches",
69 "CPU-migrations",
70 "minor-faults",
71 "major-faults",
72};
73
74#define MAX_ALIASES 8
75
76static char *hw_cache[][MAX_ALIASES] = {
77 { "L1-dcache", "l1-d", "l1d", "L1-data", },
78 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
79 { "LLC", "L2" },
80 { "dTLB", "d-tlb", "Data-TLB", },
81 { "iTLB", "i-tlb", "Instruction-TLB", },
82 { "branch", "branches", "bpu", "btb", "bpc", },
83};
84
85static char *hw_cache_op[][MAX_ALIASES] = {
86 { "load", "loads", "read", },
87 { "store", "stores", "write", },
88 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
89};
90
91static char *hw_cache_result[][MAX_ALIASES] = {
92 { "refs", "Reference", "ops", "access", },
93 { "misses", "miss", },
94};
95
96#define C(x) PERF_COUNT_HW_CACHE_##x
97#define CACHE_READ (1 << C(OP_READ))
98#define CACHE_WRITE (1 << C(OP_WRITE))
99#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
100#define COP(x) (1 << x)
101
102/*
103 * cache operartion stat
104 * L1I : Read and prefetch only
105 * ITLB and BPU : Read-only
106 */
107static unsigned long hw_cache_stat[C(MAX)] = {
108 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
109 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
110 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
111 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
112 [C(ITLB)] = (CACHE_READ),
113 [C(BPU)] = (CACHE_READ),
114};
115
116#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \
117 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
118 if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \
119 sys_dirent.d_name) && \
120 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
121 (strcmp(sys_dirent.d_name, ".")) && \
122 (strcmp(sys_dirent.d_name, "..")))
123
124static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
125{
126 char evt_path[MAXPATHLEN];
127 int fd;
128
129 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
130 sys_dir->d_name, evt_dir->d_name);
131 fd = open(evt_path, O_RDONLY);
132 if (fd < 0)
133 return -EINVAL;
134 close(fd);
135
136 return 0;
137}
138
139#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \
140 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
141 if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \
142 sys_dirent.d_name, evt_dirent.d_name) && \
143 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
144 (strcmp(evt_dirent.d_name, ".")) && \
145 (strcmp(evt_dirent.d_name, "..")) && \
146 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
147
148#define MAX_EVENT_LENGTH 30
149
150int valid_debugfs_mount(const char *debugfs)
151{
152 struct statfs st_fs;
153
154 if (statfs(debugfs, &st_fs) < 0)
155 return -ENOENT;
156 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
157 return -ENOENT;
158 return 0;
159}
160
161static char *tracepoint_id_to_name(u64 config)
162{
163 static char tracepoint_name[2 * MAX_EVENT_LENGTH];
164 DIR *sys_dir, *evt_dir;
165 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
166 struct stat st;
167 char id_buf[4];
168 int fd;
169 u64 id;
170 char evt_path[MAXPATHLEN];
171
172 if (valid_debugfs_mount(debugfs_path))
173 return "unkown";
174
175 sys_dir = opendir(debugfs_path);
176 if (!sys_dir)
177 goto cleanup;
178
179 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
180 evt_dir = opendir(evt_path);
181 if (!evt_dir)
182 goto cleanup;
183 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
184 evt_path, st) {
185 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
186 debugfs_path, sys_dirent.d_name,
187 evt_dirent.d_name);
188 fd = open(evt_path, O_RDONLY);
189 if (fd < 0)
190 continue;
191 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
192 close(fd);
193 continue;
194 }
195 close(fd);
196 id = atoll(id_buf);
197 if (id == config) {
198 closedir(evt_dir);
199 closedir(sys_dir);
200 snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH,
201 "%s:%s", sys_dirent.d_name,
202 evt_dirent.d_name);
203 return tracepoint_name;
204 }
205 }
206 closedir(evt_dir);
207 }
208
209cleanup:
210 closedir(sys_dir);
211 return "unkown";
212}
213
214static int is_cache_op_valid(u8 cache_type, u8 cache_op)
215{
216 if (hw_cache_stat[cache_type] & COP(cache_op))
217 return 1; /* valid */
218 else
219 return 0; /* invalid */
220}
221
222static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
223{
224 static char name[50];
225
226 if (cache_result) {
227 sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
228 hw_cache_op[cache_op][0],
229 hw_cache_result[cache_result][0]);
230 } else {
231 sprintf(name, "%s-%s", hw_cache[cache_type][0],
232 hw_cache_op[cache_op][1]);
233 }
234
235 return name;
236}
237
238char *event_name(int counter)
239{
240 u64 config = attrs[counter].config;
241 int type = attrs[counter].type;
242
243 return __event_name(type, config);
244}
245
246char *__event_name(int type, u64 config)
247{
248 static char buf[32];
249
250 if (type == PERF_TYPE_RAW) {
251 sprintf(buf, "raw 0x%llx", config);
252 return buf;
253 }
254
255 switch (type) {
256 case PERF_TYPE_HARDWARE:
257 if (config < PERF_COUNT_HW_MAX)
258 return hw_event_names[config];
259 return "unknown-hardware";
260
261 case PERF_TYPE_HW_CACHE: {
262 u8 cache_type, cache_op, cache_result;
263
264 cache_type = (config >> 0) & 0xff;
265 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
266 return "unknown-ext-hardware-cache-type";
267
268 cache_op = (config >> 8) & 0xff;
269 if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
270 return "unknown-ext-hardware-cache-op";
271
272 cache_result = (config >> 16) & 0xff;
273 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
274 return "unknown-ext-hardware-cache-result";
275
276 if (!is_cache_op_valid(cache_type, cache_op))
277 return "invalid-cache";
278
279 return event_cache_name(cache_type, cache_op, cache_result);
280 }
281
282 case PERF_TYPE_SOFTWARE:
283 if (config < PERF_COUNT_SW_MAX)
284 return sw_event_names[config];
285 return "unknown-software";
286
287 case PERF_TYPE_TRACEPOINT:
288 return tracepoint_id_to_name(config);
289
290 default:
291 break;
292 }
293
294 return "unknown";
295}
296
297static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size)
298{
299 int i, j;
300 int n, longest = -1;
301
302 for (i = 0; i < size; i++) {
303 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
304 n = strlen(names[i][j]);
305 if (n > longest && !strncasecmp(*str, names[i][j], n))
306 longest = n;
307 }
308 if (longest > 0) {
309 *str += longest;
310 return i;
311 }
312 }
313
314 return -1;
315}
316
317static int
318parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
319{
320 const char *s = *str;
321 int cache_type = -1, cache_op = -1, cache_result = -1;
322
323 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
324 /*
325 * No fallback - if we cannot get a clear cache type
326 * then bail out:
327 */
328 if (cache_type == -1)
329 return 0;
330
331 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
332 ++s;
333
334 if (cache_op == -1) {
335 cache_op = parse_aliases(&s, hw_cache_op,
336 PERF_COUNT_HW_CACHE_OP_MAX);
337 if (cache_op >= 0) {
338 if (!is_cache_op_valid(cache_type, cache_op))
339 return 0;
340 continue;
341 }
342 }
343
344 if (cache_result == -1) {
345 cache_result = parse_aliases(&s, hw_cache_result,
346 PERF_COUNT_HW_CACHE_RESULT_MAX);
347 if (cache_result >= 0)
348 continue;
349 }
350
351 /*
352 * Can't parse this as a cache op or result, so back up
353 * to the '-'.
354 */
355 --s;
356 break;
357 }
358
359 /*
360 * Fall back to reads:
361 */
362 if (cache_op == -1)
363 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
364
365 /*
366 * Fall back to accesses:
367 */
368 if (cache_result == -1)
369 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
370
371 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
372 attr->type = PERF_TYPE_HW_CACHE;
373
374 *str = s;
375 return 1;
376}
377
378static int parse_tracepoint_event(const char **strp,
379 struct perf_counter_attr *attr)
380{
381 const char *evt_name;
382 char *flags;
383 char sys_name[MAX_EVENT_LENGTH];
384 char id_buf[4];
385 int fd;
386 unsigned int sys_length, evt_length;
387 u64 id;
388 char evt_path[MAXPATHLEN];
389
390 if (valid_debugfs_mount(debugfs_path))
391 return 0;
392
393 evt_name = strchr(*strp, ':');
394 if (!evt_name)
395 return 0;
396
397 sys_length = evt_name - *strp;
398 if (sys_length >= MAX_EVENT_LENGTH)
399 return 0;
400
401 strncpy(sys_name, *strp, sys_length);
402 sys_name[sys_length] = '\0';
403 evt_name = evt_name + 1;
404
405 flags = strchr(evt_name, ':');
406 if (flags) {
407 *flags = '\0';
408 flags++;
409 if (!strncmp(flags, "record", strlen(flags)))
410 attr->sample_type |= PERF_SAMPLE_RAW;
411 }
412
413 evt_length = strlen(evt_name);
414 if (evt_length >= MAX_EVENT_LENGTH)
415 return 0;
416
417 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
418 sys_name, evt_name);
419 fd = open(evt_path, O_RDONLY);
420 if (fd < 0)
421 return 0;
422
423 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
424 close(fd);
425 return 0;
426 }
427 close(fd);
428 id = atoll(id_buf);
429 attr->config = id;
430 attr->type = PERF_TYPE_TRACEPOINT;
431 *strp = evt_name + evt_length;
432 return 1;
433}
434
435static int check_events(const char *str, unsigned int i)
436{
437 int n;
438
439 n = strlen(event_symbols[i].symbol);
440 if (!strncmp(str, event_symbols[i].symbol, n))
441 return n;
442
443 n = strlen(event_symbols[i].alias);
444 if (n)
445 if (!strncmp(str, event_symbols[i].alias, n))
446 return n;
447 return 0;
448}
449
450static int
451parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
452{
453 const char *str = *strp;
454 unsigned int i;
455 int n;
456
457 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
458 n = check_events(str, i);
459 if (n > 0) {
460 attr->type = event_symbols[i].type;
461 attr->config = event_symbols[i].config;
462 *strp = str + n;
463 return 1;
464 }
465 }
466 return 0;
467}
468
469static int parse_raw_event(const char **strp, struct perf_counter_attr *attr)
470{
471 const char *str = *strp;
472 u64 config;
473 int n;
474
475 if (*str != 'r')
476 return 0;
477 n = hex2u64(str + 1, &config);
478 if (n > 0) {
479 *strp = str + n + 1;
480 attr->type = PERF_TYPE_RAW;
481 attr->config = config;
482 return 1;
483 }
484 return 0;
485}
486
487static int
488parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
489{
490 const char *str = *strp;
491 char *endp;
492 unsigned long type;
493 u64 config;
494
495 type = strtoul(str, &endp, 0);
496 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
497 str = endp + 1;
498 config = strtoul(str, &endp, 0);
499 if (endp > str) {
500 attr->type = type;
501 attr->config = config;
502 *strp = endp;
503 return 1;
504 }
505 }
506 return 0;
507}
508
509static int
510parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
511{
512 const char *str = *strp;
513 int eu = 1, ek = 1, eh = 1;
514
515 if (*str++ != ':')
516 return 0;
517 while (*str) {
518 if (*str == 'u')
519 eu = 0;
520 else if (*str == 'k')
521 ek = 0;
522 else if (*str == 'h')
523 eh = 0;
524 else
525 break;
526 ++str;
527 }
528 if (str >= *strp + 2) {
529 *strp = str;
530 attr->exclude_user = eu;
531 attr->exclude_kernel = ek;
532 attr->exclude_hv = eh;
533 return 1;
534 }
535 return 0;
536}
537
538/*
539 * Each event can have multiple symbolic names.
540 * Symbolic names are (almost) exactly matched.
541 */
542static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
543{
544 if (!(parse_tracepoint_event(str, attr) ||
545 parse_raw_event(str, attr) ||
546 parse_numeric_event(str, attr) ||
547 parse_symbolic_event(str, attr) ||
548 parse_generic_hw_event(str, attr)))
549 return 0;
550
551 parse_event_modifier(str, attr);
552
553 return 1;
554}
555
556int parse_events(const struct option *opt __used, const char *str, int unset __used)
557{
558 struct perf_counter_attr attr;
559
560 for (;;) {
561 if (nr_counters == MAX_COUNTERS)
562 return -1;
563
564 memset(&attr, 0, sizeof(attr));
565 if (!parse_event_symbols(&str, &attr))
566 return -1;
567
568 if (!(*str == 0 || *str == ',' || isspace(*str)))
569 return -1;
570
571 attrs[nr_counters] = attr;
572 nr_counters++;
573
574 if (*str == 0)
575 break;
576 if (*str == ',')
577 ++str;
578 while (isspace(*str))
579 ++str;
580 }
581
582 return 0;
583}
584
585static const char * const event_type_descriptors[] = {
586 "",
587 "Hardware event",
588 "Software event",
589 "Tracepoint event",
590 "Hardware cache event",
591};
592
593/*
594 * Print the events from <debugfs_mount_point>/tracing/events
595 */
596
597static void print_tracepoint_events(void)
598{
599 DIR *sys_dir, *evt_dir;
600 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
601 struct stat st;
602 char evt_path[MAXPATHLEN];
603
604 if (valid_debugfs_mount(debugfs_path))
605 return;
606
607 sys_dir = opendir(debugfs_path);
608 if (!sys_dir)
609 goto cleanup;
610
611 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
612 evt_dir = opendir(evt_path);
613 if (!evt_dir)
614 goto cleanup;
615 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
616 evt_path, st) {
617 snprintf(evt_path, MAXPATHLEN, "%s:%s",
618 sys_dirent.d_name, evt_dirent.d_name);
619 fprintf(stderr, " %-40s [%s]\n", evt_path,
620 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
621 }
622 closedir(evt_dir);
623 }
624
625cleanup:
626 closedir(sys_dir);
627}
628
629/*
630 * Print the help text for the event symbols:
631 */
632void print_events(void)
633{
634 struct event_symbol *syms = event_symbols;
635 unsigned int i, type, op, prev_type = -1;
636 char name[40];
637
638 fprintf(stderr, "\n");
639 fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
640
641 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
642 type = syms->type + 1;
643 if (type >= ARRAY_SIZE(event_type_descriptors))
644 type = 0;
645
646 if (type != prev_type)
647 fprintf(stderr, "\n");
648
649 if (strlen(syms->alias))
650 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
651 else
652 strcpy(name, syms->symbol);
653 fprintf(stderr, " %-40s [%s]\n", name,
654 event_type_descriptors[type]);
655
656 prev_type = type;
657 }
658
659 fprintf(stderr, "\n");
660 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
661 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
662 /* skip invalid cache type */
663 if (!is_cache_op_valid(type, op))
664 continue;
665
666 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
667 fprintf(stderr, " %-40s [%s]\n",
668 event_cache_name(type, op, i),
669 event_type_descriptors[4]);
670 }
671 }
672 }
673
674 fprintf(stderr, "\n");
675 fprintf(stderr, " %-40s [raw hardware event descriptor]\n",
676 "rNNN");
677 fprintf(stderr, "\n");
678
679 print_tracepoint_events();
680
681 exit(129);
682}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
new file mode 100644
index 000000000000..192a962e3a0f
--- /dev/null
+++ b/tools/perf/util/parse-events.h
@@ -0,0 +1,23 @@
1
2/*
3 * Parse symbolic events/counts passed in as options:
4 */
5
6struct option;
7
8extern int nr_counters;
9
10extern struct perf_counter_attr attrs[MAX_COUNTERS];
11
12extern char *event_name(int ctr);
13extern char *__event_name(int type, u64 config);
14
15extern int parse_events(const struct option *opt, const char *str, int unset);
16
17#define EVENTS_HELP_MAX (128*1024)
18
19extern void print_events(void);
20
21extern char debugfs_path[];
22extern int valid_debugfs_mount(const char *debugfs);
23
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
new file mode 100644
index 000000000000..1bf67190c820
--- /dev/null
+++ b/tools/perf/util/parse-options.c
@@ -0,0 +1,509 @@
1#include "util.h"
2#include "parse-options.h"
3#include "cache.h"
4
5#define OPT_SHORT 1
6#define OPT_UNSET 2
7
8static int opterror(const struct option *opt, const char *reason, int flags)
9{
10 if (flags & OPT_SHORT)
11 return error("switch `%c' %s", opt->short_name, reason);
12 if (flags & OPT_UNSET)
13 return error("option `no-%s' %s", opt->long_name, reason);
14 return error("option `%s' %s", opt->long_name, reason);
15}
16
17static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
18 int flags, const char **arg)
19{
20 if (p->opt) {
21 *arg = p->opt;
22 p->opt = NULL;
23 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
24 **(p->argv + 1) == '-')) {
25 *arg = (const char *)opt->defval;
26 } else if (p->argc > 1) {
27 p->argc--;
28 *arg = *++p->argv;
29 } else
30 return opterror(opt, "requires a value", flags);
31 return 0;
32}
33
34static int get_value(struct parse_opt_ctx_t *p,
35 const struct option *opt, int flags)
36{
37 const char *s, *arg = NULL;
38 const int unset = flags & OPT_UNSET;
39
40 if (unset && p->opt)
41 return opterror(opt, "takes no value", flags);
42 if (unset && (opt->flags & PARSE_OPT_NONEG))
43 return opterror(opt, "isn't available", flags);
44
45 if (!(flags & OPT_SHORT) && p->opt) {
46 switch (opt->type) {
47 case OPTION_CALLBACK:
48 if (!(opt->flags & PARSE_OPT_NOARG))
49 break;
50 /* FALLTHROUGH */
51 case OPTION_BOOLEAN:
52 case OPTION_BIT:
53 case OPTION_SET_INT:
54 case OPTION_SET_PTR:
55 return opterror(opt, "takes no value", flags);
56 default:
57 break;
58 }
59 }
60
61 switch (opt->type) {
62 case OPTION_BIT:
63 if (unset)
64 *(int *)opt->value &= ~opt->defval;
65 else
66 *(int *)opt->value |= opt->defval;
67 return 0;
68
69 case OPTION_BOOLEAN:
70 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
71 return 0;
72
73 case OPTION_SET_INT:
74 *(int *)opt->value = unset ? 0 : opt->defval;
75 return 0;
76
77 case OPTION_SET_PTR:
78 *(void **)opt->value = unset ? NULL : (void *)opt->defval;
79 return 0;
80
81 case OPTION_STRING:
82 if (unset)
83 *(const char **)opt->value = NULL;
84 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
85 *(const char **)opt->value = (const char *)opt->defval;
86 else
87 return get_arg(p, opt, flags, (const char **)opt->value);
88 return 0;
89
90 case OPTION_CALLBACK:
91 if (unset)
92 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
93 if (opt->flags & PARSE_OPT_NOARG)
94 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
95 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
96 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
97 if (get_arg(p, opt, flags, &arg))
98 return -1;
99 return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
100
101 case OPTION_INTEGER:
102 if (unset) {
103 *(int *)opt->value = 0;
104 return 0;
105 }
106 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
107 *(int *)opt->value = opt->defval;
108 return 0;
109 }
110 if (get_arg(p, opt, flags, &arg))
111 return -1;
112 *(int *)opt->value = strtol(arg, (char **)&s, 10);
113 if (*s)
114 return opterror(opt, "expects a numerical value", flags);
115 return 0;
116
117 case OPTION_LONG:
118 if (unset) {
119 *(long *)opt->value = 0;
120 return 0;
121 }
122 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
123 *(long *)opt->value = opt->defval;
124 return 0;
125 }
126 if (get_arg(p, opt, flags, &arg))
127 return -1;
128 *(long *)opt->value = strtol(arg, (char **)&s, 10);
129 if (*s)
130 return opterror(opt, "expects a numerical value", flags);
131 return 0;
132
133 default:
134 die("should not happen, someone must be hit on the forehead");
135 }
136}
137
138static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
139{
140 for (; options->type != OPTION_END; options++) {
141 if (options->short_name == *p->opt) {
142 p->opt = p->opt[1] ? p->opt + 1 : NULL;
143 return get_value(p, options, OPT_SHORT);
144 }
145 }
146 return -2;
147}
148
149static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
150 const struct option *options)
151{
152 const char *arg_end = strchr(arg, '=');
153 const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
154 int abbrev_flags = 0, ambiguous_flags = 0;
155
156 if (!arg_end)
157 arg_end = arg + strlen(arg);
158
159 for (; options->type != OPTION_END; options++) {
160 const char *rest;
161 int flags = 0;
162
163 if (!options->long_name)
164 continue;
165
166 rest = skip_prefix(arg, options->long_name);
167 if (options->type == OPTION_ARGUMENT) {
168 if (!rest)
169 continue;
170 if (*rest == '=')
171 return opterror(options, "takes no value", flags);
172 if (*rest)
173 continue;
174 p->out[p->cpidx++] = arg - 2;
175 return 0;
176 }
177 if (!rest) {
178 /* abbreviated? */
179 if (!strncmp(options->long_name, arg, arg_end - arg)) {
180is_abbreviated:
181 if (abbrev_option) {
182 /*
183 * If this is abbreviated, it is
184 * ambiguous. So when there is no
185 * exact match later, we need to
186 * error out.
187 */
188 ambiguous_option = abbrev_option;
189 ambiguous_flags = abbrev_flags;
190 }
191 if (!(flags & OPT_UNSET) && *arg_end)
192 p->opt = arg_end + 1;
193 abbrev_option = options;
194 abbrev_flags = flags;
195 continue;
196 }
197 /* negated and abbreviated very much? */
198 if (!prefixcmp("no-", arg)) {
199 flags |= OPT_UNSET;
200 goto is_abbreviated;
201 }
202 /* negated? */
203 if (strncmp(arg, "no-", 3))
204 continue;
205 flags |= OPT_UNSET;
206 rest = skip_prefix(arg + 3, options->long_name);
207 /* abbreviated and negated? */
208 if (!rest && !prefixcmp(options->long_name, arg + 3))
209 goto is_abbreviated;
210 if (!rest)
211 continue;
212 }
213 if (*rest) {
214 if (*rest != '=')
215 continue;
216 p->opt = rest + 1;
217 }
218 return get_value(p, options, flags);
219 }
220
221 if (ambiguous_option)
222 return error("Ambiguous option: %s "
223 "(could be --%s%s or --%s%s)",
224 arg,
225 (ambiguous_flags & OPT_UNSET) ? "no-" : "",
226 ambiguous_option->long_name,
227 (abbrev_flags & OPT_UNSET) ? "no-" : "",
228 abbrev_option->long_name);
229 if (abbrev_option)
230 return get_value(p, abbrev_option, abbrev_flags);
231 return -2;
232}
233
234static void check_typos(const char *arg, const struct option *options)
235{
236 if (strlen(arg) < 3)
237 return;
238
239 if (!prefixcmp(arg, "no-")) {
240 error ("did you mean `--%s` (with two dashes ?)", arg);
241 exit(129);
242 }
243
244 for (; options->type != OPTION_END; options++) {
245 if (!options->long_name)
246 continue;
247 if (!prefixcmp(options->long_name, arg)) {
248 error ("did you mean `--%s` (with two dashes ?)", arg);
249 exit(129);
250 }
251 }
252}
253
254void parse_options_start(struct parse_opt_ctx_t *ctx,
255 int argc, const char **argv, int flags)
256{
257 memset(ctx, 0, sizeof(*ctx));
258 ctx->argc = argc - 1;
259 ctx->argv = argv + 1;
260 ctx->out = argv;
261 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
262 ctx->flags = flags;
263 if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
264 (flags & PARSE_OPT_STOP_AT_NON_OPTION))
265 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
266}
267
268static int usage_with_options_internal(const char * const *,
269 const struct option *, int);
270
271int parse_options_step(struct parse_opt_ctx_t *ctx,
272 const struct option *options,
273 const char * const usagestr[])
274{
275 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
276
277 /* we must reset ->opt, unknown short option leave it dangling */
278 ctx->opt = NULL;
279
280 for (; ctx->argc; ctx->argc--, ctx->argv++) {
281 const char *arg = ctx->argv[0];
282
283 if (*arg != '-' || !arg[1]) {
284 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
285 break;
286 ctx->out[ctx->cpidx++] = ctx->argv[0];
287 continue;
288 }
289
290 if (arg[1] != '-') {
291 ctx->opt = arg + 1;
292 if (internal_help && *ctx->opt == 'h')
293 return parse_options_usage(usagestr, options);
294 switch (parse_short_opt(ctx, options)) {
295 case -1:
296 return parse_options_usage(usagestr, options);
297 case -2:
298 goto unknown;
299 }
300 if (ctx->opt)
301 check_typos(arg + 1, options);
302 while (ctx->opt) {
303 if (internal_help && *ctx->opt == 'h')
304 return parse_options_usage(usagestr, options);
305 switch (parse_short_opt(ctx, options)) {
306 case -1:
307 return parse_options_usage(usagestr, options);
308 case -2:
309 /* fake a short option thing to hide the fact that we may have
310 * started to parse aggregated stuff
311 *
312 * This is leaky, too bad.
313 */
314 ctx->argv[0] = strdup(ctx->opt - 1);
315 *(char *)ctx->argv[0] = '-';
316 goto unknown;
317 }
318 }
319 continue;
320 }
321
322 if (!arg[2]) { /* "--" */
323 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
324 ctx->argc--;
325 ctx->argv++;
326 }
327 break;
328 }
329
330 if (internal_help && !strcmp(arg + 2, "help-all"))
331 return usage_with_options_internal(usagestr, options, 1);
332 if (internal_help && !strcmp(arg + 2, "help"))
333 return parse_options_usage(usagestr, options);
334 switch (parse_long_opt(ctx, arg + 2, options)) {
335 case -1:
336 return parse_options_usage(usagestr, options);
337 case -2:
338 goto unknown;
339 }
340 continue;
341unknown:
342 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
343 return PARSE_OPT_UNKNOWN;
344 ctx->out[ctx->cpidx++] = ctx->argv[0];
345 ctx->opt = NULL;
346 }
347 return PARSE_OPT_DONE;
348}
349
350int parse_options_end(struct parse_opt_ctx_t *ctx)
351{
352 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
353 ctx->out[ctx->cpidx + ctx->argc] = NULL;
354 return ctx->cpidx + ctx->argc;
355}
356
357int parse_options(int argc, const char **argv, const struct option *options,
358 const char * const usagestr[], int flags)
359{
360 struct parse_opt_ctx_t ctx;
361
362 parse_options_start(&ctx, argc, argv, flags);
363 switch (parse_options_step(&ctx, options, usagestr)) {
364 case PARSE_OPT_HELP:
365 exit(129);
366 case PARSE_OPT_DONE:
367 break;
368 default: /* PARSE_OPT_UNKNOWN */
369 if (ctx.argv[0][1] == '-') {
370 error("unknown option `%s'", ctx.argv[0] + 2);
371 } else {
372 error("unknown switch `%c'", *ctx.opt);
373 }
374 usage_with_options(usagestr, options);
375 }
376
377 return parse_options_end(&ctx);
378}
379
380#define USAGE_OPTS_WIDTH 24
381#define USAGE_GAP 2
382
383int usage_with_options_internal(const char * const *usagestr,
384 const struct option *opts, int full)
385{
386 if (!usagestr)
387 return PARSE_OPT_HELP;
388
389 fprintf(stderr, "\n usage: %s\n", *usagestr++);
390 while (*usagestr && **usagestr)
391 fprintf(stderr, " or: %s\n", *usagestr++);
392 while (*usagestr) {
393 fprintf(stderr, "%s%s\n",
394 **usagestr ? " " : "",
395 *usagestr);
396 usagestr++;
397 }
398
399 if (opts->type != OPTION_GROUP)
400 fputc('\n', stderr);
401
402 for (; opts->type != OPTION_END; opts++) {
403 size_t pos;
404 int pad;
405
406 if (opts->type == OPTION_GROUP) {
407 fputc('\n', stderr);
408 if (*opts->help)
409 fprintf(stderr, "%s\n", opts->help);
410 continue;
411 }
412 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
413 continue;
414
415 pos = fprintf(stderr, " ");
416 if (opts->short_name)
417 pos += fprintf(stderr, "-%c", opts->short_name);
418 if (opts->long_name && opts->short_name)
419 pos += fprintf(stderr, ", ");
420 if (opts->long_name)
421 pos += fprintf(stderr, "--%s", opts->long_name);
422
423 switch (opts->type) {
424 case OPTION_ARGUMENT:
425 break;
426 case OPTION_INTEGER:
427 if (opts->flags & PARSE_OPT_OPTARG)
428 if (opts->long_name)
429 pos += fprintf(stderr, "[=<n>]");
430 else
431 pos += fprintf(stderr, "[<n>]");
432 else
433 pos += fprintf(stderr, " <n>");
434 break;
435 case OPTION_CALLBACK:
436 if (opts->flags & PARSE_OPT_NOARG)
437 break;
438 /* FALLTHROUGH */
439 case OPTION_STRING:
440 if (opts->argh) {
441 if (opts->flags & PARSE_OPT_OPTARG)
442 if (opts->long_name)
443 pos += fprintf(stderr, "[=<%s>]", opts->argh);
444 else
445 pos += fprintf(stderr, "[<%s>]", opts->argh);
446 else
447 pos += fprintf(stderr, " <%s>", opts->argh);
448 } else {
449 if (opts->flags & PARSE_OPT_OPTARG)
450 if (opts->long_name)
451 pos += fprintf(stderr, "[=...]");
452 else
453 pos += fprintf(stderr, "[...]");
454 else
455 pos += fprintf(stderr, " ...");
456 }
457 break;
458 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
459 break;
460 }
461
462 if (pos <= USAGE_OPTS_WIDTH)
463 pad = USAGE_OPTS_WIDTH - pos;
464 else {
465 fputc('\n', stderr);
466 pad = USAGE_OPTS_WIDTH;
467 }
468 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
469 }
470 fputc('\n', stderr);
471
472 return PARSE_OPT_HELP;
473}
474
475void usage_with_options(const char * const *usagestr,
476 const struct option *opts)
477{
478 usage_with_options_internal(usagestr, opts, 0);
479 exit(129);
480}
481
482int parse_options_usage(const char * const *usagestr,
483 const struct option *opts)
484{
485 return usage_with_options_internal(usagestr, opts, 0);
486}
487
488
489int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
490 int unset)
491{
492 int *target = opt->value;
493
494 if (unset)
495 /* --no-quiet, --no-verbose */
496 *target = 0;
497 else if (opt->short_name == 'v') {
498 if (*target >= 0)
499 (*target)++;
500 else
501 *target = 1;
502 } else {
503 if (*target <= 0)
504 (*target)--;
505 else
506 *target = -1;
507 }
508 return 0;
509}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
new file mode 100644
index 000000000000..8aa3464c7090
--- /dev/null
+++ b/tools/perf/util/parse-options.h
@@ -0,0 +1,175 @@
1#ifndef PARSE_OPTIONS_H
2#define PARSE_OPTIONS_H
3
4enum parse_opt_type {
5 /* special types */
6 OPTION_END,
7 OPTION_ARGUMENT,
8 OPTION_GROUP,
9 /* options with no arguments */
10 OPTION_BIT,
11 OPTION_BOOLEAN, /* _INCR would have been a better name */
12 OPTION_SET_INT,
13 OPTION_SET_PTR,
14 /* options with arguments (usually) */
15 OPTION_STRING,
16 OPTION_INTEGER,
17 OPTION_LONG,
18 OPTION_CALLBACK,
19};
20
21enum parse_opt_flags {
22 PARSE_OPT_KEEP_DASHDASH = 1,
23 PARSE_OPT_STOP_AT_NON_OPTION = 2,
24 PARSE_OPT_KEEP_ARGV0 = 4,
25 PARSE_OPT_KEEP_UNKNOWN = 8,
26 PARSE_OPT_NO_INTERNAL_HELP = 16,
27};
28
29enum parse_opt_option_flags {
30 PARSE_OPT_OPTARG = 1,
31 PARSE_OPT_NOARG = 2,
32 PARSE_OPT_NONEG = 4,
33 PARSE_OPT_HIDDEN = 8,
34 PARSE_OPT_LASTARG_DEFAULT = 16,
35};
36
37struct option;
38typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
39
40/*
41 * `type`::
42 * holds the type of the option, you must have an OPTION_END last in your
43 * array.
44 *
45 * `short_name`::
46 * the character to use as a short option name, '\0' if none.
47 *
48 * `long_name`::
49 * the long option name, without the leading dashes, NULL if none.
50 *
51 * `value`::
52 * stores pointers to the values to be filled.
53 *
54 * `argh`::
55 * token to explain the kind of argument this option wants. Keep it
56 * homogenous across the repository.
57 *
58 * `help`::
59 * the short help associated to what the option does.
60 * Must never be NULL (except for OPTION_END).
61 * OPTION_GROUP uses this pointer to store the group header.
62 *
63 * `flags`::
64 * mask of parse_opt_option_flags.
65 * PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
66 * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
67 * PARSE_OPT_NONEG: says that this option cannot be negated
68 * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
69 * the long one.
70 *
71 * `callback`::
72 * pointer to the callback to use for OPTION_CALLBACK.
73 *
74 * `defval`::
75 * default value to fill (*->value) with for PARSE_OPT_OPTARG.
76 * OPTION_{BIT,SET_INT,SET_PTR} store the {mask,integer,pointer} to put in
77 * the value when met.
78 * CALLBACKS can use it like they want.
79 */
80struct option {
81 enum parse_opt_type type;
82 int short_name;
83 const char *long_name;
84 void *value;
85 const char *argh;
86 const char *help;
87
88 int flags;
89 parse_opt_cb *callback;
90 intptr_t defval;
91};
92
93#define OPT_END() { .type = OPTION_END }
94#define OPT_ARGUMENT(l, h) { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
95#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) }
96#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (b) }
97#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
98#define OPT_SET_INT(s, l, v, h, i) { .type = OPTION_SET_INT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (i) }
99#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
100#define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
101#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = (v), .help = (h) }
102#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h) }
103#define OPT_DATE(s, l, v, h) \
104 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
105#define OPT_CALLBACK(s, l, v, a, h, f) \
106 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
107#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
108 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
109
110/* parse_options() will filter out the processed options and leave the
111 * non-option argments in argv[].
112 * Returns the number of arguments left in argv[].
113 */
114extern int parse_options(int argc, const char **argv,
115 const struct option *options,
116 const char * const usagestr[], int flags);
117
118extern NORETURN void usage_with_options(const char * const *usagestr,
119 const struct option *options);
120
121/*----- incremantal advanced APIs -----*/
122
123enum {
124 PARSE_OPT_HELP = -1,
125 PARSE_OPT_DONE,
126 PARSE_OPT_UNKNOWN,
127};
128
129/*
130 * It's okay for the caller to consume argv/argc in the usual way.
131 * Other fields of that structure are private to parse-options and should not
132 * be modified in any way.
133 */
134struct parse_opt_ctx_t {
135 const char **argv;
136 const char **out;
137 int argc, cpidx;
138 const char *opt;
139 int flags;
140};
141
142extern int parse_options_usage(const char * const *usagestr,
143 const struct option *opts);
144
145extern void parse_options_start(struct parse_opt_ctx_t *ctx,
146 int argc, const char **argv, int flags);
147
148extern int parse_options_step(struct parse_opt_ctx_t *ctx,
149 const struct option *options,
150 const char * const usagestr[]);
151
152extern int parse_options_end(struct parse_opt_ctx_t *ctx);
153
154
155/*----- some often used options -----*/
156extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
157extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
158extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
159
160#define OPT__VERBOSE(var) OPT_BOOLEAN('v', "verbose", (var), "be verbose")
161#define OPT__QUIET(var) OPT_BOOLEAN('q', "quiet", (var), "be quiet")
162#define OPT__VERBOSITY(var) \
163 { OPTION_CALLBACK, 'v', "verbose", (var), NULL, "be more verbose", \
164 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
165 { OPTION_CALLBACK, 'q', "quiet", (var), NULL, "be more quiet", \
166 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
167#define OPT__DRY_RUN(var) OPT_BOOLEAN('n', "dry-run", (var), "dry run")
168#define OPT__ABBREV(var) \
169 { OPTION_CALLBACK, 0, "abbrev", (var), "n", \
170 "use <n> digits to display SHA-1s", \
171 PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
172
173extern const char *parse_options_fix_filename(const char *prefix, const char *file);
174
175#endif
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
new file mode 100644
index 000000000000..a501a40dd2cb
--- /dev/null
+++ b/tools/perf/util/path.c
@@ -0,0 +1,353 @@
1/*
2 * I'm tired of doing "vsnprintf()" etc just to open a
3 * file, so here's a "return static buffer with printf"
4 * interface for paths.
5 *
6 * It's obviously not thread-safe. Sue me. But it's quite
7 * useful for doing things like
8 *
9 * f = open(mkpath("%s/%s.perf", base, name), O_RDONLY);
10 *
11 * which is what it's designed for.
12 */
13#include "cache.h"
14
15static char bad_path[] = "/bad-path/";
16/*
17 * Two hacks:
18 */
19
20static char *get_perf_dir(void)
21{
22 return ".";
23}
24
25size_t strlcpy(char *dest, const char *src, size_t size)
26{
27 size_t ret = strlen(src);
28
29 if (size) {
30 size_t len = (ret >= size) ? size - 1 : ret;
31 memcpy(dest, src, len);
32 dest[len] = '\0';
33 }
34 return ret;
35}
36
37
38static char *get_pathname(void)
39{
40 static char pathname_array[4][PATH_MAX];
41 static int index;
42 return pathname_array[3 & ++index];
43}
44
45static char *cleanup_path(char *path)
46{
47 /* Clean it up */
48 if (!memcmp(path, "./", 2)) {
49 path += 2;
50 while (*path == '/')
51 path++;
52 }
53 return path;
54}
55
56char *mksnpath(char *buf, size_t n, const char *fmt, ...)
57{
58 va_list args;
59 unsigned len;
60
61 va_start(args, fmt);
62 len = vsnprintf(buf, n, fmt, args);
63 va_end(args);
64 if (len >= n) {
65 strlcpy(buf, bad_path, n);
66 return buf;
67 }
68 return cleanup_path(buf);
69}
70
71static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
72{
73 const char *perf_dir = get_perf_dir();
74 size_t len;
75
76 len = strlen(perf_dir);
77 if (n < len + 1)
78 goto bad;
79 memcpy(buf, perf_dir, len);
80 if (len && !is_dir_sep(perf_dir[len-1]))
81 buf[len++] = '/';
82 len += vsnprintf(buf + len, n - len, fmt, args);
83 if (len >= n)
84 goto bad;
85 return cleanup_path(buf);
86bad:
87 strlcpy(buf, bad_path, n);
88 return buf;
89}
90
91char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
92{
93 va_list args;
94 va_start(args, fmt);
95 (void)perf_vsnpath(buf, n, fmt, args);
96 va_end(args);
97 return buf;
98}
99
100char *perf_pathdup(const char *fmt, ...)
101{
102 char path[PATH_MAX];
103 va_list args;
104 va_start(args, fmt);
105 (void)perf_vsnpath(path, sizeof(path), fmt, args);
106 va_end(args);
107 return xstrdup(path);
108}
109
110char *mkpath(const char *fmt, ...)
111{
112 va_list args;
113 unsigned len;
114 char *pathname = get_pathname();
115
116 va_start(args, fmt);
117 len = vsnprintf(pathname, PATH_MAX, fmt, args);
118 va_end(args);
119 if (len >= PATH_MAX)
120 return bad_path;
121 return cleanup_path(pathname);
122}
123
124char *perf_path(const char *fmt, ...)
125{
126 const char *perf_dir = get_perf_dir();
127 char *pathname = get_pathname();
128 va_list args;
129 unsigned len;
130
131 len = strlen(perf_dir);
132 if (len > PATH_MAX-100)
133 return bad_path;
134 memcpy(pathname, perf_dir, len);
135 if (len && perf_dir[len-1] != '/')
136 pathname[len++] = '/';
137 va_start(args, fmt);
138 len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
139 va_end(args);
140 if (len >= PATH_MAX)
141 return bad_path;
142 return cleanup_path(pathname);
143}
144
145
146/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
147int perf_mkstemp(char *path, size_t len, const char *template)
148{
149 const char *tmp;
150 size_t n;
151
152 tmp = getenv("TMPDIR");
153 if (!tmp)
154 tmp = "/tmp";
155 n = snprintf(path, len, "%s/%s", tmp, template);
156 if (len <= n) {
157 errno = ENAMETOOLONG;
158 return -1;
159 }
160 return mkstemp(path);
161}
162
163
164const char *make_relative_path(const char *abs, const char *base)
165{
166 static char buf[PATH_MAX + 1];
167 int baselen;
168 if (!base)
169 return abs;
170 baselen = strlen(base);
171 if (prefixcmp(abs, base))
172 return abs;
173 if (abs[baselen] == '/')
174 baselen++;
175 else if (base[baselen - 1] != '/')
176 return abs;
177 strcpy(buf, abs + baselen);
178 return buf;
179}
180
181/*
182 * It is okay if dst == src, but they should not overlap otherwise.
183 *
184 * Performs the following normalizations on src, storing the result in dst:
185 * - Ensures that components are separated by '/' (Windows only)
186 * - Squashes sequences of '/'.
187 * - Removes "." components.
188 * - Removes ".." components, and the components the precede them.
189 * Returns failure (non-zero) if a ".." component appears as first path
190 * component anytime during the normalization. Otherwise, returns success (0).
191 *
192 * Note that this function is purely textual. It does not follow symlinks,
193 * verify the existence of the path, or make any system calls.
194 */
195int normalize_path_copy(char *dst, const char *src)
196{
197 char *dst0;
198
199 if (has_dos_drive_prefix(src)) {
200 *dst++ = *src++;
201 *dst++ = *src++;
202 }
203 dst0 = dst;
204
205 if (is_dir_sep(*src)) {
206 *dst++ = '/';
207 while (is_dir_sep(*src))
208 src++;
209 }
210
211 for (;;) {
212 char c = *src;
213
214 /*
215 * A path component that begins with . could be
216 * special:
217 * (1) "." and ends -- ignore and terminate.
218 * (2) "./" -- ignore them, eat slash and continue.
219 * (3) ".." and ends -- strip one and terminate.
220 * (4) "../" -- strip one, eat slash and continue.
221 */
222 if (c == '.') {
223 if (!src[1]) {
224 /* (1) */
225 src++;
226 } else if (is_dir_sep(src[1])) {
227 /* (2) */
228 src += 2;
229 while (is_dir_sep(*src))
230 src++;
231 continue;
232 } else if (src[1] == '.') {
233 if (!src[2]) {
234 /* (3) */
235 src += 2;
236 goto up_one;
237 } else if (is_dir_sep(src[2])) {
238 /* (4) */
239 src += 3;
240 while (is_dir_sep(*src))
241 src++;
242 goto up_one;
243 }
244 }
245 }
246
247 /* copy up to the next '/', and eat all '/' */
248 while ((c = *src++) != '\0' && !is_dir_sep(c))
249 *dst++ = c;
250 if (is_dir_sep(c)) {
251 *dst++ = '/';
252 while (is_dir_sep(c))
253 c = *src++;
254 src--;
255 } else if (!c)
256 break;
257 continue;
258
259 up_one:
260 /*
261 * dst0..dst is prefix portion, and dst[-1] is '/';
262 * go up one level.
263 */
264 dst--; /* go to trailing '/' */
265 if (dst <= dst0)
266 return -1;
267 /* Windows: dst[-1] cannot be backslash anymore */
268 while (dst0 < dst && dst[-1] != '/')
269 dst--;
270 }
271 *dst = '\0';
272 return 0;
273}
274
275/*
276 * path = Canonical absolute path
277 * prefix_list = Colon-separated list of absolute paths
278 *
279 * Determines, for each path in prefix_list, whether the "prefix" really
280 * is an ancestor directory of path. Returns the length of the longest
281 * ancestor directory, excluding any trailing slashes, or -1 if no prefix
282 * is an ancestor. (Note that this means 0 is returned if prefix_list is
283 * "/".) "/foo" is not considered an ancestor of "/foobar". Directories
284 * are not considered to be their own ancestors. path must be in a
285 * canonical form: empty components, or "." or ".." components are not
286 * allowed. prefix_list may be null, which is like "".
287 */
288int longest_ancestor_length(const char *path, const char *prefix_list)
289{
290 char buf[PATH_MAX+1];
291 const char *ceil, *colon;
292 int len, max_len = -1;
293
294 if (prefix_list == NULL || !strcmp(path, "/"))
295 return -1;
296
297 for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
298 for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
299 len = colon - ceil;
300 if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
301 continue;
302 strlcpy(buf, ceil, len+1);
303 if (normalize_path_copy(buf, buf) < 0)
304 continue;
305 len = strlen(buf);
306 if (len > 0 && buf[len-1] == '/')
307 buf[--len] = '\0';
308
309 if (!strncmp(path, buf, len) &&
310 path[len] == '/' &&
311 len > max_len) {
312 max_len = len;
313 }
314 }
315
316 return max_len;
317}
318
319/* strip arbitrary amount of directory separators at end of path */
320static inline int chomp_trailing_dir_sep(const char *path, int len)
321{
322 while (len && is_dir_sep(path[len - 1]))
323 len--;
324 return len;
325}
326
327/*
328 * If path ends with suffix (complete path components), returns the
329 * part before suffix (sans trailing directory separators).
330 * Otherwise returns NULL.
331 */
332char *strip_path_suffix(const char *path, const char *suffix)
333{
334 int path_len = strlen(path), suffix_len = strlen(suffix);
335
336 while (suffix_len) {
337 if (!path_len)
338 return NULL;
339
340 if (is_dir_sep(path[path_len - 1])) {
341 if (!is_dir_sep(suffix[suffix_len - 1]))
342 return NULL;
343 path_len = chomp_trailing_dir_sep(path, path_len);
344 suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
345 }
346 else if (path[--path_len] != suffix[--suffix_len])
347 return NULL;
348 }
349
350 if (path_len && !is_dir_sep(path[path_len - 1]))
351 return NULL;
352 return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
353}
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
new file mode 100644
index 000000000000..2726fe40eb5d
--- /dev/null
+++ b/tools/perf/util/quote.c
@@ -0,0 +1,485 @@
1#include "cache.h"
2#include "quote.h"
3
4int quote_path_fully = 1;
5
6/* Help to copy the thing properly quoted for the shell safety.
7 * any single quote is replaced with '\'', any exclamation point
8 * is replaced with '\!', and the whole thing is enclosed in a
9 *
10 * E.g.
11 * original sq_quote result
12 * name ==> name ==> 'name'
13 * a b ==> a b ==> 'a b'
14 * a'b ==> a'\''b ==> 'a'\''b'
15 * a!b ==> a'\!'b ==> 'a'\!'b'
16 */
17static inline int need_bs_quote(char c)
18{
19 return (c == '\'' || c == '!');
20}
21
22void sq_quote_buf(struct strbuf *dst, const char *src)
23{
24 char *to_free = NULL;
25
26 if (dst->buf == src)
27 to_free = strbuf_detach(dst, NULL);
28
29 strbuf_addch(dst, '\'');
30 while (*src) {
31 size_t len = strcspn(src, "'!");
32 strbuf_add(dst, src, len);
33 src += len;
34 while (need_bs_quote(*src)) {
35 strbuf_addstr(dst, "'\\");
36 strbuf_addch(dst, *src++);
37 strbuf_addch(dst, '\'');
38 }
39 }
40 strbuf_addch(dst, '\'');
41 free(to_free);
42}
43
44void sq_quote_print(FILE *stream, const char *src)
45{
46 char c;
47
48 fputc('\'', stream);
49 while ((c = *src++)) {
50 if (need_bs_quote(c)) {
51 fputs("'\\", stream);
52 fputc(c, stream);
53 fputc('\'', stream);
54 } else {
55 fputc(c, stream);
56 }
57 }
58 fputc('\'', stream);
59}
60
61void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
62{
63 int i;
64
65 /* Copy into destination buffer. */
66 strbuf_grow(dst, 255);
67 for (i = 0; argv[i]; ++i) {
68 strbuf_addch(dst, ' ');
69 sq_quote_buf(dst, argv[i]);
70 if (maxlen && dst->len > maxlen)
71 die("Too many or long arguments");
72 }
73}
74
75char *sq_dequote_step(char *arg, char **next)
76{
77 char *dst = arg;
78 char *src = arg;
79 char c;
80
81 if (*src != '\'')
82 return NULL;
83 for (;;) {
84 c = *++src;
85 if (!c)
86 return NULL;
87 if (c != '\'') {
88 *dst++ = c;
89 continue;
90 }
91 /* We stepped out of sq */
92 switch (*++src) {
93 case '\0':
94 *dst = 0;
95 if (next)
96 *next = NULL;
97 return arg;
98 case '\\':
99 c = *++src;
100 if (need_bs_quote(c) && *++src == '\'') {
101 *dst++ = c;
102 continue;
103 }
104 /* Fallthrough */
105 default:
106 if (!next || !isspace(*src))
107 return NULL;
108 do {
109 c = *++src;
110 } while (isspace(c));
111 *dst = 0;
112 *next = src;
113 return arg;
114 }
115 }
116}
117
118char *sq_dequote(char *arg)
119{
120 return sq_dequote_step(arg, NULL);
121}
122
123int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc)
124{
125 char *next = arg;
126
127 if (!*arg)
128 return 0;
129 do {
130 char *dequoted = sq_dequote_step(next, &next);
131 if (!dequoted)
132 return -1;
133 ALLOC_GROW(*argv, *nr + 1, *alloc);
134 (*argv)[(*nr)++] = dequoted;
135 } while (next);
136
137 return 0;
138}
139
140/* 1 means: quote as octal
141 * 0 means: quote as octal if (quote_path_fully)
142 * -1 means: never quote
143 * c: quote as "\\c"
144 */
145#define X8(x) x, x, x, x, x, x, x, x
146#define X16(x) X8(x), X8(x)
147static signed char const sq_lookup[256] = {
148 /* 0 1 2 3 4 5 6 7 */
149 /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a',
150 /* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1,
151 /* 0x10 */ X16(1),
152 /* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1,
153 /* 0x28 */ X16(-1), X16(-1), X16(-1),
154 /* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1,
155 /* 0x60 */ X16(-1), X8(-1),
156 /* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1,
157 /* 0x80 */ /* set to 0 */
158};
159
160static inline int sq_must_quote(char c)
161{
162 return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
163}
164
165/*
166 * Returns the longest prefix not needing a quote up to maxlen if
167 * positive.
168 * This stops at the first \0 because it's marked as a character
169 * needing an escape.
170 */
171static ssize_t next_quote_pos(const char *s, ssize_t maxlen)
172{
173 ssize_t len;
174
175 if (maxlen < 0) {
176 for (len = 0; !sq_must_quote(s[len]); len++);
177 } else {
178 for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++);
179 }
180 return len;
181}
182
183/*
184 * C-style name quoting.
185 *
186 * (1) if sb and fp are both NULL, inspect the input name and counts the
187 * number of bytes that are needed to hold c_style quoted version of name,
188 * counting the double quotes around it but not terminating NUL, and
189 * returns it.
190 * However, if name does not need c_style quoting, it returns 0.
191 *
192 * (2) if sb or fp are not NULL, it emits the c_style quoted version
193 * of name, enclosed with double quotes if asked and needed only.
194 * Return value is the same as in (1).
195 */
196static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
197 struct strbuf *sb, FILE *fp, int no_dq)
198{
199#define EMIT(c) \
200 do { \
201 if (sb) strbuf_addch(sb, (c)); \
202 if (fp) fputc((c), fp); \
203 count++; \
204 } while (0)
205
206#define EMITBUF(s, l) \
207 do { \
208 int __ret; \
209 if (sb) strbuf_add(sb, (s), (l)); \
210 if (fp) __ret = fwrite((s), (l), 1, fp); \
211 count += (l); \
212 } while (0)
213
214 ssize_t len, count = 0;
215 const char *p = name;
216
217 for (;;) {
218 int ch;
219
220 len = next_quote_pos(p, maxlen);
221 if (len == maxlen || !p[len])
222 break;
223
224 if (!no_dq && p == name)
225 EMIT('"');
226
227 EMITBUF(p, len);
228 EMIT('\\');
229 p += len;
230 ch = (unsigned char)*p++;
231 if (sq_lookup[ch] >= ' ') {
232 EMIT(sq_lookup[ch]);
233 } else {
234 EMIT(((ch >> 6) & 03) + '0');
235 EMIT(((ch >> 3) & 07) + '0');
236 EMIT(((ch >> 0) & 07) + '0');
237 }
238 }
239
240 EMITBUF(p, len);
241 if (p == name) /* no ending quote needed */
242 return 0;
243
244 if (!no_dq)
245 EMIT('"');
246 return count;
247}
248
249size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq)
250{
251 return quote_c_style_counted(name, -1, sb, fp, nodq);
252}
253
254void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, int nodq)
255{
256 if (quote_c_style(prefix, NULL, NULL, 0) ||
257 quote_c_style(path, NULL, NULL, 0)) {
258 if (!nodq)
259 strbuf_addch(sb, '"');
260 quote_c_style(prefix, sb, NULL, 1);
261 quote_c_style(path, sb, NULL, 1);
262 if (!nodq)
263 strbuf_addch(sb, '"');
264 } else {
265 strbuf_addstr(sb, prefix);
266 strbuf_addstr(sb, path);
267 }
268}
269
270void write_name_quoted(const char *name, FILE *fp, int terminator)
271{
272 if (terminator) {
273 quote_c_style(name, NULL, fp, 0);
274 } else {
275 fputs(name, fp);
276 }
277 fputc(terminator, fp);
278}
279
280void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
281 const char *name, FILE *fp, int terminator)
282{
283 int needquote = 0;
284
285 if (terminator) {
286 needquote = next_quote_pos(pfx, pfxlen) < pfxlen
287 || name[next_quote_pos(name, -1)];
288 }
289 if (needquote) {
290 fputc('"', fp);
291 quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
292 quote_c_style(name, NULL, fp, 1);
293 fputc('"', fp);
294 } else {
295 int ret;
296
297 ret = fwrite(pfx, pfxlen, 1, fp);
298 fputs(name, fp);
299 }
300 fputc(terminator, fp);
301}
302
303/* quote path as relative to the given prefix */
304char *quote_path_relative(const char *in, int len,
305 struct strbuf *out, const char *prefix)
306{
307 int needquote;
308
309 if (len < 0)
310 len = strlen(in);
311
312 /* "../" prefix itself does not need quoting, but "in" might. */
313 needquote = (next_quote_pos(in, len) < len);
314 strbuf_setlen(out, 0);
315 strbuf_grow(out, len);
316
317 if (needquote)
318 strbuf_addch(out, '"');
319 if (prefix) {
320 int off = 0;
321 while (off < len && prefix[off] && prefix[off] == in[off])
322 if (prefix[off] == '/') {
323 prefix += off + 1;
324 in += off + 1;
325 len -= off + 1;
326 off = 0;
327 } else
328 off++;
329
330 for (; *prefix; prefix++)
331 if (*prefix == '/')
332 strbuf_addstr(out, "../");
333 }
334
335 quote_c_style_counted (in, len, out, NULL, 1);
336
337 if (needquote)
338 strbuf_addch(out, '"');
339 if (!out->len)
340 strbuf_addstr(out, "./");
341
342 return out->buf;
343}
344
345/*
346 * C-style name unquoting.
347 *
348 * Quoted should point at the opening double quote.
349 * + Returns 0 if it was able to unquote the string properly, and appends the
350 * result in the strbuf `sb'.
351 * + Returns -1 in case of error, and doesn't touch the strbuf. Though note
352 * that this function will allocate memory in the strbuf, so calling
353 * strbuf_release is mandatory whichever result unquote_c_style returns.
354 *
355 * Updates endp pointer to point at one past the ending double quote if given.
356 */
357int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
358{
359 size_t oldlen = sb->len, len;
360 int ch, ac;
361
362 if (*quoted++ != '"')
363 return -1;
364
365 for (;;) {
366 len = strcspn(quoted, "\"\\");
367 strbuf_add(sb, quoted, len);
368 quoted += len;
369
370 switch (*quoted++) {
371 case '"':
372 if (endp)
373 *endp = quoted;
374 return 0;
375 case '\\':
376 break;
377 default:
378 goto error;
379 }
380
381 switch ((ch = *quoted++)) {
382 case 'a': ch = '\a'; break;
383 case 'b': ch = '\b'; break;
384 case 'f': ch = '\f'; break;
385 case 'n': ch = '\n'; break;
386 case 'r': ch = '\r'; break;
387 case 't': ch = '\t'; break;
388 case 'v': ch = '\v'; break;
389
390 case '\\': case '"':
391 break; /* verbatim */
392
393 /* octal values with first digit over 4 overflow */
394 case '0': case '1': case '2': case '3':
395 ac = ((ch - '0') << 6);
396 if ((ch = *quoted++) < '0' || '7' < ch)
397 goto error;
398 ac |= ((ch - '0') << 3);
399 if ((ch = *quoted++) < '0' || '7' < ch)
400 goto error;
401 ac |= (ch - '0');
402 ch = ac;
403 break;
404 default:
405 goto error;
406 }
407 strbuf_addch(sb, ch);
408 }
409
410 error:
411 strbuf_setlen(sb, oldlen);
412 return -1;
413}
414
415/* quoting as a string literal for other languages */
416
417void perl_quote_print(FILE *stream, const char *src)
418{
419 const char sq = '\'';
420 const char bq = '\\';
421 char c;
422
423 fputc(sq, stream);
424 while ((c = *src++)) {
425 if (c == sq || c == bq)
426 fputc(bq, stream);
427 fputc(c, stream);
428 }
429 fputc(sq, stream);
430}
431
432void python_quote_print(FILE *stream, const char *src)
433{
434 const char sq = '\'';
435 const char bq = '\\';
436 const char nl = '\n';
437 char c;
438
439 fputc(sq, stream);
440 while ((c = *src++)) {
441 if (c == nl) {
442 fputc(bq, stream);
443 fputc('n', stream);
444 continue;
445 }
446 if (c == sq || c == bq)
447 fputc(bq, stream);
448 fputc(c, stream);
449 }
450 fputc(sq, stream);
451}
452
453void tcl_quote_print(FILE *stream, const char *src)
454{
455 char c;
456
457 fputc('"', stream);
458 while ((c = *src++)) {
459 switch (c) {
460 case '[': case ']':
461 case '{': case '}':
462 case '$': case '\\': case '"':
463 fputc('\\', stream);
464 default:
465 fputc(c, stream);
466 break;
467 case '\f':
468 fputs("\\f", stream);
469 break;
470 case '\r':
471 fputs("\\r", stream);
472 break;
473 case '\n':
474 fputs("\\n", stream);
475 break;
476 case '\t':
477 fputs("\\t", stream);
478 break;
479 case '\v':
480 fputs("\\v", stream);
481 break;
482 }
483 }
484 fputc('"', stream);
485}
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
new file mode 100644
index 000000000000..a5454a1d1c13
--- /dev/null
+++ b/tools/perf/util/quote.h
@@ -0,0 +1,68 @@
1#ifndef QUOTE_H
2#define QUOTE_H
3
4#include <stddef.h>
5#include <stdio.h>
6
7/* Help to copy the thing properly quoted for the shell safety.
8 * any single quote is replaced with '\'', any exclamation point
9 * is replaced with '\!', and the whole thing is enclosed in a
10 * single quote pair.
11 *
12 * For example, if you are passing the result to system() as an
13 * argument:
14 *
15 * sprintf(cmd, "foobar %s %s", sq_quote(arg0), sq_quote(arg1))
16 *
17 * would be appropriate. If the system() is going to call ssh to
18 * run the command on the other side:
19 *
20 * sprintf(cmd, "git-diff-tree %s %s", sq_quote(arg0), sq_quote(arg1));
21 * sprintf(rcmd, "ssh %s %s", sq_util/quote.host), sq_quote(cmd));
22 *
23 * Note that the above examples leak memory! Remember to free result from
24 * sq_quote() in a real application.
25 *
26 * sq_quote_buf() writes to an existing buffer of specified size; it
27 * will return the number of characters that would have been written
28 * excluding the final null regardless of the buffer size.
29 */
30
31extern void sq_quote_print(FILE *stream, const char *src);
32
33extern void sq_quote_buf(struct strbuf *, const char *src);
34extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
35
36/* This unwraps what sq_quote() produces in place, but returns
37 * NULL if the input does not look like what sq_quote would have
38 * produced.
39 */
40extern char *sq_dequote(char *);
41
42/*
43 * Same as the above, but can be used to unwrap many arguments in the
44 * same string separated by space. "next" is changed to point to the
45 * next argument that should be passed as first parameter. When there
46 * is no more argument to be dequoted, "next" is updated to point to NULL.
47 */
48extern char *sq_dequote_step(char *arg, char **next);
49extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc);
50
51extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp);
52extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq);
53extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
54
55extern void write_name_quoted(const char *name, FILE *, int terminator);
56extern void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
57 const char *name, FILE *, int terminator);
58
59/* quote path as relative to the given prefix */
60char *quote_path_relative(const char *in, int len,
61 struct strbuf *out, const char *prefix);
62
63/* quoting as a string literal for other languages */
64extern void perl_quote_print(FILE *stream, const char *src);
65extern void python_quote_print(FILE *stream, const char *src);
66extern void tcl_quote_print(FILE *stream, const char *src);
67
68#endif
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
new file mode 100644
index 000000000000..a3935343091a
--- /dev/null
+++ b/tools/perf/util/run-command.c
@@ -0,0 +1,304 @@
1#include "cache.h"
2#include "run-command.h"
3#include "exec_cmd.h"
4
5static inline void close_pair(int fd[2])
6{
7 close(fd[0]);
8 close(fd[1]);
9}
10
11static inline void dup_devnull(int to)
12{
13 int fd = open("/dev/null", O_RDWR);
14 dup2(fd, to);
15 close(fd);
16}
17
18int start_command(struct child_process *cmd)
19{
20 int need_in, need_out, need_err;
21 int fdin[2], fdout[2], fderr[2];
22
23 /*
24 * In case of errors we must keep the promise to close FDs
25 * that have been passed in via ->in and ->out.
26 */
27
28 need_in = !cmd->no_stdin && cmd->in < 0;
29 if (need_in) {
30 if (pipe(fdin) < 0) {
31 if (cmd->out > 0)
32 close(cmd->out);
33 return -ERR_RUN_COMMAND_PIPE;
34 }
35 cmd->in = fdin[1];
36 }
37
38 need_out = !cmd->no_stdout
39 && !cmd->stdout_to_stderr
40 && cmd->out < 0;
41 if (need_out) {
42 if (pipe(fdout) < 0) {
43 if (need_in)
44 close_pair(fdin);
45 else if (cmd->in)
46 close(cmd->in);
47 return -ERR_RUN_COMMAND_PIPE;
48 }
49 cmd->out = fdout[0];
50 }
51
52 need_err = !cmd->no_stderr && cmd->err < 0;
53 if (need_err) {
54 if (pipe(fderr) < 0) {
55 if (need_in)
56 close_pair(fdin);
57 else if (cmd->in)
58 close(cmd->in);
59 if (need_out)
60 close_pair(fdout);
61 else if (cmd->out)
62 close(cmd->out);
63 return -ERR_RUN_COMMAND_PIPE;
64 }
65 cmd->err = fderr[0];
66 }
67
68 fflush(NULL);
69 cmd->pid = fork();
70 if (!cmd->pid) {
71 if (cmd->no_stdin)
72 dup_devnull(0);
73 else if (need_in) {
74 dup2(fdin[0], 0);
75 close_pair(fdin);
76 } else if (cmd->in) {
77 dup2(cmd->in, 0);
78 close(cmd->in);
79 }
80
81 if (cmd->no_stderr)
82 dup_devnull(2);
83 else if (need_err) {
84 dup2(fderr[1], 2);
85 close_pair(fderr);
86 }
87
88 if (cmd->no_stdout)
89 dup_devnull(1);
90 else if (cmd->stdout_to_stderr)
91 dup2(2, 1);
92 else if (need_out) {
93 dup2(fdout[1], 1);
94 close_pair(fdout);
95 } else if (cmd->out > 1) {
96 dup2(cmd->out, 1);
97 close(cmd->out);
98 }
99
100 if (cmd->dir && chdir(cmd->dir))
101 die("exec %s: cd to %s failed (%s)", cmd->argv[0],
102 cmd->dir, strerror(errno));
103 if (cmd->env) {
104 for (; *cmd->env; cmd->env++) {
105 if (strchr(*cmd->env, '='))
106 putenv((char*)*cmd->env);
107 else
108 unsetenv(*cmd->env);
109 }
110 }
111 if (cmd->preexec_cb)
112 cmd->preexec_cb();
113 if (cmd->perf_cmd) {
114 execv_perf_cmd(cmd->argv);
115 } else {
116 execvp(cmd->argv[0], (char *const*) cmd->argv);
117 }
118 exit(127);
119 }
120
121 if (cmd->pid < 0) {
122 int err = errno;
123 if (need_in)
124 close_pair(fdin);
125 else if (cmd->in)
126 close(cmd->in);
127 if (need_out)
128 close_pair(fdout);
129 else if (cmd->out)
130 close(cmd->out);
131 if (need_err)
132 close_pair(fderr);
133 return err == ENOENT ?
134 -ERR_RUN_COMMAND_EXEC :
135 -ERR_RUN_COMMAND_FORK;
136 }
137
138 if (need_in)
139 close(fdin[0]);
140 else if (cmd->in)
141 close(cmd->in);
142
143 if (need_out)
144 close(fdout[1]);
145 else if (cmd->out)
146 close(cmd->out);
147
148 if (need_err)
149 close(fderr[1]);
150
151 return 0;
152}
153
154static int wait_or_whine(pid_t pid)
155{
156 for (;;) {
157 int status, code;
158 pid_t waiting = waitpid(pid, &status, 0);
159
160 if (waiting < 0) {
161 if (errno == EINTR)
162 continue;
163 error("waitpid failed (%s)", strerror(errno));
164 return -ERR_RUN_COMMAND_WAITPID;
165 }
166 if (waiting != pid)
167 return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
168 if (WIFSIGNALED(status))
169 return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
170
171 if (!WIFEXITED(status))
172 return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
173 code = WEXITSTATUS(status);
174 switch (code) {
175 case 127:
176 return -ERR_RUN_COMMAND_EXEC;
177 case 0:
178 return 0;
179 default:
180 return -code;
181 }
182 }
183}
184
185int finish_command(struct child_process *cmd)
186{
187 return wait_or_whine(cmd->pid);
188}
189
190int run_command(struct child_process *cmd)
191{
192 int code = start_command(cmd);
193 if (code)
194 return code;
195 return finish_command(cmd);
196}
197
198static void prepare_run_command_v_opt(struct child_process *cmd,
199 const char **argv,
200 int opt)
201{
202 memset(cmd, 0, sizeof(*cmd));
203 cmd->argv = argv;
204 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
205 cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
206 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
207}
208
209int run_command_v_opt(const char **argv, int opt)
210{
211 struct child_process cmd;
212 prepare_run_command_v_opt(&cmd, argv, opt);
213 return run_command(&cmd);
214}
215
216int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
217{
218 struct child_process cmd;
219 prepare_run_command_v_opt(&cmd, argv, opt);
220 cmd.dir = dir;
221 cmd.env = env;
222 return run_command(&cmd);
223}
224
225int start_async(struct async *async)
226{
227 int pipe_out[2];
228
229 if (pipe(pipe_out) < 0)
230 return error("cannot create pipe: %s", strerror(errno));
231 async->out = pipe_out[0];
232
233 /* Flush stdio before fork() to avoid cloning buffers */
234 fflush(NULL);
235
236 async->pid = fork();
237 if (async->pid < 0) {
238 error("fork (async) failed: %s", strerror(errno));
239 close_pair(pipe_out);
240 return -1;
241 }
242 if (!async->pid) {
243 close(pipe_out[0]);
244 exit(!!async->proc(pipe_out[1], async->data));
245 }
246 close(pipe_out[1]);
247
248 return 0;
249}
250
251int finish_async(struct async *async)
252{
253 int ret = 0;
254
255 if (wait_or_whine(async->pid))
256 ret = error("waitpid (async) failed");
257
258 return ret;
259}
260
261int run_hook(const char *index_file, const char *name, ...)
262{
263 struct child_process hook;
264 const char **argv = NULL, *env[2];
265 char index[PATH_MAX];
266 va_list args;
267 int ret;
268 size_t i = 0, alloc = 0;
269
270 if (access(perf_path("hooks/%s", name), X_OK) < 0)
271 return 0;
272
273 va_start(args, name);
274 ALLOC_GROW(argv, i + 1, alloc);
275 argv[i++] = perf_path("hooks/%s", name);
276 while (argv[i-1]) {
277 ALLOC_GROW(argv, i + 1, alloc);
278 argv[i++] = va_arg(args, const char *);
279 }
280 va_end(args);
281
282 memset(&hook, 0, sizeof(hook));
283 hook.argv = argv;
284 hook.no_stdin = 1;
285 hook.stdout_to_stderr = 1;
286 if (index_file) {
287 snprintf(index, sizeof(index), "PERF_INDEX_FILE=%s", index_file);
288 env[0] = index;
289 env[1] = NULL;
290 hook.env = env;
291 }
292
293 ret = start_command(&hook);
294 free(argv);
295 if (ret) {
296 warning("Could not spawn %s", argv[0]);
297 return ret;
298 }
299 ret = finish_command(&hook);
300 if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
301 warning("%s exited due to uncaught signal", argv[0]);
302
303 return ret;
304}
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
new file mode 100644
index 000000000000..cc1837deba88
--- /dev/null
+++ b/tools/perf/util/run-command.h
@@ -0,0 +1,88 @@
1#ifndef RUN_COMMAND_H
2#define RUN_COMMAND_H
3
4enum {
5 ERR_RUN_COMMAND_FORK = 10000,
6 ERR_RUN_COMMAND_EXEC,
7 ERR_RUN_COMMAND_PIPE,
8 ERR_RUN_COMMAND_WAITPID,
9 ERR_RUN_COMMAND_WAITPID_WRONG_PID,
10 ERR_RUN_COMMAND_WAITPID_SIGNAL,
11 ERR_RUN_COMMAND_WAITPID_NOEXIT,
12};
13#define IS_RUN_COMMAND_ERR(x) (-(x) >= ERR_RUN_COMMAND_FORK)
14
15struct child_process {
16 const char **argv;
17 pid_t pid;
18 /*
19 * Using .in, .out, .err:
20 * - Specify 0 for no redirections (child inherits stdin, stdout,
21 * stderr from parent).
22 * - Specify -1 to have a pipe allocated as follows:
23 * .in: returns the writable pipe end; parent writes to it,
24 * the readable pipe end becomes child's stdin
25 * .out, .err: returns the readable pipe end; parent reads from
26 * it, the writable pipe end becomes child's stdout/stderr
27 * The caller of start_command() must close the returned FDs
28 * after it has completed reading from/writing to it!
29 * - Specify > 0 to set a channel to a particular FD as follows:
30 * .in: a readable FD, becomes child's stdin
31 * .out: a writable FD, becomes child's stdout/stderr
32 * .err > 0 not supported
33 * The specified FD is closed by start_command(), even in case
34 * of errors!
35 */
36 int in;
37 int out;
38 int err;
39 const char *dir;
40 const char *const *env;
41 unsigned no_stdin:1;
42 unsigned no_stdout:1;
43 unsigned no_stderr:1;
44 unsigned perf_cmd:1; /* if this is to be perf sub-command */
45 unsigned stdout_to_stderr:1;
46 void (*preexec_cb)(void);
47};
48
49int start_command(struct child_process *);
50int finish_command(struct child_process *);
51int run_command(struct child_process *);
52
53extern int run_hook(const char *index_file, const char *name, ...);
54
55#define RUN_COMMAND_NO_STDIN 1
56#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */
57#define RUN_COMMAND_STDOUT_TO_STDERR 4
58int run_command_v_opt(const char **argv, int opt);
59
60/*
61 * env (the environment) is to be formatted like environ: "VAR=VALUE".
62 * To unset an environment variable use just "VAR".
63 */
64int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env);
65
66/*
67 * The purpose of the following functions is to feed a pipe by running
68 * a function asynchronously and providing output that the caller reads.
69 *
70 * It is expected that no synchronization and mutual exclusion between
71 * the caller and the feed function is necessary so that the function
72 * can run in a thread without interfering with the caller.
73 */
74struct async {
75 /*
76 * proc writes to fd and closes it;
77 * returns 0 on success, non-zero on failure
78 */
79 int (*proc)(int fd, void *data);
80 void *data;
81 int out; /* caller reads from here and closes it */
82 pid_t pid;
83};
84
85int start_async(struct async *async);
86int finish_async(struct async *async);
87
88#endif
diff --git a/tools/perf/util/sigchain.c b/tools/perf/util/sigchain.c
new file mode 100644
index 000000000000..1118b99e57d3
--- /dev/null
+++ b/tools/perf/util/sigchain.c
@@ -0,0 +1,52 @@
1#include "sigchain.h"
2#include "cache.h"
3
4#define SIGCHAIN_MAX_SIGNALS 32
5
6struct sigchain_signal {
7 sigchain_fun *old;
8 int n;
9 int alloc;
10};
11static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS];
12
13static void check_signum(int sig)
14{
15 if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS)
16 die("BUG: signal out of range: %d", sig);
17}
18
19int sigchain_push(int sig, sigchain_fun f)
20{
21 struct sigchain_signal *s = signals + sig;
22 check_signum(sig);
23
24 ALLOC_GROW(s->old, s->n + 1, s->alloc);
25 s->old[s->n] = signal(sig, f);
26 if (s->old[s->n] == SIG_ERR)
27 return -1;
28 s->n++;
29 return 0;
30}
31
32int sigchain_pop(int sig)
33{
34 struct sigchain_signal *s = signals + sig;
35 check_signum(sig);
36 if (s->n < 1)
37 return 0;
38
39 if (signal(sig, s->old[s->n - 1]) == SIG_ERR)
40 return -1;
41 s->n--;
42 return 0;
43}
44
45void sigchain_push_common(sigchain_fun f)
46{
47 sigchain_push(SIGINT, f);
48 sigchain_push(SIGHUP, f);
49 sigchain_push(SIGTERM, f);
50 sigchain_push(SIGQUIT, f);
51 sigchain_push(SIGPIPE, f);
52}
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
new file mode 100644
index 000000000000..618083bce0c6
--- /dev/null
+++ b/tools/perf/util/sigchain.h
@@ -0,0 +1,11 @@
1#ifndef SIGCHAIN_H
2#define SIGCHAIN_H
3
4typedef void (*sigchain_fun)(int);
5
6int sigchain_push(int sig, sigchain_fun f);
7int sigchain_pop(int sig);
8
9void sigchain_push_common(sigchain_fun f);
10
11#endif /* SIGCHAIN_H */
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
new file mode 100644
index 000000000000..5249d5a1b0c2
--- /dev/null
+++ b/tools/perf/util/strbuf.c
@@ -0,0 +1,360 @@
1#include "cache.h"
2
3int prefixcmp(const char *str, const char *prefix)
4{
5 for (; ; str++, prefix++)
6 if (!*prefix)
7 return 0;
8 else if (*str != *prefix)
9 return (unsigned char)*prefix - (unsigned char)*str;
10}
11
12/*
13 * Used as the default ->buf value, so that people can always assume
14 * buf is non NULL and ->buf is NUL terminated even for a freshly
15 * initialized strbuf.
16 */
17char strbuf_slopbuf[1];
18
19void strbuf_init(struct strbuf *sb, ssize_t hint)
20{
21 sb->alloc = sb->len = 0;
22 sb->buf = strbuf_slopbuf;
23 if (hint)
24 strbuf_grow(sb, hint);
25}
26
27void strbuf_release(struct strbuf *sb)
28{
29 if (sb->alloc) {
30 free(sb->buf);
31 strbuf_init(sb, 0);
32 }
33}
34
35char *strbuf_detach(struct strbuf *sb, size_t *sz)
36{
37 char *res = sb->alloc ? sb->buf : NULL;
38 if (sz)
39 *sz = sb->len;
40 strbuf_init(sb, 0);
41 return res;
42}
43
44void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
45{
46 strbuf_release(sb);
47 sb->buf = buf;
48 sb->len = len;
49 sb->alloc = alloc;
50 strbuf_grow(sb, 0);
51 sb->buf[sb->len] = '\0';
52}
53
54void strbuf_grow(struct strbuf *sb, size_t extra)
55{
56 if (sb->len + extra + 1 <= sb->len)
57 die("you want to use way too much memory");
58 if (!sb->alloc)
59 sb->buf = NULL;
60 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
61}
62
63void strbuf_trim(struct strbuf *sb)
64{
65 char *b = sb->buf;
66 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
67 sb->len--;
68 while (sb->len > 0 && isspace(*b)) {
69 b++;
70 sb->len--;
71 }
72 memmove(sb->buf, b, sb->len);
73 sb->buf[sb->len] = '\0';
74}
75void strbuf_rtrim(struct strbuf *sb)
76{
77 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
78 sb->len--;
79 sb->buf[sb->len] = '\0';
80}
81
82void strbuf_ltrim(struct strbuf *sb)
83{
84 char *b = sb->buf;
85 while (sb->len > 0 && isspace(*b)) {
86 b++;
87 sb->len--;
88 }
89 memmove(sb->buf, b, sb->len);
90 sb->buf[sb->len] = '\0';
91}
92
93void strbuf_tolower(struct strbuf *sb)
94{
95 unsigned int i;
96
97 for (i = 0; i < sb->len; i++)
98 sb->buf[i] = tolower(sb->buf[i]);
99}
100
101struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
102{
103 int alloc = 2, pos = 0;
104 char *n, *p;
105 struct strbuf **ret;
106 struct strbuf *t;
107
108 ret = calloc(alloc, sizeof(struct strbuf *));
109 p = n = sb->buf;
110 while (n < sb->buf + sb->len) {
111 int len;
112 n = memchr(n, delim, sb->len - (n - sb->buf));
113 if (pos + 1 >= alloc) {
114 alloc = alloc * 2;
115 ret = realloc(ret, sizeof(struct strbuf *) * alloc);
116 }
117 if (!n)
118 n = sb->buf + sb->len - 1;
119 len = n - p + 1;
120 t = malloc(sizeof(struct strbuf));
121 strbuf_init(t, len);
122 strbuf_add(t, p, len);
123 ret[pos] = t;
124 ret[++pos] = NULL;
125 p = ++n;
126 }
127 return ret;
128}
129
130void strbuf_list_free(struct strbuf **sbs)
131{
132 struct strbuf **s = sbs;
133
134 while (*s) {
135 strbuf_release(*s);
136 free(*s++);
137 }
138 free(sbs);
139}
140
141int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
142{
143 int len = a->len < b->len ? a->len: b->len;
144 int cmp = memcmp(a->buf, b->buf, len);
145 if (cmp)
146 return cmp;
147 return a->len < b->len ? -1: a->len != b->len;
148}
149
150void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
151 const void *data, size_t dlen)
152{
153 if (pos + len < pos)
154 die("you want to use way too much memory");
155 if (pos > sb->len)
156 die("`pos' is too far after the end of the buffer");
157 if (pos + len > sb->len)
158 die("`pos + len' is too far after the end of the buffer");
159
160 if (dlen >= len)
161 strbuf_grow(sb, dlen - len);
162 memmove(sb->buf + pos + dlen,
163 sb->buf + pos + len,
164 sb->len - pos - len);
165 memcpy(sb->buf + pos, data, dlen);
166 strbuf_setlen(sb, sb->len + dlen - len);
167}
168
169void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
170{
171 strbuf_splice(sb, pos, 0, data, len);
172}
173
174void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
175{
176 strbuf_splice(sb, pos, len, NULL, 0);
177}
178
179void strbuf_add(struct strbuf *sb, const void *data, size_t len)
180{
181 strbuf_grow(sb, len);
182 memcpy(sb->buf + sb->len, data, len);
183 strbuf_setlen(sb, sb->len + len);
184}
185
186void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
187{
188 strbuf_grow(sb, len);
189 memcpy(sb->buf + sb->len, sb->buf + pos, len);
190 strbuf_setlen(sb, sb->len + len);
191}
192
193void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
194{
195 int len;
196 va_list ap;
197
198 if (!strbuf_avail(sb))
199 strbuf_grow(sb, 64);
200 va_start(ap, fmt);
201 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
202 va_end(ap);
203 if (len < 0)
204 die("your vsnprintf is broken");
205 if (len > strbuf_avail(sb)) {
206 strbuf_grow(sb, len);
207 va_start(ap, fmt);
208 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
209 va_end(ap);
210 if (len > strbuf_avail(sb)) {
211 die("this should not happen, your snprintf is broken");
212 }
213 }
214 strbuf_setlen(sb, sb->len + len);
215}
216
217void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
218 void *context)
219{
220 for (;;) {
221 const char *percent;
222 size_t consumed;
223
224 percent = strchrnul(format, '%');
225 strbuf_add(sb, format, percent - format);
226 if (!*percent)
227 break;
228 format = percent + 1;
229
230 consumed = fn(sb, format, context);
231 if (consumed)
232 format += consumed;
233 else
234 strbuf_addch(sb, '%');
235 }
236}
237
238size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
239 void *context)
240{
241 struct strbuf_expand_dict_entry *e = context;
242 size_t len;
243
244 for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
245 if (!strncmp(placeholder, e->placeholder, len)) {
246 if (e->value)
247 strbuf_addstr(sb, e->value);
248 return len;
249 }
250 }
251 return 0;
252}
253
254size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
255{
256 size_t res;
257 size_t oldalloc = sb->alloc;
258
259 strbuf_grow(sb, size);
260 res = fread(sb->buf + sb->len, 1, size, f);
261 if (res > 0)
262 strbuf_setlen(sb, sb->len + res);
263 else if (oldalloc == 0)
264 strbuf_release(sb);
265 return res;
266}
267
268ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
269{
270 size_t oldlen = sb->len;
271 size_t oldalloc = sb->alloc;
272
273 strbuf_grow(sb, hint ? hint : 8192);
274 for (;;) {
275 ssize_t cnt;
276
277 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
278 if (cnt < 0) {
279 if (oldalloc == 0)
280 strbuf_release(sb);
281 else
282 strbuf_setlen(sb, oldlen);
283 return -1;
284 }
285 if (!cnt)
286 break;
287 sb->len += cnt;
288 strbuf_grow(sb, 8192);
289 }
290
291 sb->buf[sb->len] = '\0';
292 return sb->len - oldlen;
293}
294
295#define STRBUF_MAXLINK (2*PATH_MAX)
296
297int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint)
298{
299 size_t oldalloc = sb->alloc;
300
301 if (hint < 32)
302 hint = 32;
303
304 while (hint < STRBUF_MAXLINK) {
305 ssize_t len;
306
307 strbuf_grow(sb, hint);
308 len = readlink(path, sb->buf, hint);
309 if (len < 0) {
310 if (errno != ERANGE)
311 break;
312 } else if (len < hint) {
313 strbuf_setlen(sb, len);
314 return 0;
315 }
316
317 /* .. the buffer was too small - try again */
318 hint *= 2;
319 }
320 if (oldalloc == 0)
321 strbuf_release(sb);
322 return -1;
323}
324
325int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
326{
327 int ch;
328
329 strbuf_grow(sb, 0);
330 if (feof(fp))
331 return EOF;
332
333 strbuf_reset(sb);
334 while ((ch = fgetc(fp)) != EOF) {
335 if (ch == term)
336 break;
337 strbuf_grow(sb, 1);
338 sb->buf[sb->len++] = ch;
339 }
340 if (ch == EOF && sb->len == 0)
341 return EOF;
342
343 sb->buf[sb->len] = '\0';
344 return 0;
345}
346
347int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint)
348{
349 int fd, len;
350
351 fd = open(path, O_RDONLY);
352 if (fd < 0)
353 return -1;
354 len = strbuf_read(sb, fd, hint);
355 close(fd);
356 if (len < 0)
357 return -1;
358
359 return len;
360}
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
new file mode 100644
index 000000000000..d2aa86c014c1
--- /dev/null
+++ b/tools/perf/util/strbuf.h
@@ -0,0 +1,137 @@
1#ifndef STRBUF_H
2#define STRBUF_H
3
4/*
5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
6 * long, overflow safe strings.
7 *
8 * Strbufs has some invariants that are very important to keep in mind:
9 *
10 * 1. the ->buf member is always malloc-ed, hence strbuf's can be used to
11 * build complex strings/buffers whose final size isn't easily known.
12 *
13 * It is NOT legal to copy the ->buf pointer away.
14 * `strbuf_detach' is the operation that detachs a buffer from its shell
15 * while keeping the shell valid wrt its invariants.
16 *
17 * 2. the ->buf member is a byte array that has at least ->len + 1 bytes
18 * allocated. The extra byte is used to store a '\0', allowing the ->buf
19 * member to be a valid C-string. Every strbuf function ensure this
20 * invariant is preserved.
21 *
22 * Note that it is OK to "play" with the buffer directly if you work it
23 * that way:
24 *
25 * strbuf_grow(sb, SOME_SIZE);
26 * ... Here, the memory array starting at sb->buf, and of length
27 * ... strbuf_avail(sb) is all yours, and you are sure that
28 * ... strbuf_avail(sb) is at least SOME_SIZE.
29 * strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
30 *
31 * Of course, SOME_OTHER_SIZE must be smaller or equal to strbuf_avail(sb).
32 *
33 * Doing so is safe, though if it has to be done in many places, adding the
34 * missing API to the strbuf module is the way to go.
35 *
36 * XXX: do _not_ assume that the area that is yours is of size ->alloc - 1
37 * even if it's true in the current implementation. Alloc is somehow a
38 * "private" member that should not be messed with.
39 */
40
41#include <assert.h>
42
43extern char strbuf_slopbuf[];
44struct strbuf {
45 size_t alloc;
46 size_t len;
47 char *buf;
48};
49
50#define STRBUF_INIT { 0, 0, strbuf_slopbuf }
51
52/*----- strbuf life cycle -----*/
53extern void strbuf_init(struct strbuf *buf, ssize_t hint);
54extern void strbuf_release(struct strbuf *);
55extern char *strbuf_detach(struct strbuf *, size_t *);
56extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
57static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
58 struct strbuf tmp = *a;
59 *a = *b;
60 *b = tmp;
61}
62
63/*----- strbuf size related -----*/
64static inline ssize_t strbuf_avail(const struct strbuf *sb) {
65 return sb->alloc ? sb->alloc - sb->len - 1 : 0;
66}
67
68extern void strbuf_grow(struct strbuf *, size_t);
69
70static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
71 if (!sb->alloc)
72 strbuf_grow(sb, 0);
73 assert(len < sb->alloc);
74 sb->len = len;
75 sb->buf[len] = '\0';
76}
77#define strbuf_reset(sb) strbuf_setlen(sb, 0)
78
79/*----- content related -----*/
80extern void strbuf_trim(struct strbuf *);
81extern void strbuf_rtrim(struct strbuf *);
82extern void strbuf_ltrim(struct strbuf *);
83extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
84extern void strbuf_tolower(struct strbuf *);
85
86extern struct strbuf **strbuf_split(const struct strbuf *, int delim);
87extern void strbuf_list_free(struct strbuf **);
88
89/*----- add data in your buffer -----*/
90static inline void strbuf_addch(struct strbuf *sb, int c) {
91 strbuf_grow(sb, 1);
92 sb->buf[sb->len++] = c;
93 sb->buf[sb->len] = '\0';
94}
95
96extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t);
97extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
98
99/* splice pos..pos+len with given data */
100extern void strbuf_splice(struct strbuf *, size_t pos, size_t len,
101 const void *, size_t);
102
103extern void strbuf_add(struct strbuf *, const void *, size_t);
104static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
105 strbuf_add(sb, s, strlen(s));
106}
107static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) {
108 strbuf_add(sb, sb2->buf, sb2->len);
109}
110extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
111
112typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
113extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
114struct strbuf_expand_dict_entry {
115 const char *placeholder;
116 const char *value;
117};
118extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);
119
120__attribute__((format(printf,2,3)))
121extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
122
123extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
124/* XXX: if read fails, any partial read is undone */
125extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
126extern int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint);
127extern int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint);
128
129extern int strbuf_getline(struct strbuf *, FILE *, int);
130
131extern void stripspace(struct strbuf *buf, int skip_comments);
132extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
133
134extern int strbuf_branchname(struct strbuf *sb, const char *name);
135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
136
137#endif /* STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
new file mode 100644
index 000000000000..c93eca9a7be3
--- /dev/null
+++ b/tools/perf/util/string.c
@@ -0,0 +1,34 @@
1#include "string.h"
2
3static int hex(char ch)
4{
5 if ((ch >= '0') && (ch <= '9'))
6 return ch - '0';
7 if ((ch >= 'a') && (ch <= 'f'))
8 return ch - 'a' + 10;
9 if ((ch >= 'A') && (ch <= 'F'))
10 return ch - 'A' + 10;
11 return -1;
12}
13
14/*
15 * While we find nice hex chars, build a long_val.
16 * Return number of chars processed.
17 */
18int hex2u64(const char *ptr, u64 *long_val)
19{
20 const char *p = ptr;
21 *long_val = 0;
22
23 while (*p) {
24 const int hex_val = hex(*p);
25
26 if (hex_val < 0)
27 break;
28
29 *long_val = (*long_val << 4) | hex_val;
30 p++;
31 }
32
33 return p - ptr;
34}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
new file mode 100644
index 000000000000..bf39dfadfd24
--- /dev/null
+++ b/tools/perf/util/string.h
@@ -0,0 +1,11 @@
1#ifndef _PERF_STRING_H_
2#define _PERF_STRING_H_
3
4#include "types.h"
5
6int hex2u64(const char *ptr, u64 *val);
7
8#define _STR(x) #x
9#define STR(x) _STR(x)
10
11#endif
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
new file mode 100644
index 000000000000..7ad38171dc2b
--- /dev/null
+++ b/tools/perf/util/strlist.c
@@ -0,0 +1,200 @@
1/*
2 * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Licensed under the GPLv2.
5 */
6
7#include "strlist.h"
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13static struct str_node *str_node__new(const char *s, bool dupstr)
14{
15 struct str_node *self = malloc(sizeof(*self));
16
17 if (self != NULL) {
18 if (dupstr) {
19 s = strdup(s);
20 if (s == NULL)
21 goto out_delete;
22 }
23 self->s = s;
24 }
25
26 return self;
27
28out_delete:
29 free(self);
30 return NULL;
31}
32
33static void str_node__delete(struct str_node *self, bool dupstr)
34{
35 if (dupstr)
36 free((void *)self->s);
37 free(self);
38}
39
40int strlist__add(struct strlist *self, const char *new_entry)
41{
42 struct rb_node **p = &self->entries.rb_node;
43 struct rb_node *parent = NULL;
44 struct str_node *sn;
45
46 while (*p != NULL) {
47 int rc;
48
49 parent = *p;
50 sn = rb_entry(parent, struct str_node, rb_node);
51 rc = strcmp(sn->s, new_entry);
52
53 if (rc > 0)
54 p = &(*p)->rb_left;
55 else if (rc < 0)
56 p = &(*p)->rb_right;
57 else
58 return -EEXIST;
59 }
60
61 sn = str_node__new(new_entry, self->dupstr);
62 if (sn == NULL)
63 return -ENOMEM;
64
65 rb_link_node(&sn->rb_node, parent, p);
66 rb_insert_color(&sn->rb_node, &self->entries);
67 ++self->nr_entries;
68
69 return 0;
70}
71
72int strlist__load(struct strlist *self, const char *filename)
73{
74 char entry[1024];
75 int err;
76 FILE *fp = fopen(filename, "r");
77
78 if (fp == NULL)
79 return errno;
80
81 while (fgets(entry, sizeof(entry), fp) != NULL) {
82 const size_t len = strlen(entry);
83
84 if (len == 0)
85 continue;
86 entry[len - 1] = '\0';
87
88 err = strlist__add(self, entry);
89 if (err != 0)
90 goto out;
91 }
92
93 err = 0;
94out:
95 fclose(fp);
96 return err;
97}
98
99void strlist__remove(struct strlist *self, struct str_node *sn)
100{
101 rb_erase(&sn->rb_node, &self->entries);
102 str_node__delete(sn, self->dupstr);
103}
104
105bool strlist__has_entry(struct strlist *self, const char *entry)
106{
107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL;
109
110 while (*p != NULL) {
111 struct str_node *sn;
112 int rc;
113
114 parent = *p;
115 sn = rb_entry(parent, struct str_node, rb_node);
116 rc = strcmp(sn->s, entry);
117
118 if (rc > 0)
119 p = &(*p)->rb_left;
120 else if (rc < 0)
121 p = &(*p)->rb_right;
122 else
123 return true;
124 }
125
126 return false;
127}
128
129static int strlist__parse_list_entry(struct strlist *self, const char *s)
130{
131 if (strncmp(s, "file://", 7) == 0)
132 return strlist__load(self, s + 7);
133
134 return strlist__add(self, s);
135}
136
137int strlist__parse_list(struct strlist *self, const char *s)
138{
139 char *sep;
140 int err;
141
142 while ((sep = strchr(s, ',')) != NULL) {
143 *sep = '\0';
144 err = strlist__parse_list_entry(self, s);
145 *sep = ',';
146 if (err != 0)
147 return err;
148 s = sep + 1;
149 }
150
151 return *s ? strlist__parse_list_entry(self, s) : 0;
152}
153
154struct strlist *strlist__new(bool dupstr, const char *slist)
155{
156 struct strlist *self = malloc(sizeof(*self));
157
158 if (self != NULL) {
159 self->entries = RB_ROOT;
160 self->dupstr = dupstr;
161 self->nr_entries = 0;
162 if (slist && strlist__parse_list(self, slist) != 0)
163 goto out_error;
164 }
165
166 return self;
167out_error:
168 free(self);
169 return NULL;
170}
171
172void strlist__delete(struct strlist *self)
173{
174 if (self != NULL) {
175 struct str_node *pos;
176 struct rb_node *next = rb_first(&self->entries);
177
178 while (next) {
179 pos = rb_entry(next, struct str_node, rb_node);
180 next = rb_next(&pos->rb_node);
181 strlist__remove(self, pos);
182 }
183 self->entries = RB_ROOT;
184 free(self);
185 }
186}
187
188struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
189{
190 struct rb_node *nd;
191
192 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
193 struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
194
195 if (!idx--)
196 return pos;
197 }
198
199 return NULL;
200}
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
new file mode 100644
index 000000000000..921818e44a54
--- /dev/null
+++ b/tools/perf/util/strlist.h
@@ -0,0 +1,39 @@
1#ifndef STRLIST_H_
2#define STRLIST_H_
3
4#include <linux/rbtree.h>
5#include <stdbool.h>
6
7struct str_node {
8 struct rb_node rb_node;
9 const char *s;
10};
11
12struct strlist {
13 struct rb_root entries;
14 unsigned int nr_entries;
15 bool dupstr;
16};
17
18struct strlist *strlist__new(bool dupstr, const char *slist);
19void strlist__delete(struct strlist *self);
20
21void strlist__remove(struct strlist *self, struct str_node *sn);
22int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str);
24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry);
27
28static inline bool strlist__empty(const struct strlist *self)
29{
30 return self->nr_entries == 0;
31}
32
33static inline unsigned int strlist__nr_entries(const struct strlist *self)
34{
35 return self->nr_entries;
36}
37
38int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* STRLIST_H_ */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
new file mode 100644
index 000000000000..5c0f42e6b33b
--- /dev/null
+++ b/tools/perf/util/symbol.c
@@ -0,0 +1,930 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "symbol.h"
5
6#include <libelf.h>
7#include <gelf.h>
8#include <elf.h>
9
10const char *sym_hist_filter;
11
12enum dso_origin {
13 DSO__ORIG_KERNEL = 0,
14 DSO__ORIG_JAVA_JIT,
15 DSO__ORIG_FEDORA,
16 DSO__ORIG_UBUNTU,
17 DSO__ORIG_BUILDID,
18 DSO__ORIG_DSO,
19 DSO__ORIG_NOT_FOUND,
20};
21
22static struct symbol *symbol__new(u64 start, u64 len,
23 const char *name, unsigned int priv_size,
24 u64 obj_start, int verbose)
25{
26 size_t namelen = strlen(name) + 1;
27 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
28
29 if (!self)
30 return NULL;
31
32 if (verbose >= 2)
33 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
34 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
35
36 self->obj_start= obj_start;
37 self->hist = NULL;
38 self->hist_sum = 0;
39
40 if (sym_hist_filter && !strcmp(name, sym_hist_filter))
41 self->hist = calloc(sizeof(u64), len);
42
43 if (priv_size) {
44 memset(self, 0, priv_size);
45 self = ((void *)self) + priv_size;
46 }
47 self->start = start;
48 self->end = len ? start + len - 1 : start;
49 memcpy(self->name, name, namelen);
50
51 return self;
52}
53
54static void symbol__delete(struct symbol *self, unsigned int priv_size)
55{
56 free(((void *)self) - priv_size);
57}
58
59static size_t symbol__fprintf(struct symbol *self, FILE *fp)
60{
61 if (!self->module)
62 return fprintf(fp, " %llx-%llx %s\n",
63 self->start, self->end, self->name);
64 else
65 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
66 self->start, self->end, self->name, self->module->name);
67}
68
69struct dso *dso__new(const char *name, unsigned int sym_priv_size)
70{
71 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
72
73 if (self != NULL) {
74 strcpy(self->name, name);
75 self->syms = RB_ROOT;
76 self->sym_priv_size = sym_priv_size;
77 self->find_symbol = dso__find_symbol;
78 self->slen_calculated = 0;
79 self->origin = DSO__ORIG_NOT_FOUND;
80 }
81
82 return self;
83}
84
85static void dso__delete_symbols(struct dso *self)
86{
87 struct symbol *pos;
88 struct rb_node *next = rb_first(&self->syms);
89
90 while (next) {
91 pos = rb_entry(next, struct symbol, rb_node);
92 next = rb_next(&pos->rb_node);
93 rb_erase(&pos->rb_node, &self->syms);
94 symbol__delete(pos, self->sym_priv_size);
95 }
96}
97
98void dso__delete(struct dso *self)
99{
100 dso__delete_symbols(self);
101 free(self);
102}
103
104static void dso__insert_symbol(struct dso *self, struct symbol *sym)
105{
106 struct rb_node **p = &self->syms.rb_node;
107 struct rb_node *parent = NULL;
108 const u64 ip = sym->start;
109 struct symbol *s;
110
111 while (*p != NULL) {
112 parent = *p;
113 s = rb_entry(parent, struct symbol, rb_node);
114 if (ip < s->start)
115 p = &(*p)->rb_left;
116 else
117 p = &(*p)->rb_right;
118 }
119 rb_link_node(&sym->rb_node, parent, p);
120 rb_insert_color(&sym->rb_node, &self->syms);
121}
122
123struct symbol *dso__find_symbol(struct dso *self, u64 ip)
124{
125 struct rb_node *n;
126
127 if (self == NULL)
128 return NULL;
129
130 n = self->syms.rb_node;
131
132 while (n) {
133 struct symbol *s = rb_entry(n, struct symbol, rb_node);
134
135 if (ip < s->start)
136 n = n->rb_left;
137 else if (ip > s->end)
138 n = n->rb_right;
139 else
140 return s;
141 }
142
143 return NULL;
144}
145
146size_t dso__fprintf(struct dso *self, FILE *fp)
147{
148 size_t ret = fprintf(fp, "dso: %s\n", self->name);
149
150 struct rb_node *nd;
151 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
152 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
153 ret += symbol__fprintf(pos, fp);
154 }
155
156 return ret;
157}
158
159static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
160{
161 struct rb_node *nd, *prevnd;
162 char *line = NULL;
163 size_t n;
164 FILE *file = fopen("/proc/kallsyms", "r");
165 int count = 0;
166
167 if (file == NULL)
168 goto out_failure;
169
170 while (!feof(file)) {
171 u64 start;
172 struct symbol *sym;
173 int line_len, len;
174 char symbol_type;
175
176 line_len = getline(&line, &n, file);
177 if (line_len < 0)
178 break;
179
180 if (!line)
181 goto out_failure;
182
183 line[--line_len] = '\0'; /* \n */
184
185 len = hex2u64(line, &start);
186
187 len++;
188 if (len + 2 >= line_len)
189 continue;
190
191 symbol_type = toupper(line[len]);
192 /*
193 * We're interested only in code ('T'ext)
194 */
195 if (symbol_type != 'T' && symbol_type != 'W')
196 continue;
197 /*
198 * Well fix up the end later, when we have all sorted.
199 */
200 sym = symbol__new(start, 0xdead, line + len + 2,
201 self->sym_priv_size, 0, verbose);
202
203 if (sym == NULL)
204 goto out_delete_line;
205
206 if (filter && filter(self, sym))
207 symbol__delete(sym, self->sym_priv_size);
208 else {
209 dso__insert_symbol(self, sym);
210 count++;
211 }
212 }
213
214 /*
215 * Now that we have all sorted out, just set the ->end of all
216 * symbols
217 */
218 prevnd = rb_first(&self->syms);
219
220 if (prevnd == NULL)
221 goto out_delete_line;
222
223 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
224 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
225 *curr = rb_entry(nd, struct symbol, rb_node);
226
227 prev->end = curr->start - 1;
228 prevnd = nd;
229 }
230
231 free(line);
232 fclose(file);
233
234 return count;
235
236out_delete_line:
237 free(line);
238out_failure:
239 return -1;
240}
241
242static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose)
243{
244 char *line = NULL;
245 size_t n;
246 FILE *file;
247 int nr_syms = 0;
248
249 file = fopen(self->name, "r");
250 if (file == NULL)
251 goto out_failure;
252
253 while (!feof(file)) {
254 u64 start, size;
255 struct symbol *sym;
256 int line_len, len;
257
258 line_len = getline(&line, &n, file);
259 if (line_len < 0)
260 break;
261
262 if (!line)
263 goto out_failure;
264
265 line[--line_len] = '\0'; /* \n */
266
267 len = hex2u64(line, &start);
268
269 len++;
270 if (len + 2 >= line_len)
271 continue;
272
273 len += hex2u64(line + len, &size);
274
275 len++;
276 if (len + 2 >= line_len)
277 continue;
278
279 sym = symbol__new(start, size, line + len,
280 self->sym_priv_size, start, verbose);
281
282 if (sym == NULL)
283 goto out_delete_line;
284
285 if (filter && filter(self, sym))
286 symbol__delete(sym, self->sym_priv_size);
287 else {
288 dso__insert_symbol(self, sym);
289 nr_syms++;
290 }
291 }
292
293 free(line);
294 fclose(file);
295
296 return nr_syms;
297
298out_delete_line:
299 free(line);
300out_failure:
301 return -1;
302}
303
304/**
305 * elf_symtab__for_each_symbol - iterate thru all the symbols
306 *
307 * @self: struct elf_symtab instance to iterate
308 * @index: uint32_t index
309 * @sym: GElf_Sym iterator
310 */
311#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
312 for (index = 0, gelf_getsym(syms, index, &sym);\
313 index < nr_syms; \
314 index++, gelf_getsym(syms, index, &sym))
315
316static inline uint8_t elf_sym__type(const GElf_Sym *sym)
317{
318 return GELF_ST_TYPE(sym->st_info);
319}
320
321static inline int elf_sym__is_function(const GElf_Sym *sym)
322{
323 return elf_sym__type(sym) == STT_FUNC &&
324 sym->st_name != 0 &&
325 sym->st_shndx != SHN_UNDEF &&
326 sym->st_size != 0;
327}
328
329static inline int elf_sym__is_label(const GElf_Sym *sym)
330{
331 return elf_sym__type(sym) == STT_NOTYPE &&
332 sym->st_name != 0 &&
333 sym->st_shndx != SHN_UNDEF &&
334 sym->st_shndx != SHN_ABS;
335}
336
337static inline const char *elf_sec__name(const GElf_Shdr *shdr,
338 const Elf_Data *secstrs)
339{
340 return secstrs->d_buf + shdr->sh_name;
341}
342
343static inline int elf_sec__is_text(const GElf_Shdr *shdr,
344 const Elf_Data *secstrs)
345{
346 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
347}
348
349static inline const char *elf_sym__name(const GElf_Sym *sym,
350 const Elf_Data *symstrs)
351{
352 return symstrs->d_buf + sym->st_name;
353}
354
355static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
356 GElf_Shdr *shp, const char *name,
357 size_t *index)
358{
359 Elf_Scn *sec = NULL;
360 size_t cnt = 1;
361
362 while ((sec = elf_nextscn(elf, sec)) != NULL) {
363 char *str;
364
365 gelf_getshdr(sec, shp);
366 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
367 if (!strcmp(name, str)) {
368 if (index)
369 *index = cnt;
370 break;
371 }
372 ++cnt;
373 }
374
375 return sec;
376}
377
378#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
379 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
380 idx < nr_entries; \
381 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
382
383#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
384 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
385 idx < nr_entries; \
386 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
387
388/*
389 * We need to check if we have a .dynsym, so that we can handle the
390 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
391 * .dynsym or .symtab).
392 * And always look at the original dso, not at debuginfo packages, that
393 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
394 */
395static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
396{
397 uint32_t nr_rel_entries, idx;
398 GElf_Sym sym;
399 u64 plt_offset;
400 GElf_Shdr shdr_plt;
401 struct symbol *f;
402 GElf_Shdr shdr_rel_plt, shdr_dynsym;
403 Elf_Data *reldata, *syms, *symstrs;
404 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
405 size_t dynsym_idx;
406 GElf_Ehdr ehdr;
407 char sympltname[1024];
408 Elf *elf;
409 int nr = 0, symidx, fd, err = 0;
410
411 fd = open(self->name, O_RDONLY);
412 if (fd < 0)
413 goto out;
414
415 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
416 if (elf == NULL)
417 goto out_close;
418
419 if (gelf_getehdr(elf, &ehdr) == NULL)
420 goto out_elf_end;
421
422 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
423 ".dynsym", &dynsym_idx);
424 if (scn_dynsym == NULL)
425 goto out_elf_end;
426
427 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
428 ".rela.plt", NULL);
429 if (scn_plt_rel == NULL) {
430 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
431 ".rel.plt", NULL);
432 if (scn_plt_rel == NULL)
433 goto out_elf_end;
434 }
435
436 err = -1;
437
438 if (shdr_rel_plt.sh_link != dynsym_idx)
439 goto out_elf_end;
440
441 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
442 goto out_elf_end;
443
444 /*
445 * Fetch the relocation section to find the indexes to the GOT
446 * and the symbols in the .dynsym they refer to.
447 */
448 reldata = elf_getdata(scn_plt_rel, NULL);
449 if (reldata == NULL)
450 goto out_elf_end;
451
452 syms = elf_getdata(scn_dynsym, NULL);
453 if (syms == NULL)
454 goto out_elf_end;
455
456 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
457 if (scn_symstrs == NULL)
458 goto out_elf_end;
459
460 symstrs = elf_getdata(scn_symstrs, NULL);
461 if (symstrs == NULL)
462 goto out_elf_end;
463
464 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
465 plt_offset = shdr_plt.sh_offset;
466
467 if (shdr_rel_plt.sh_type == SHT_RELA) {
468 GElf_Rela pos_mem, *pos;
469
470 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
471 nr_rel_entries) {
472 symidx = GELF_R_SYM(pos->r_info);
473 plt_offset += shdr_plt.sh_entsize;
474 gelf_getsym(syms, symidx, &sym);
475 snprintf(sympltname, sizeof(sympltname),
476 "%s@plt", elf_sym__name(&sym, symstrs));
477
478 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
479 sympltname, self->sym_priv_size, 0, verbose);
480 if (!f)
481 goto out_elf_end;
482
483 dso__insert_symbol(self, f);
484 ++nr;
485 }
486 } else if (shdr_rel_plt.sh_type == SHT_REL) {
487 GElf_Rel pos_mem, *pos;
488 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
489 nr_rel_entries) {
490 symidx = GELF_R_SYM(pos->r_info);
491 plt_offset += shdr_plt.sh_entsize;
492 gelf_getsym(syms, symidx, &sym);
493 snprintf(sympltname, sizeof(sympltname),
494 "%s@plt", elf_sym__name(&sym, symstrs));
495
496 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
497 sympltname, self->sym_priv_size, 0, verbose);
498 if (!f)
499 goto out_elf_end;
500
501 dso__insert_symbol(self, f);
502 ++nr;
503 }
504 }
505
506 err = 0;
507out_elf_end:
508 elf_end(elf);
509out_close:
510 close(fd);
511
512 if (err == 0)
513 return nr;
514out:
515 fprintf(stderr, "%s: problems reading %s PLT info.\n",
516 __func__, self->name);
517 return 0;
518}
519
520static int dso__load_sym(struct dso *self, int fd, const char *name,
521 symbol_filter_t filter, int verbose, struct module *mod)
522{
523 Elf_Data *symstrs, *secstrs;
524 uint32_t nr_syms;
525 int err = -1;
526 uint32_t index;
527 GElf_Ehdr ehdr;
528 GElf_Shdr shdr;
529 Elf_Data *syms;
530 GElf_Sym sym;
531 Elf_Scn *sec, *sec_strndx;
532 Elf *elf;
533 int nr = 0, kernel = !strcmp("[kernel]", self->name);
534
535 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
536 if (elf == NULL) {
537 if (verbose)
538 fprintf(stderr, "%s: cannot read %s ELF file.\n",
539 __func__, name);
540 goto out_close;
541 }
542
543 if (gelf_getehdr(elf, &ehdr) == NULL) {
544 if (verbose)
545 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
546 goto out_elf_end;
547 }
548
549 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
550 if (sec == NULL) {
551 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
552 if (sec == NULL)
553 goto out_elf_end;
554 }
555
556 syms = elf_getdata(sec, NULL);
557 if (syms == NULL)
558 goto out_elf_end;
559
560 sec = elf_getscn(elf, shdr.sh_link);
561 if (sec == NULL)
562 goto out_elf_end;
563
564 symstrs = elf_getdata(sec, NULL);
565 if (symstrs == NULL)
566 goto out_elf_end;
567
568 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
569 if (sec_strndx == NULL)
570 goto out_elf_end;
571
572 secstrs = elf_getdata(sec_strndx, NULL);
573 if (secstrs == NULL)
574 goto out_elf_end;
575
576 nr_syms = shdr.sh_size / shdr.sh_entsize;
577
578 memset(&sym, 0, sizeof(sym));
579 if (!kernel) {
580 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
581 elf_section_by_name(elf, &ehdr, &shdr,
582 ".gnu.prelink_undo",
583 NULL) != NULL);
584 } else self->adjust_symbols = 0;
585
586 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
587 struct symbol *f;
588 const char *name;
589 char *demangled;
590 u64 obj_start;
591 struct section *section = NULL;
592 int is_label = elf_sym__is_label(&sym);
593 const char *section_name;
594
595 if (!is_label && !elf_sym__is_function(&sym))
596 continue;
597
598 sec = elf_getscn(elf, sym.st_shndx);
599 if (!sec)
600 goto out_elf_end;
601
602 gelf_getshdr(sec, &shdr);
603
604 if (is_label && !elf_sec__is_text(&shdr, secstrs))
605 continue;
606
607 section_name = elf_sec__name(&shdr, secstrs);
608 obj_start = sym.st_value;
609
610 if (self->adjust_symbols) {
611 if (verbose >= 2)
612 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
613 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
614
615 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
616 }
617
618 if (mod) {
619 section = mod->sections->find_section(mod->sections, section_name);
620 if (section)
621 sym.st_value += section->vma;
622 else {
623 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
624 mod->name, section_name);
625 goto out_elf_end;
626 }
627 }
628 /*
629 * We need to figure out if the object was created from C++ sources
630 * DWARF DW_compile_unit has this, but we don't always have access
631 * to it...
632 */
633 name = elf_sym__name(&sym, symstrs);
634 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
635 if (demangled != NULL)
636 name = demangled;
637
638 f = symbol__new(sym.st_value, sym.st_size, name,
639 self->sym_priv_size, obj_start, verbose);
640 free(demangled);
641 if (!f)
642 goto out_elf_end;
643
644 if (filter && filter(self, f))
645 symbol__delete(f, self->sym_priv_size);
646 else {
647 f->module = mod;
648 dso__insert_symbol(self, f);
649 nr++;
650 }
651 }
652
653 err = nr;
654out_elf_end:
655 elf_end(elf);
656out_close:
657 return err;
658}
659
660#define BUILD_ID_SIZE 128
661
662static char *dso__read_build_id(struct dso *self, int verbose)
663{
664 int i;
665 GElf_Ehdr ehdr;
666 GElf_Shdr shdr;
667 Elf_Data *build_id_data;
668 Elf_Scn *sec;
669 char *build_id = NULL, *bid;
670 unsigned char *raw;
671 Elf *elf;
672 int fd = open(self->name, O_RDONLY);
673
674 if (fd < 0)
675 goto out;
676
677 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
678 if (elf == NULL) {
679 if (verbose)
680 fprintf(stderr, "%s: cannot read %s ELF file.\n",
681 __func__, self->name);
682 goto out_close;
683 }
684
685 if (gelf_getehdr(elf, &ehdr) == NULL) {
686 if (verbose)
687 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
688 goto out_elf_end;
689 }
690
691 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
692 if (sec == NULL)
693 goto out_elf_end;
694
695 build_id_data = elf_getdata(sec, NULL);
696 if (build_id_data == NULL)
697 goto out_elf_end;
698 build_id = malloc(BUILD_ID_SIZE);
699 if (build_id == NULL)
700 goto out_elf_end;
701 raw = build_id_data->d_buf + 16;
702 bid = build_id;
703
704 for (i = 0; i < 20; ++i) {
705 sprintf(bid, "%02x", *raw);
706 ++raw;
707 bid += 2;
708 }
709 if (verbose >= 2)
710 printf("%s(%s): %s\n", __func__, self->name, build_id);
711out_elf_end:
712 elf_end(elf);
713out_close:
714 close(fd);
715out:
716 return build_id;
717}
718
719char dso__symtab_origin(const struct dso *self)
720{
721 static const char origin[] = {
722 [DSO__ORIG_KERNEL] = 'k',
723 [DSO__ORIG_JAVA_JIT] = 'j',
724 [DSO__ORIG_FEDORA] = 'f',
725 [DSO__ORIG_UBUNTU] = 'u',
726 [DSO__ORIG_BUILDID] = 'b',
727 [DSO__ORIG_DSO] = 'd',
728 };
729
730 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
731 return '!';
732 return origin[self->origin];
733}
734
735int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
736{
737 int size = PATH_MAX;
738 char *name = malloc(size), *build_id = NULL;
739 int ret = -1;
740 int fd;
741
742 if (!name)
743 return -1;
744
745 self->adjust_symbols = 0;
746
747 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
748 ret = dso__load_perf_map(self, filter, verbose);
749 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
750 DSO__ORIG_NOT_FOUND;
751 return ret;
752 }
753
754 self->origin = DSO__ORIG_FEDORA - 1;
755
756more:
757 do {
758 self->origin++;
759 switch (self->origin) {
760 case DSO__ORIG_FEDORA:
761 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
762 break;
763 case DSO__ORIG_UBUNTU:
764 snprintf(name, size, "/usr/lib/debug%s", self->name);
765 break;
766 case DSO__ORIG_BUILDID:
767 build_id = dso__read_build_id(self, verbose);
768 if (build_id != NULL) {
769 snprintf(name, size,
770 "/usr/lib/debug/.build-id/%.2s/%s.debug",
771 build_id, build_id + 2);
772 free(build_id);
773 break;
774 }
775 self->origin++;
776 /* Fall thru */
777 case DSO__ORIG_DSO:
778 snprintf(name, size, "%s", self->name);
779 break;
780
781 default:
782 goto out;
783 }
784
785 fd = open(name, O_RDONLY);
786 } while (fd < 0);
787
788 ret = dso__load_sym(self, fd, name, filter, verbose, NULL);
789 close(fd);
790
791 /*
792 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
793 */
794 if (!ret)
795 goto more;
796
797 if (ret > 0) {
798 int nr_plt = dso__synthesize_plt_symbols(self, verbose);
799 if (nr_plt > 0)
800 ret += nr_plt;
801 }
802out:
803 free(name);
804 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
805 return 0;
806 return ret;
807}
808
809static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
810 symbol_filter_t filter, int verbose)
811{
812 struct module *mod = mod_dso__find_module(mods, name);
813 int err = 0, fd;
814
815 if (mod == NULL || !mod->active)
816 return err;
817
818 fd = open(mod->path, O_RDONLY);
819
820 if (fd < 0)
821 return err;
822
823 err = dso__load_sym(self, fd, name, filter, verbose, mod);
824 close(fd);
825
826 return err;
827}
828
829int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose)
830{
831 struct mod_dso *mods = mod_dso__new_dso("modules");
832 struct module *pos;
833 struct rb_node *next;
834 int err;
835
836 err = mod_dso__load_modules(mods);
837
838 if (err <= 0)
839 return err;
840
841 /*
842 * Iterate over modules, and load active symbols.
843 */
844 next = rb_first(&mods->mods);
845 while (next) {
846 pos = rb_entry(next, struct module, rb_node);
847 err = dso__load_module(self, mods, pos->name, filter, verbose);
848
849 if (err < 0)
850 break;
851
852 next = rb_next(&pos->rb_node);
853 }
854
855 if (err < 0) {
856 mod_dso__delete_modules(mods);
857 mod_dso__delete_self(mods);
858 }
859
860 return err;
861}
862
863static inline void dso__fill_symbol_holes(struct dso *self)
864{
865 struct symbol *prev = NULL;
866 struct rb_node *nd;
867
868 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
869 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
870
871 if (prev) {
872 u64 hole = 0;
873 int alias = pos->start == prev->start;
874
875 if (!alias)
876 hole = prev->start - pos->end - 1;
877
878 if (hole || alias) {
879 if (alias)
880 pos->end = prev->end;
881 else if (hole)
882 pos->end = prev->start - 1;
883 }
884 }
885 prev = pos;
886 }
887}
888
889static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
890 symbol_filter_t filter, int verbose)
891{
892 int err, fd = open(vmlinux, O_RDONLY);
893
894 if (fd < 0)
895 return -1;
896
897 err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL);
898
899 if (err > 0)
900 dso__fill_symbol_holes(self);
901
902 close(fd);
903
904 return err;
905}
906
907int dso__load_kernel(struct dso *self, const char *vmlinux,
908 symbol_filter_t filter, int verbose, int modules)
909{
910 int err = -1;
911
912 if (vmlinux) {
913 err = dso__load_vmlinux(self, vmlinux, filter, verbose);
914 if (err > 0 && modules)
915 err = dso__load_modules(self, filter, verbose);
916 }
917
918 if (err <= 0)
919 err = dso__load_kallsyms(self, filter, verbose);
920
921 if (err > 0)
922 self->origin = DSO__ORIG_KERNEL;
923
924 return err;
925}
926
927void symbol__init(void)
928{
929 elf_version(EV_CURRENT);
930}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
new file mode 100644
index 000000000000..b53bf0125c1b
--- /dev/null
+++ b/tools/perf/util/symbol.h
@@ -0,0 +1,80 @@
1#ifndef _PERF_SYMBOL_
2#define _PERF_SYMBOL_ 1
3
4#include <linux/types.h>
5#include "types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8#include "module.h"
9
10#ifdef HAVE_CPLUS_DEMANGLE
11extern char *cplus_demangle(const char *, int);
12
13static inline char *bfd_demangle(void __used *v, const char *c, int i)
14{
15 return cplus_demangle(c, i);
16}
17#else
18#ifdef NO_DEMANGLE
19static inline char *bfd_demangle(void __used *v, const char __used *c,
20 int __used i)
21{
22 return NULL;
23}
24#else
25#include <bfd.h>
26#endif
27#endif
28
29#ifndef DMGL_PARAMS
30#define DMGL_PARAMS (1 << 0) /* Include function args */
31#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
32#endif
33
34struct symbol {
35 struct rb_node rb_node;
36 u64 start;
37 u64 end;
38 u64 obj_start;
39 u64 hist_sum;
40 u64 *hist;
41 struct module *module;
42 void *priv;
43 char name[0];
44};
45
46struct dso {
47 struct list_head node;
48 struct rb_root syms;
49 struct symbol *(*find_symbol)(struct dso *, u64 ip);
50 unsigned int sym_priv_size;
51 unsigned char adjust_symbols;
52 unsigned char slen_calculated;
53 unsigned char origin;
54 char name[0];
55};
56
57const char *sym_hist_filter;
58
59typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
60
61struct dso *dso__new(const char *name, unsigned int sym_priv_size);
62void dso__delete(struct dso *self);
63
64static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
65{
66 return ((void *)sym) - self->sym_priv_size;
67}
68
69struct symbol *dso__find_symbol(struct dso *self, u64 ip);
70
71int dso__load_kernel(struct dso *self, const char *vmlinux,
72 symbol_filter_t filter, int verbose, int modules);
73int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
74int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
75
76size_t dso__fprintf(struct dso *self, FILE *fp);
77char dso__symtab_origin(const struct dso *self);
78
79void symbol__init(void);
80#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
new file mode 100644
index 000000000000..5e75f9005940
--- /dev/null
+++ b/tools/perf/util/types.h
@@ -0,0 +1,17 @@
1#ifndef _PERF_TYPES_H
2#define _PERF_TYPES_H
3
4/*
5 * We define u64 as unsigned long long for every architecture
6 * so that we can print it with %Lx without getting warnings.
7 */
8typedef unsigned long long u64;
9typedef signed long long s64;
10typedef unsigned int u32;
11typedef signed int s32;
12typedef unsigned short u16;
13typedef signed short s16;
14typedef unsigned char u8;
15typedef signed char s8;
16
17#endif /* _PERF_TYPES_H */
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
new file mode 100644
index 000000000000..e16bf9a707e8
--- /dev/null
+++ b/tools/perf/util/usage.c
@@ -0,0 +1,80 @@
1/*
2 * GIT - The information manager from hell
3 *
4 * Copyright (C) Linus Torvalds, 2005
5 */
6#include "util.h"
7
8static void report(const char *prefix, const char *err, va_list params)
9{
10 char msg[1024];
11 vsnprintf(msg, sizeof(msg), err, params);
12 fprintf(stderr, " %s%s\n", prefix, msg);
13}
14
15static NORETURN void usage_builtin(const char *err)
16{
17 fprintf(stderr, "\n Usage: %s\n", err);
18 exit(129);
19}
20
21static NORETURN void die_builtin(const char *err, va_list params)
22{
23 report(" Fatal: ", err, params);
24 exit(128);
25}
26
27static void error_builtin(const char *err, va_list params)
28{
29 report(" Error: ", err, params);
30}
31
32static void warn_builtin(const char *warn, va_list params)
33{
34 report(" Warning: ", warn, params);
35}
36
37/* If we are in a dlopen()ed .so write to a global variable would segfault
38 * (ugh), so keep things static. */
39static void (*usage_routine)(const char *err) NORETURN = usage_builtin;
40static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin;
41static void (*error_routine)(const char *err, va_list params) = error_builtin;
42static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
43
44void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN)
45{
46 die_routine = routine;
47}
48
49void usage(const char *err)
50{
51 usage_routine(err);
52}
53
54void die(const char *err, ...)
55{
56 va_list params;
57
58 va_start(params, err);
59 die_routine(err, params);
60 va_end(params);
61}
62
63int error(const char *err, ...)
64{
65 va_list params;
66
67 va_start(params, err);
68 error_routine(err, params);
69 va_end(params);
70 return -1;
71}
72
73void warning(const char *warn, ...)
74{
75 va_list params;
76
77 va_start(params, warn);
78 warn_routine(warn, params);
79 va_end(params);
80}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
new file mode 100644
index 000000000000..68fe157d72fb
--- /dev/null
+++ b/tools/perf/util/util.h
@@ -0,0 +1,395 @@
1#ifndef GIT_COMPAT_UTIL_H
2#define GIT_COMPAT_UTIL_H
3
4#define _FILE_OFFSET_BITS 64
5
6#ifndef FLEX_ARRAY
7/*
8 * See if our compiler is known to support flexible array members.
9 */
10#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
11# define FLEX_ARRAY /* empty */
12#elif defined(__GNUC__)
13# if (__GNUC__ >= 3)
14# define FLEX_ARRAY /* empty */
15# else
16# define FLEX_ARRAY 0 /* older GNU extension */
17# endif
18#endif
19
20/*
21 * Otherwise, default to safer but a bit wasteful traditional style
22 */
23#ifndef FLEX_ARRAY
24# define FLEX_ARRAY 1
25#endif
26#endif
27
28#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
29
30#ifdef __GNUC__
31#define TYPEOF(x) (__typeof__(x))
32#else
33#define TYPEOF(x)
34#endif
35
36#define MSB(x, bits) ((x) & TYPEOF(x)(~0ULL << (sizeof(x) * 8 - (bits))))
37#define HAS_MULTI_BITS(i) ((i) & ((i) - 1)) /* checks if an integer has more than 1 bit set */
38
39/* Approximation of the length of the decimal representation of this type. */
40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
41
42#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX)
43#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
44#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
45#endif
46#define _ALL_SOURCE 1
47#define _GNU_SOURCE 1
48#define _BSD_SOURCE 1
49
50#include <unistd.h>
51#include <stdio.h>
52#include <sys/stat.h>
53#include <sys/statfs.h>
54#include <fcntl.h>
55#include <stddef.h>
56#include <stdlib.h>
57#include <stdarg.h>
58#include <string.h>
59#include <errno.h>
60#include <limits.h>
61#include <sys/param.h>
62#include <sys/types.h>
63#include <dirent.h>
64#include <sys/time.h>
65#include <time.h>
66#include <signal.h>
67#include <fnmatch.h>
68#include <assert.h>
69#include <regex.h>
70#include <utime.h>
71#include <sys/wait.h>
72#include <sys/poll.h>
73#include <sys/socket.h>
74#include <sys/ioctl.h>
75#ifndef NO_SYS_SELECT_H
76#include <sys/select.h>
77#endif
78#include <netinet/in.h>
79#include <netinet/tcp.h>
80#include <arpa/inet.h>
81#include <netdb.h>
82#include <pwd.h>
83#include <inttypes.h>
84#include "../../../include/linux/magic.h"
85
86#ifndef NO_ICONV
87#include <iconv.h>
88#endif
89
90/* On most systems <limits.h> would have given us this, but
91 * not on some systems (e.g. GNU/Hurd).
92 */
93#ifndef PATH_MAX
94#define PATH_MAX 4096
95#endif
96
97#ifndef PRIuMAX
98#define PRIuMAX "llu"
99#endif
100
101#ifndef PRIu32
102#define PRIu32 "u"
103#endif
104
105#ifndef PRIx32
106#define PRIx32 "x"
107#endif
108
109#ifndef PATH_SEP
110#define PATH_SEP ':'
111#endif
112
113#ifndef STRIP_EXTENSION
114#define STRIP_EXTENSION ""
115#endif
116
117#ifndef has_dos_drive_prefix
118#define has_dos_drive_prefix(path) 0
119#endif
120
121#ifndef is_dir_sep
122#define is_dir_sep(c) ((c) == '/')
123#endif
124
125#ifdef __GNUC__
126#define NORETURN __attribute__((__noreturn__))
127#else
128#define NORETURN
129#ifndef __attribute__
130#define __attribute__(x)
131#endif
132#endif
133
134/* General helper functions */
135extern void usage(const char *err) NORETURN;
136extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
137extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
138extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
139
140extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
141
142extern int prefixcmp(const char *str, const char *prefix);
143extern time_t tm_to_time_t(const struct tm *tm);
144
145static inline const char *skip_prefix(const char *str, const char *prefix)
146{
147 size_t len = strlen(prefix);
148 return strncmp(str, prefix, len) ? NULL : str + len;
149}
150
151#if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
152
153#ifndef PROT_READ
154#define PROT_READ 1
155#define PROT_WRITE 2
156#define MAP_PRIVATE 1
157#define MAP_FAILED ((void*)-1)
158#endif
159
160#define mmap git_mmap
161#define munmap git_munmap
162extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
163extern int git_munmap(void *start, size_t length);
164
165#else /* NO_MMAP || USE_WIN32_MMAP */
166
167#include <sys/mman.h>
168
169#endif /* NO_MMAP || USE_WIN32_MMAP */
170
171#ifdef NO_MMAP
172
173/* This value must be multiple of (pagesize * 2) */
174#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024)
175
176#else /* NO_MMAP */
177
178/* This value must be multiple of (pagesize * 2) */
179#define DEFAULT_PACKED_GIT_WINDOW_SIZE \
180 (sizeof(void*) >= 8 \
181 ? 1 * 1024 * 1024 * 1024 \
182 : 32 * 1024 * 1024)
183
184#endif /* NO_MMAP */
185
186#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
187#define on_disk_bytes(st) ((st).st_size)
188#else
189#define on_disk_bytes(st) ((st).st_blocks * 512)
190#endif
191
192#define DEFAULT_PACKED_GIT_LIMIT \
193 ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
194
195#ifdef NO_PREAD
196#define pread git_pread
197extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
198#endif
199/*
200 * Forward decl that will remind us if its twin in cache.h changes.
201 * This function is used in compat/pread.c. But we can't include
202 * cache.h there.
203 */
204extern ssize_t read_in_full(int fd, void *buf, size_t count);
205
206#ifdef NO_SETENV
207#define setenv gitsetenv
208extern int gitsetenv(const char *, const char *, int);
209#endif
210
211#ifdef NO_MKDTEMP
212#define mkdtemp gitmkdtemp
213extern char *gitmkdtemp(char *);
214#endif
215
216#ifdef NO_UNSETENV
217#define unsetenv gitunsetenv
218extern void gitunsetenv(const char *);
219#endif
220
221#ifdef NO_STRCASESTR
222#define strcasestr gitstrcasestr
223extern char *gitstrcasestr(const char *haystack, const char *needle);
224#endif
225
226#ifdef NO_STRLCPY
227#define strlcpy gitstrlcpy
228extern size_t gitstrlcpy(char *, const char *, size_t);
229#endif
230
231#ifdef NO_STRTOUMAX
232#define strtoumax gitstrtoumax
233extern uintmax_t gitstrtoumax(const char *, char **, int);
234#endif
235
236#ifdef NO_HSTRERROR
237#define hstrerror githstrerror
238extern const char *githstrerror(int herror);
239#endif
240
241#ifdef NO_MEMMEM
242#define memmem gitmemmem
243void *gitmemmem(const void *haystack, size_t haystacklen,
244 const void *needle, size_t needlelen);
245#endif
246
247#ifdef FREAD_READS_DIRECTORIES
248#ifdef fopen
249#undef fopen
250#endif
251#define fopen(a,b) git_fopen(a,b)
252extern FILE *git_fopen(const char*, const char*);
253#endif
254
255#ifdef SNPRINTF_RETURNS_BOGUS
256#define snprintf git_snprintf
257extern int git_snprintf(char *str, size_t maxsize,
258 const char *format, ...);
259#define vsnprintf git_vsnprintf
260extern int git_vsnprintf(char *str, size_t maxsize,
261 const char *format, va_list ap);
262#endif
263
264#ifdef __GLIBC_PREREQ
265#if __GLIBC_PREREQ(2, 1)
266#define HAVE_STRCHRNUL
267#endif
268#endif
269
270#ifndef HAVE_STRCHRNUL
271#define strchrnul gitstrchrnul
272static inline char *gitstrchrnul(const char *s, int c)
273{
274 while (*s && *s != c)
275 s++;
276 return (char *)s;
277}
278#endif
279
280/*
281 * Wrappers:
282 */
283extern char *xstrdup(const char *str);
284extern void *xmalloc(size_t size);
285extern void *xmemdupz(const void *data, size_t len);
286extern char *xstrndup(const char *str, size_t len);
287extern void *xrealloc(void *ptr, size_t size);
288extern void *xcalloc(size_t nmemb, size_t size);
289extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
290extern ssize_t xread(int fd, void *buf, size_t len);
291extern ssize_t xwrite(int fd, const void *buf, size_t len);
292extern int xdup(int fd);
293extern FILE *xfdopen(int fd, const char *mode);
294extern int xmkstemp(char *template);
295
296static inline size_t xsize_t(off_t len)
297{
298 return (size_t)len;
299}
300
301static inline int has_extension(const char *filename, const char *ext)
302{
303 size_t len = strlen(filename);
304 size_t extlen = strlen(ext);
305 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
306}
307
308/* Sane ctype - no locale, and works with signed chars */
309#undef isascii
310#undef isspace
311#undef isdigit
312#undef isalpha
313#undef isalnum
314#undef tolower
315#undef toupper
316extern unsigned char sane_ctype[256];
317#define GIT_SPACE 0x01
318#define GIT_DIGIT 0x02
319#define GIT_ALPHA 0x04
320#define GIT_GLOB_SPECIAL 0x08
321#define GIT_REGEX_SPECIAL 0x10
322#define GIT_PRINT_EXTRA 0x20
323#define GIT_PRINT 0x3E
324#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
325#define isascii(x) (((x) & ~0x7f) == 0)
326#define isspace(x) sane_istest(x,GIT_SPACE)
327#define isdigit(x) sane_istest(x,GIT_DIGIT)
328#define isalpha(x) sane_istest(x,GIT_ALPHA)
329#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
330#define isprint(x) sane_istest(x,GIT_PRINT)
331#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
332#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
333#define tolower(x) sane_case((unsigned char)(x), 0x20)
334#define toupper(x) sane_case((unsigned char)(x), 0)
335
336static inline int sane_case(int x, int high)
337{
338 if (sane_istest(x, GIT_ALPHA))
339 x = (x & ~0x20) | high;
340 return x;
341}
342
343static inline int strtoul_ui(char const *s, int base, unsigned int *result)
344{
345 unsigned long ul;
346 char *p;
347
348 errno = 0;
349 ul = strtoul(s, &p, base);
350 if (errno || *p || p == s || (unsigned int) ul != ul)
351 return -1;
352 *result = ul;
353 return 0;
354}
355
356static inline int strtol_i(char const *s, int base, int *result)
357{
358 long ul;
359 char *p;
360
361 errno = 0;
362 ul = strtol(s, &p, base);
363 if (errno || *p || p == s || (int) ul != ul)
364 return -1;
365 *result = ul;
366 return 0;
367}
368
369#ifdef INTERNAL_QSORT
370void git_qsort(void *base, size_t nmemb, size_t size,
371 int(*compar)(const void *, const void *));
372#define qsort git_qsort
373#endif
374
375#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
376# define FORCE_DIR_SET_GID S_ISGID
377#else
378# define FORCE_DIR_SET_GID 0
379#endif
380
381#ifdef NO_NSEC
382#undef USE_NSEC
383#define ST_CTIME_NSEC(st) 0
384#define ST_MTIME_NSEC(st) 0
385#else
386#ifdef USE_ST_TIMESPEC
387#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
388#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
389#else
390#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
391#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
392#endif
393#endif
394
395#endif
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
new file mode 100644
index 000000000000..4574ac28396f
--- /dev/null
+++ b/tools/perf/util/wrapper.c
@@ -0,0 +1,207 @@
1/*
2 * Various trivial helper wrappers around standard functions
3 */
4#include "cache.h"
5
6/*
7 * There's no pack memory to release - but stay close to the Git
8 * version so wrap this away:
9 */
10static inline void release_pack_memory(size_t size __used, int flag __used)
11{
12}
13
14char *xstrdup(const char *str)
15{
16 char *ret = strdup(str);
17 if (!ret) {
18 release_pack_memory(strlen(str) + 1, -1);
19 ret = strdup(str);
20 if (!ret)
21 die("Out of memory, strdup failed");
22 }
23 return ret;
24}
25
26void *xmalloc(size_t size)
27{
28 void *ret = malloc(size);
29 if (!ret && !size)
30 ret = malloc(1);
31 if (!ret) {
32 release_pack_memory(size, -1);
33 ret = malloc(size);
34 if (!ret && !size)
35 ret = malloc(1);
36 if (!ret)
37 die("Out of memory, malloc failed");
38 }
39#ifdef XMALLOC_POISON
40 memset(ret, 0xA5, size);
41#endif
42 return ret;
43}
44
45/*
46 * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
47 * "data" to the allocated memory, zero terminates the allocated memory,
48 * and returns a pointer to the allocated memory. If the allocation fails,
49 * the program dies.
50 */
51void *xmemdupz(const void *data, size_t len)
52{
53 char *p = xmalloc(len + 1);
54 memcpy(p, data, len);
55 p[len] = '\0';
56 return p;
57}
58
59char *xstrndup(const char *str, size_t len)
60{
61 char *p = memchr(str, '\0', len);
62
63 return xmemdupz(str, p ? (size_t)(p - str) : len);
64}
65
66void *xrealloc(void *ptr, size_t size)
67{
68 void *ret = realloc(ptr, size);
69 if (!ret && !size)
70 ret = realloc(ptr, 1);
71 if (!ret) {
72 release_pack_memory(size, -1);
73 ret = realloc(ptr, size);
74 if (!ret && !size)
75 ret = realloc(ptr, 1);
76 if (!ret)
77 die("Out of memory, realloc failed");
78 }
79 return ret;
80}
81
82void *xcalloc(size_t nmemb, size_t size)
83{
84 void *ret = calloc(nmemb, size);
85 if (!ret && (!nmemb || !size))
86 ret = calloc(1, 1);
87 if (!ret) {
88 release_pack_memory(nmemb * size, -1);
89 ret = calloc(nmemb, size);
90 if (!ret && (!nmemb || !size))
91 ret = calloc(1, 1);
92 if (!ret)
93 die("Out of memory, calloc failed");
94 }
95 return ret;
96}
97
98void *xmmap(void *start, size_t length,
99 int prot, int flags, int fd, off_t offset)
100{
101 void *ret = mmap(start, length, prot, flags, fd, offset);
102 if (ret == MAP_FAILED) {
103 if (!length)
104 return NULL;
105 release_pack_memory(length, fd);
106 ret = mmap(start, length, prot, flags, fd, offset);
107 if (ret == MAP_FAILED)
108 die("Out of memory? mmap failed: %s", strerror(errno));
109 }
110 return ret;
111}
112
113/*
114 * xread() is the same a read(), but it automatically restarts read()
115 * operations with a recoverable error (EAGAIN and EINTR). xread()
116 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
117 */
118ssize_t xread(int fd, void *buf, size_t len)
119{
120 ssize_t nr;
121 while (1) {
122 nr = read(fd, buf, len);
123 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
124 continue;
125 return nr;
126 }
127}
128
129/*
130 * xwrite() is the same a write(), but it automatically restarts write()
131 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
132 * GUARANTEE that "len" bytes is written even if the operation is successful.
133 */
134ssize_t xwrite(int fd, const void *buf, size_t len)
135{
136 ssize_t nr;
137 while (1) {
138 nr = write(fd, buf, len);
139 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
140 continue;
141 return nr;
142 }
143}
144
145ssize_t read_in_full(int fd, void *buf, size_t count)
146{
147 char *p = buf;
148 ssize_t total = 0;
149
150 while (count > 0) {
151 ssize_t loaded = xread(fd, p, count);
152 if (loaded <= 0)
153 return total ? total : loaded;
154 count -= loaded;
155 p += loaded;
156 total += loaded;
157 }
158
159 return total;
160}
161
162ssize_t write_in_full(int fd, const void *buf, size_t count)
163{
164 const char *p = buf;
165 ssize_t total = 0;
166
167 while (count > 0) {
168 ssize_t written = xwrite(fd, p, count);
169 if (written < 0)
170 return -1;
171 if (!written) {
172 errno = ENOSPC;
173 return -1;
174 }
175 count -= written;
176 p += written;
177 total += written;
178 }
179
180 return total;
181}
182
183int xdup(int fd)
184{
185 int ret = dup(fd);
186 if (ret < 0)
187 die("dup failed: %s", strerror(errno));
188 return ret;
189}
190
191FILE *xfdopen(int fd, const char *mode)
192{
193 FILE *stream = fdopen(fd, mode);
194 if (stream == NULL)
195 die("Out of memory? fdopen failed: %s", strerror(errno));
196 return stream;
197}
198
199int xmkstemp(char *template)
200{
201 int fd;
202
203 fd = mkstemp(template);
204 if (fd < 0)
205 die("Unable to create temporary file: %s", strerror(errno));
206 return fd;
207}