aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2009-09-08 20:55:21 -0400
committerDan Williams <dan.j.williams@intel.com>2009-09-08 20:55:21 -0400
commitbbb20089a3275a19e475dbc21320c3742e3ca423 (patch)
tree216fdc1cbef450ca688135c5b8969169482d9a48 /tools/perf
parent3e48e656903e9fd8bc805c6a2c4264d7808d315b (diff)
parent657a77fa7284d8ae28dfa48f1dc5d919bf5b2843 (diff)
Merge branch 'dmaengine' into async-tx-next
Conflicts: crypto/async_tx/async_xor.c drivers/dma/ioat/dma_v2.h drivers/dma/ioat/pci.c drivers/md/raid5.c
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/.gitignore16
-rw-r--r--tools/perf/Documentation/Makefile300
-rw-r--r--tools/perf/Documentation/asciidoc.conf91
-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.txt42
-rw-r--r--tools/perf/Documentation/perf-report.txt26
-rw-r--r--tools/perf/Documentation/perf-stat.txt66
-rw-r--r--tools/perf/Documentation/perf-top.txt39
-rw-r--r--tools/perf/Documentation/perf.txt24
-rw-r--r--tools/perf/Makefile935
-rw-r--r--tools/perf/builtin-annotate.c1522
-rw-r--r--tools/perf/builtin-help.c461
-rw-r--r--tools/perf/builtin-list.c20
-rw-r--r--tools/perf/builtin-record.c628
-rw-r--r--tools/perf/builtin-report.c1581
-rw-r--r--tools/perf/builtin-stat.c521
-rw-r--r--tools/perf/builtin-top.c736
-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.c428
-rw-r--r--tools/perf/perf.h81
-rw-r--r--tools/perf/types.h17
-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.h119
-rw-r--r--tools/perf/util/color.c241
-rw-r--r--tools/perf/util/color.h36
-rw-r--r--tools/perf/util/config.c873
-rw-r--r--tools/perf/util/ctype.c31
-rw-r--r--tools/perf/util/environment.c9
-rw-r--r--tools/perf/util/exec_cmd.c165
-rw-r--r--tools/perf/util/exec_cmd.h13
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh24
-rw-r--r--tools/perf/util/help.c367
-rw-r--r--tools/perf/util/help.h29
-rw-r--r--tools/perf/util/levenshtein.c84
-rw-r--r--tools/perf/util/levenshtein.h8
-rw-r--r--tools/perf/util/list.h603
-rw-r--r--tools/perf/util/pager.c99
-rw-r--r--tools/perf/util/parse-events.c316
-rw-r--r--tools/perf/util/parse-events.h17
-rw-r--r--tools/perf/util/parse-options.c508
-rw-r--r--tools/perf/util/parse-options.h174
-rw-r--r--tools/perf/util/path.c353
-rw-r--r--tools/perf/util/quote.c481
-rw-r--r--tools/perf/util/quote.h68
-rw-r--r--tools/perf/util/rbtree.c383
-rw-r--r--tools/perf/util/rbtree.h171
-rw-r--r--tools/perf/util/run-command.c395
-rw-r--r--tools/perf/util/run-command.h93
-rw-r--r--tools/perf/util/sigchain.c52
-rw-r--r--tools/perf/util/sigchain.h11
-rw-r--r--tools/perf/util/strbuf.c359
-rw-r--r--tools/perf/util/strbuf.h137
-rw-r--r--tools/perf/util/string.c34
-rw-r--r--tools/perf/util/string.h8
-rw-r--r--tools/perf/util/symbol.c641
-rw-r--r--tools/perf/util/symbol.h49
-rw-r--r--tools/perf/util/usage.c80
-rw-r--r--tools/perf/util/util.h408
-rw-r--r--tools/perf/util/wrapper.c206
70 files changed, 16100 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/Documentation/Makefile b/tools/perf/Documentation/Makefile
new file mode 100644
index 000000000000..5457192e1b41
--- /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 =
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/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..1dbc1eeb4c01
--- /dev/null
+++ b/tools/perf/Documentation/perf-record.txt
@@ -0,0 +1,42 @@
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
40SEE ALSO
41--------
42linkperf: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..52d3fc6846a9
--- /dev/null
+++ b/tools/perf/Documentation/perf-report.txt
@@ -0,0 +1,26 @@
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 report.
17
18OPTIONS
19-------
20-i::
21--input=::
22 Input file name. (default: perf.data)
23
24SEE ALSO
25--------
26linkperf: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..c368a72721d7
--- /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] [-l] [-a] <command>
12'perf stat' [-e <EVENT> | --event=EVENT] [-l] [-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-l::
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..539d01289725
--- /dev/null
+++ b/tools/perf/Documentation/perf-top.txt
@@ -0,0 +1,39 @@
1perf-top(1)
2===========
3
4NAME
5----
6perf-top - Run a command and profile it
7
8SYNOPSIS
9--------
10[verse]
11'perf top' [-e <EVENT> | --event=EVENT] [-l] [-a] <command>
12
13DESCRIPTION
14-----------
15This command runs a command and gathers a performance counter profile
16from it.
17
18
19OPTIONS
20-------
21<command>...::
22 Any command you can specify in a shell.
23
24-e::
25--event=::
26 Select the PMU event. Selection can be a symbolic event name
27 (use 'perf list' to list all events) or a raw PMU
28 event (eventsel+umask) in the form of rNNN where NNN is a
29 hexadecimal event descriptor.
30
31-a::
32 system-wide collection
33
34-l::
35 scale counter values
36
37SEE ALSO
38--------
39linkperf: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..36d7eef49913
--- /dev/null
+++ b/tools/perf/Makefile
@@ -0,0 +1,935 @@
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
161ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
162 M64 := -m64
163endif
164
165# CFLAGS and LDFLAGS are for the users to override from the command line.
166
167CFLAGS = $(M64) -ggdb3 -Wall -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6
168LDFLAGS = -lpthread -lrt -lelf -lm
169ALL_CFLAGS = $(CFLAGS)
170ALL_LDFLAGS = $(LDFLAGS)
171STRIP ?= strip
172
173# Among the variables below, these:
174# perfexecdir
175# template_dir
176# mandir
177# infodir
178# htmldir
179# ETC_PERFCONFIG (but not sysconfdir)
180# can be specified as a relative path some/where/else;
181# this is interpreted as relative to $(prefix) and "perf" at
182# runtime figures out where they are based on the path to the executable.
183# This can help installing the suite in a relocatable way.
184
185prefix = $(HOME)
186bindir_relative = bin
187bindir = $(prefix)/$(bindir_relative)
188mandir = share/man
189infodir = share/info
190perfexecdir = libexec/perf-core
191sharedir = $(prefix)/share
192template_dir = share/perf-core/templates
193htmldir = share/doc/perf-doc
194ifeq ($(prefix),/usr)
195sysconfdir = /etc
196ETC_PERFCONFIG = $(sysconfdir)/perfconfig
197else
198sysconfdir = $(prefix)/etc
199ETC_PERFCONFIG = etc/perfconfig
200endif
201lib = lib
202# DESTDIR=
203
204export prefix bindir sharedir sysconfdir
205
206CC = gcc
207AR = ar
208RM = rm -f
209TAR = tar
210FIND = find
211INSTALL = install
212RPMBUILD = rpmbuild
213PTHREAD_LIBS = -lpthread
214
215# sparse is architecture-neutral, which means that we need to tell it
216# explicitly what architecture to check for. Fix this up for yours..
217SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
218
219
220
221### --- END CONFIGURATION SECTION ---
222
223# Those must not be GNU-specific; they are shared with perl/ which may
224# be built by a different compiler. (Note that this is an artifact now
225# but it still might be nice to keep that distinction.)
226BASIC_CFLAGS =
227BASIC_LDFLAGS =
228
229# Guard against environment variables
230BUILTIN_OBJS =
231BUILT_INS =
232COMPAT_CFLAGS =
233COMPAT_OBJS =
234LIB_H =
235LIB_OBJS =
236SCRIPT_PERL =
237SCRIPT_SH =
238TEST_PROGRAMS =
239
240#
241# No scripts right now:
242#
243
244# SCRIPT_SH += perf-am.sh
245
246#
247# No Perl scripts right now:
248#
249
250# SCRIPT_PERL += perf-add--interactive.perl
251
252SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
253 $(patsubst %.perl,%,$(SCRIPT_PERL))
254
255# Empty...
256EXTRA_PROGRAMS =
257
258# ... and all the rest that could be moved out of bindir to perfexecdir
259PROGRAMS += $(EXTRA_PROGRAMS)
260
261#
262# Single 'perf' binary right now:
263#
264PROGRAMS += perf
265
266# List built-in command $C whose implementation cmd_$C() is not in
267# builtin-$C.o but is linked in as part of some other command.
268#
269# None right now:
270#
271# BUILT_INS += perf-init $X
272
273# what 'all' will build and 'install' will install, in perfexecdir
274ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
275
276# what 'all' will build but not install in perfexecdir
277OTHER_PROGRAMS = perf$X
278
279# Set paths to tools early so that they can be used for version tests.
280ifndef SHELL_PATH
281 SHELL_PATH = /bin/sh
282endif
283ifndef PERL_PATH
284 PERL_PATH = /usr/bin/perl
285endif
286
287export PERL_PATH
288
289LIB_FILE=libperf.a
290
291LIB_H += ../../include/linux/perf_counter.h
292LIB_H += perf.h
293LIB_H += types.h
294LIB_H += util/list.h
295LIB_H += util/rbtree.h
296LIB_H += util/levenshtein.h
297LIB_H += util/parse-options.h
298LIB_H += util/parse-events.h
299LIB_H += util/quote.h
300LIB_H += util/util.h
301LIB_H += util/help.h
302LIB_H += util/strbuf.h
303LIB_H += util/string.h
304LIB_H += util/run-command.h
305LIB_H += util/sigchain.h
306LIB_H += util/symbol.h
307LIB_H += util/color.h
308
309LIB_OBJS += util/abspath.o
310LIB_OBJS += util/alias.o
311LIB_OBJS += util/config.o
312LIB_OBJS += util/ctype.o
313LIB_OBJS += util/environment.o
314LIB_OBJS += util/exec_cmd.o
315LIB_OBJS += util/help.o
316LIB_OBJS += util/levenshtein.o
317LIB_OBJS += util/parse-options.o
318LIB_OBJS += util/parse-events.o
319LIB_OBJS += util/path.o
320LIB_OBJS += util/rbtree.o
321LIB_OBJS += util/run-command.o
322LIB_OBJS += util/quote.o
323LIB_OBJS += util/strbuf.o
324LIB_OBJS += util/string.o
325LIB_OBJS += util/usage.o
326LIB_OBJS += util/wrapper.o
327LIB_OBJS += util/sigchain.o
328LIB_OBJS += util/symbol.o
329LIB_OBJS += util/color.o
330LIB_OBJS += util/pager.o
331
332BUILTIN_OBJS += builtin-annotate.o
333BUILTIN_OBJS += builtin-help.o
334BUILTIN_OBJS += builtin-list.o
335BUILTIN_OBJS += builtin-record.o
336BUILTIN_OBJS += builtin-report.o
337BUILTIN_OBJS += builtin-stat.o
338BUILTIN_OBJS += builtin-top.o
339
340PERFLIBS = $(LIB_FILE)
341EXTLIBS =
342
343#
344# Platform specific tweaks
345#
346
347# We choose to avoid "if .. else if .. else .. endif endif"
348# because maintaining the nesting to match is a pain. If
349# we had "elif" things would have been much nicer...
350
351-include config.mak.autogen
352-include config.mak
353
354ifeq ($(uname_S),Darwin)
355 ifndef NO_FINK
356 ifeq ($(shell test -d /sw/lib && echo y),y)
357 BASIC_CFLAGS += -I/sw/include
358 BASIC_LDFLAGS += -L/sw/lib
359 endif
360 endif
361 ifndef NO_DARWIN_PORTS
362 ifeq ($(shell test -d /opt/local/lib && echo y),y)
363 BASIC_CFLAGS += -I/opt/local/include
364 BASIC_LDFLAGS += -L/opt/local/lib
365 endif
366 endif
367 PTHREAD_LIBS =
368endif
369
370ifndef CC_LD_DYNPATH
371 ifdef NO_R_TO_GCC_LINKER
372 # Some gcc does not accept and pass -R to the linker to specify
373 # the runtime dynamic library path.
374 CC_LD_DYNPATH = -Wl,-rpath,
375 else
376 CC_LD_DYNPATH = -R
377 endif
378endif
379
380ifdef ZLIB_PATH
381 BASIC_CFLAGS += -I$(ZLIB_PATH)/include
382 EXTLIBS += -L$(ZLIB_PATH)/$(lib) $(CC_LD_DYNPATH)$(ZLIB_PATH)/$(lib)
383endif
384EXTLIBS += -lz
385
386ifdef NEEDS_SOCKET
387 EXTLIBS += -lsocket
388endif
389ifdef NEEDS_NSL
390 EXTLIBS += -lnsl
391endif
392ifdef NO_D_TYPE_IN_DIRENT
393 BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
394endif
395ifdef NO_D_INO_IN_DIRENT
396 BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
397endif
398ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
399 BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
400endif
401ifdef USE_NSEC
402 BASIC_CFLAGS += -DUSE_NSEC
403endif
404ifdef USE_ST_TIMESPEC
405 BASIC_CFLAGS += -DUSE_ST_TIMESPEC
406endif
407ifdef NO_NSEC
408 BASIC_CFLAGS += -DNO_NSEC
409endif
410ifdef NO_C99_FORMAT
411 BASIC_CFLAGS += -DNO_C99_FORMAT
412endif
413ifdef SNPRINTF_RETURNS_BOGUS
414 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
415 COMPAT_OBJS += compat/snprintf.o
416endif
417ifdef FREAD_READS_DIRECTORIES
418 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
419 COMPAT_OBJS += compat/fopen.o
420endif
421ifdef NO_SYMLINK_HEAD
422 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
423endif
424ifdef NO_STRCASESTR
425 COMPAT_CFLAGS += -DNO_STRCASESTR
426 COMPAT_OBJS += compat/strcasestr.o
427endif
428ifdef NO_STRTOUMAX
429 COMPAT_CFLAGS += -DNO_STRTOUMAX
430 COMPAT_OBJS += compat/strtoumax.o
431endif
432ifdef NO_STRTOULL
433 COMPAT_CFLAGS += -DNO_STRTOULL
434endif
435ifdef NO_SETENV
436 COMPAT_CFLAGS += -DNO_SETENV
437 COMPAT_OBJS += compat/setenv.o
438endif
439ifdef NO_MKDTEMP
440 COMPAT_CFLAGS += -DNO_MKDTEMP
441 COMPAT_OBJS += compat/mkdtemp.o
442endif
443ifdef NO_UNSETENV
444 COMPAT_CFLAGS += -DNO_UNSETENV
445 COMPAT_OBJS += compat/unsetenv.o
446endif
447ifdef NO_SYS_SELECT_H
448 BASIC_CFLAGS += -DNO_SYS_SELECT_H
449endif
450ifdef NO_MMAP
451 COMPAT_CFLAGS += -DNO_MMAP
452 COMPAT_OBJS += compat/mmap.o
453else
454 ifdef USE_WIN32_MMAP
455 COMPAT_CFLAGS += -DUSE_WIN32_MMAP
456 COMPAT_OBJS += compat/win32mmap.o
457 endif
458endif
459ifdef NO_PREAD
460 COMPAT_CFLAGS += -DNO_PREAD
461 COMPAT_OBJS += compat/pread.o
462endif
463ifdef NO_FAST_WORKING_DIRECTORY
464 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
465endif
466ifdef NO_TRUSTABLE_FILEMODE
467 BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
468endif
469ifdef NO_IPV6
470 BASIC_CFLAGS += -DNO_IPV6
471endif
472ifdef NO_UINTMAX_T
473 BASIC_CFLAGS += -Duintmax_t=uint32_t
474endif
475ifdef NO_SOCKADDR_STORAGE
476ifdef NO_IPV6
477 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
478else
479 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
480endif
481endif
482ifdef NO_INET_NTOP
483 LIB_OBJS += compat/inet_ntop.o
484endif
485ifdef NO_INET_PTON
486 LIB_OBJS += compat/inet_pton.o
487endif
488
489ifdef NO_ICONV
490 BASIC_CFLAGS += -DNO_ICONV
491endif
492
493ifdef OLD_ICONV
494 BASIC_CFLAGS += -DOLD_ICONV
495endif
496
497ifdef NO_DEFLATE_BOUND
498 BASIC_CFLAGS += -DNO_DEFLATE_BOUND
499endif
500
501ifdef PPC_SHA1
502 SHA1_HEADER = "ppc/sha1.h"
503 LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
504else
505ifdef ARM_SHA1
506 SHA1_HEADER = "arm/sha1.h"
507 LIB_OBJS += arm/sha1.o arm/sha1_arm.o
508else
509ifdef MOZILLA_SHA1
510 SHA1_HEADER = "mozilla-sha1/sha1.h"
511 LIB_OBJS += mozilla-sha1/sha1.o
512else
513 SHA1_HEADER = <openssl/sha.h>
514 EXTLIBS += $(LIB_4_CRYPTO)
515endif
516endif
517endif
518ifdef NO_PERL_MAKEMAKER
519 export NO_PERL_MAKEMAKER
520endif
521ifdef NO_HSTRERROR
522 COMPAT_CFLAGS += -DNO_HSTRERROR
523 COMPAT_OBJS += compat/hstrerror.o
524endif
525ifdef NO_MEMMEM
526 COMPAT_CFLAGS += -DNO_MEMMEM
527 COMPAT_OBJS += compat/memmem.o
528endif
529ifdef INTERNAL_QSORT
530 COMPAT_CFLAGS += -DINTERNAL_QSORT
531 COMPAT_OBJS += compat/qsort.o
532endif
533ifdef RUNTIME_PREFIX
534 COMPAT_CFLAGS += -DRUNTIME_PREFIX
535endif
536
537ifdef DIR_HAS_BSD_GROUP_SEMANTICS
538 COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
539endif
540ifdef NO_EXTERNAL_GREP
541 BASIC_CFLAGS += -DNO_EXTERNAL_GREP
542endif
543
544ifeq ($(PERL_PATH),)
545NO_PERL=NoThanks
546endif
547
548QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
549QUIET_SUBDIR1 =
550
551ifneq ($(findstring $(MAKEFLAGS),w),w)
552PRINT_DIR = --no-print-directory
553else # "make -w"
554NO_SUBDIR = :
555endif
556
557ifneq ($(findstring $(MAKEFLAGS),s),s)
558ifndef V
559 QUIET_CC = @echo ' ' CC $@;
560 QUIET_AR = @echo ' ' AR $@;
561 QUIET_LINK = @echo ' ' LINK $@;
562 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
563 QUIET_GEN = @echo ' ' GEN $@;
564 QUIET_SUBDIR0 = +@subdir=
565 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
566 $(MAKE) $(PRINT_DIR) -C $$subdir
567 export V
568 export QUIET_GEN
569 export QUIET_BUILT_IN
570endif
571endif
572
573ifdef ASCIIDOC8
574 export ASCIIDOC8
575endif
576
577# Shell quote (do not use $(call) to accommodate ancient setups);
578
579SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
580ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
581
582DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
583bindir_SQ = $(subst ','\'',$(bindir))
584bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
585mandir_SQ = $(subst ','\'',$(mandir))
586infodir_SQ = $(subst ','\'',$(infodir))
587perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
588template_dir_SQ = $(subst ','\'',$(template_dir))
589htmldir_SQ = $(subst ','\'',$(htmldir))
590prefix_SQ = $(subst ','\'',$(prefix))
591
592SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
593PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
594
595LIBS = $(PERFLIBS) $(EXTLIBS)
596
597BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
598 $(COMPAT_CFLAGS)
599LIB_OBJS += $(COMPAT_OBJS)
600
601ALL_CFLAGS += $(BASIC_CFLAGS)
602ALL_LDFLAGS += $(BASIC_LDFLAGS)
603
604export TAR INSTALL DESTDIR SHELL_PATH
605
606
607### Build rules
608
609SHELL = $(SHELL_PATH)
610
611all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS
612ifneq (,$X)
613 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
614endif
615
616all::
617
618please_set_SHELL_PATH_to_a_more_modern_shell:
619 @$$(:)
620
621shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
622
623strip: $(PROGRAMS) perf$X
624 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) perf$X
625
626perf.o: perf.c common-cmds.h PERF-CFLAGS
627 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
628 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
629 $(ALL_CFLAGS) -c $(filter %.c,$^)
630
631perf$X: perf.o $(BUILTIN_OBJS) $(PERFLIBS)
632 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ perf.o \
633 $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
634
635builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS
636 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
637 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
638 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
639 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
640
641$(BUILT_INS): perf$X
642 $(QUIET_BUILT_IN)$(RM) $@ && \
643 ln perf$X $@ 2>/dev/null || \
644 ln -s perf$X $@ 2>/dev/null || \
645 cp perf$X $@
646
647common-cmds.h: util/generate-cmdlist.sh command-list.txt
648
649common-cmds.h: $(wildcard Documentation/perf-*.txt)
650 $(QUIET_GEN)util/generate-cmdlist.sh > $@+ && mv $@+ $@
651
652$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
653 $(QUIET_GEN)$(RM) $@ $@+ && \
654 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
655 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
656 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
657 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
658 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
659 $@.sh >$@+ && \
660 chmod +x $@+ && \
661 mv $@+ $@
662
663configure: configure.ac
664 $(QUIET_GEN)$(RM) $@ $<+ && \
665 sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
666 $< > $<+ && \
667 autoconf -o $@ $<+ && \
668 $(RM) $<+
669
670# These can record PERF_VERSION
671perf.o perf.spec \
672 $(patsubst %.sh,%,$(SCRIPT_SH)) \
673 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
674 : PERF-VERSION-FILE
675
676%.o: %.c PERF-CFLAGS
677 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
678%.s: %.c PERF-CFLAGS
679 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
680%.o: %.S
681 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
682
683util/exec_cmd.o: util/exec_cmd.c PERF-CFLAGS
684 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
685 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
686 '-DBINDIR="$(bindir_relative_SQ)"' \
687 '-DPREFIX="$(prefix_SQ)"' \
688 $<
689
690builtin-init-db.o: builtin-init-db.c PERF-CFLAGS
691 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
692
693util/config.o: util/config.c PERF-CFLAGS
694 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
695
696perf-%$X: %.o $(PERFLIBS)
697 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
698
699$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
700$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
701builtin-revert.o wt-status.o: wt-status.h
702
703$(LIB_FILE): $(LIB_OBJS)
704 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
705
706doc:
707 $(MAKE) -C Documentation all
708
709man:
710 $(MAKE) -C Documentation man
711
712html:
713 $(MAKE) -C Documentation html
714
715info:
716 $(MAKE) -C Documentation info
717
718pdf:
719 $(MAKE) -C Documentation pdf
720
721TAGS:
722 $(RM) TAGS
723 $(FIND) . -name '*.[hcS]' -print | xargs etags -a
724
725tags:
726 $(RM) tags
727 $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
728
729cscope:
730 $(RM) cscope*
731 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
732
733### Detect prefix changes
734TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
735 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
736
737PERF-CFLAGS: .FORCE-PERF-CFLAGS
738 @FLAGS='$(TRACK_CFLAGS)'; \
739 if test x"$$FLAGS" != x"`cat PERF-CFLAGS 2>/dev/null`" ; then \
740 echo 1>&2 " * new build flags or prefix"; \
741 echo "$$FLAGS" >PERF-CFLAGS; \
742 fi
743
744# We need to apply sq twice, once to protect from the shell
745# that runs PERF-BUILD-OPTIONS, and then again to protect it
746# and the first level quoting from the shell that runs "echo".
747PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
748 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
749 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
750 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
751 @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
752
753### Testing rules
754
755#
756# None right now:
757#
758# TEST_PROGRAMS += test-something$X
759
760all:: $(TEST_PROGRAMS)
761
762# GNU make supports exporting all variables by "export" without parameters.
763# However, the environment gets quite big, and some programs have problems
764# with that.
765
766export NO_SVN_TESTS
767
768check: common-cmds.h
769 if sparse; \
770 then \
771 for i in *.c */*.c; \
772 do \
773 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
774 done; \
775 else \
776 echo 2>&1 "Did you mean 'make test'?"; \
777 exit 1; \
778 fi
779
780remove-dashes:
781 ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
782
783### Installation rules
784
785ifneq ($(filter /%,$(firstword $(template_dir))),)
786template_instdir = $(template_dir)
787else
788template_instdir = $(prefix)/$(template_dir)
789endif
790export template_instdir
791
792ifneq ($(filter /%,$(firstword $(perfexecdir))),)
793perfexec_instdir = $(perfexecdir)
794else
795perfexec_instdir = $(prefix)/$(perfexecdir)
796endif
797perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
798export perfexec_instdir
799
800install: all
801 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
802 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
803ifdef BUILT_INS
804 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
805 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
806ifneq (,$X)
807 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
808endif
809endif
810
811install-doc:
812 $(MAKE) -C Documentation install
813
814install-man:
815 $(MAKE) -C Documentation install-man
816
817install-html:
818 $(MAKE) -C Documentation install-html
819
820install-info:
821 $(MAKE) -C Documentation install-info
822
823install-pdf:
824 $(MAKE) -C Documentation install-pdf
825
826quick-install-doc:
827 $(MAKE) -C Documentation quick-install
828
829quick-install-man:
830 $(MAKE) -C Documentation quick-install-man
831
832quick-install-html:
833 $(MAKE) -C Documentation quick-install-html
834
835
836### Maintainer's dist rules
837#
838# None right now
839#
840#
841# perf.spec: perf.spec.in
842# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+
843# mv $@+ $@
844#
845# PERF_TARNAME=perf-$(PERF_VERSION)
846# dist: perf.spec perf-archive$(X) configure
847# ./perf-archive --format=tar \
848# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar
849# @mkdir -p $(PERF_TARNAME)
850# @cp perf.spec configure $(PERF_TARNAME)
851# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version
852# $(TAR) rf $(PERF_TARNAME).tar \
853# $(PERF_TARNAME)/perf.spec \
854# $(PERF_TARNAME)/configure \
855# $(PERF_TARNAME)/version
856# @$(RM) -r $(PERF_TARNAME)
857# gzip -f -9 $(PERF_TARNAME).tar
858#
859# htmldocs = perf-htmldocs-$(PERF_VERSION)
860# manpages = perf-manpages-$(PERF_VERSION)
861# dist-doc:
862# $(RM) -r .doc-tmp-dir
863# mkdir .doc-tmp-dir
864# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
865# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
866# gzip -n -9 -f $(htmldocs).tar
867# :
868# $(RM) -r .doc-tmp-dir
869# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
870# $(MAKE) -C Documentation DESTDIR=./ \
871# man1dir=../.doc-tmp-dir/man1 \
872# man5dir=../.doc-tmp-dir/man5 \
873# man7dir=../.doc-tmp-dir/man7 \
874# install
875# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
876# gzip -n -9 -f $(manpages).tar
877# $(RM) -r .doc-tmp-dir
878#
879# rpm: dist
880# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz
881
882### Cleaning rules
883
884distclean: clean
885# $(RM) configure
886
887clean:
888 $(RM) *.o */*.o $(LIB_FILE)
889 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
890 $(RM) $(TEST_PROGRAMS)
891 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
892 $(RM) -r autom4te.cache
893 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
894 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
895 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
896 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
897 $(MAKE) -C Documentation/ clean
898 $(RM) PERF-VERSION-FILE PERF-CFLAGS PERF-BUILD-OPTIONS
899
900.PHONY: all install clean strip
901.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
902.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
903.PHONY: .FORCE-PERF-BUILD-OPTIONS
904
905### Make sure built-ins do not have dups and listed in perf.c
906#
907check-builtins::
908 ./check-builtins.sh
909
910### Test suite coverage testing
911#
912# None right now
913#
914# .PHONY: coverage coverage-clean coverage-build coverage-report
915#
916# coverage:
917# $(MAKE) coverage-build
918# $(MAKE) coverage-report
919#
920# coverage-clean:
921# rm -f *.gcda *.gcno
922#
923# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
924# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
925#
926# coverage-build: coverage-clean
927# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
928# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
929# -j1 test
930#
931# coverage-report:
932# gcov -b *.c */*.c
933# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \
934# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
935# | tee coverage-untested-functions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
new file mode 100644
index 000000000000..7e58e3ad1508
--- /dev/null
+++ b/tools/perf/builtin-annotate.c
@@ -0,0 +1,1522 @@
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 "util/list.h"
14#include "util/cache.h"
15#include "util/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
28#define MIN_GREEN 0.5
29#define MIN_RED 5.0
30
31
32static char const *input_name = "perf.data";
33static char *vmlinux = "vmlinux";
34
35static char default_sort_order[] = "comm,symbol";
36static char *sort_order = default_sort_order;
37
38static int input;
39static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
40
41static int dump_trace = 0;
42#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
43
44static int verbose;
45
46static int print_line;
47
48static unsigned long page_size;
49static unsigned long mmap_window = 32;
50
51struct ip_event {
52 struct perf_event_header header;
53 u64 ip;
54 u32 pid, tid;
55};
56
57struct mmap_event {
58 struct perf_event_header header;
59 u32 pid, tid;
60 u64 start;
61 u64 len;
62 u64 pgoff;
63 char filename[PATH_MAX];
64};
65
66struct comm_event {
67 struct perf_event_header header;
68 u32 pid, tid;
69 char comm[16];
70};
71
72struct fork_event {
73 struct perf_event_header header;
74 u32 pid, ppid;
75};
76
77struct period_event {
78 struct perf_event_header header;
79 u64 time;
80 u64 id;
81 u64 sample_period;
82};
83
84typedef union event_union {
85 struct perf_event_header header;
86 struct ip_event ip;
87 struct mmap_event mmap;
88 struct comm_event comm;
89 struct fork_event fork;
90 struct period_event period;
91} event_t;
92
93
94struct sym_ext {
95 struct rb_node node;
96 double percent;
97 char *path;
98};
99
100static LIST_HEAD(dsos);
101static struct dso *kernel_dso;
102static struct dso *vdso;
103
104
105static void dsos__add(struct dso *dso)
106{
107 list_add_tail(&dso->node, &dsos);
108}
109
110static struct dso *dsos__find(const char *name)
111{
112 struct dso *pos;
113
114 list_for_each_entry(pos, &dsos, node)
115 if (strcmp(pos->name, name) == 0)
116 return pos;
117 return NULL;
118}
119
120static struct dso *dsos__findnew(const char *name)
121{
122 struct dso *dso = dsos__find(name);
123 int nr;
124
125 if (dso)
126 return dso;
127
128 dso = dso__new(name, 0);
129 if (!dso)
130 goto out_delete_dso;
131
132 nr = dso__load(dso, NULL, verbose);
133 if (nr < 0) {
134 if (verbose)
135 fprintf(stderr, "Failed to open: %s\n", name);
136 goto out_delete_dso;
137 }
138 if (!nr && verbose) {
139 fprintf(stderr,
140 "No symbols found in: %s, maybe install a debug package?\n",
141 name);
142 }
143
144 dsos__add(dso);
145
146 return dso;
147
148out_delete_dso:
149 dso__delete(dso);
150 return NULL;
151}
152
153static void dsos__fprintf(FILE *fp)
154{
155 struct dso *pos;
156
157 list_for_each_entry(pos, &dsos, node)
158 dso__fprintf(pos, fp);
159}
160
161static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
162{
163 return dso__find_symbol(kernel_dso, ip);
164}
165
166static int load_kernel(void)
167{
168 int err;
169
170 kernel_dso = dso__new("[kernel]", 0);
171 if (!kernel_dso)
172 return -1;
173
174 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
175 if (err) {
176 dso__delete(kernel_dso);
177 kernel_dso = NULL;
178 } else
179 dsos__add(kernel_dso);
180
181 vdso = dso__new("[vdso]", 0);
182 if (!vdso)
183 return -1;
184
185 vdso->find_symbol = vdso__find_symbol;
186
187 dsos__add(vdso);
188
189 return err;
190}
191
192struct map {
193 struct list_head node;
194 u64 start;
195 u64 end;
196 u64 pgoff;
197 u64 (*map_ip)(struct map *, u64);
198 struct dso *dso;
199};
200
201static u64 map__map_ip(struct map *map, u64 ip)
202{
203 return ip - map->start + map->pgoff;
204}
205
206static u64 vdso__map_ip(struct map *map, u64 ip)
207{
208 return ip;
209}
210
211static struct map *map__new(struct mmap_event *event)
212{
213 struct map *self = malloc(sizeof(*self));
214
215 if (self != NULL) {
216 const char *filename = event->filename;
217
218 self->start = event->start;
219 self->end = event->start + event->len;
220 self->pgoff = event->pgoff;
221
222 self->dso = dsos__findnew(filename);
223 if (self->dso == NULL)
224 goto out_delete;
225
226 if (self->dso == vdso)
227 self->map_ip = vdso__map_ip;
228 else
229 self->map_ip = map__map_ip;
230 }
231 return self;
232out_delete:
233 free(self);
234 return NULL;
235}
236
237static struct map *map__clone(struct map *self)
238{
239 struct map *map = malloc(sizeof(*self));
240
241 if (!map)
242 return NULL;
243
244 memcpy(map, self, sizeof(*self));
245
246 return map;
247}
248
249static int map__overlap(struct map *l, struct map *r)
250{
251 if (l->start > r->start) {
252 struct map *t = l;
253 l = r;
254 r = t;
255 }
256
257 if (l->end > r->start)
258 return 1;
259
260 return 0;
261}
262
263static size_t map__fprintf(struct map *self, FILE *fp)
264{
265 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
266 self->start, self->end, self->pgoff, self->dso->name);
267}
268
269
270struct thread {
271 struct rb_node rb_node;
272 struct list_head maps;
273 pid_t pid;
274 char *comm;
275};
276
277static struct thread *thread__new(pid_t pid)
278{
279 struct thread *self = malloc(sizeof(*self));
280
281 if (self != NULL) {
282 self->pid = pid;
283 self->comm = malloc(32);
284 if (self->comm)
285 snprintf(self->comm, 32, ":%d", self->pid);
286 INIT_LIST_HEAD(&self->maps);
287 }
288
289 return self;
290}
291
292static int thread__set_comm(struct thread *self, const char *comm)
293{
294 if (self->comm)
295 free(self->comm);
296 self->comm = strdup(comm);
297 return self->comm ? 0 : -ENOMEM;
298}
299
300static size_t thread__fprintf(struct thread *self, FILE *fp)
301{
302 struct map *pos;
303 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
304
305 list_for_each_entry(pos, &self->maps, node)
306 ret += map__fprintf(pos, fp);
307
308 return ret;
309}
310
311
312static struct rb_root threads;
313static struct thread *last_match;
314
315static struct thread *threads__findnew(pid_t pid)
316{
317 struct rb_node **p = &threads.rb_node;
318 struct rb_node *parent = NULL;
319 struct thread *th;
320
321 /*
322 * Font-end cache - PID lookups come in blocks,
323 * so most of the time we dont have to look up
324 * the full rbtree:
325 */
326 if (last_match && last_match->pid == pid)
327 return last_match;
328
329 while (*p != NULL) {
330 parent = *p;
331 th = rb_entry(parent, struct thread, rb_node);
332
333 if (th->pid == pid) {
334 last_match = th;
335 return th;
336 }
337
338 if (pid < th->pid)
339 p = &(*p)->rb_left;
340 else
341 p = &(*p)->rb_right;
342 }
343
344 th = thread__new(pid);
345 if (th != NULL) {
346 rb_link_node(&th->rb_node, parent, p);
347 rb_insert_color(&th->rb_node, &threads);
348 last_match = th;
349 }
350
351 return th;
352}
353
354static void thread__insert_map(struct thread *self, struct map *map)
355{
356 struct map *pos, *tmp;
357
358 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
359 if (map__overlap(pos, map)) {
360 list_del_init(&pos->node);
361 /* XXX leaks dsos */
362 free(pos);
363 }
364 }
365
366 list_add_tail(&map->node, &self->maps);
367}
368
369static int thread__fork(struct thread *self, struct thread *parent)
370{
371 struct map *map;
372
373 if (self->comm)
374 free(self->comm);
375 self->comm = strdup(parent->comm);
376 if (!self->comm)
377 return -ENOMEM;
378
379 list_for_each_entry(map, &parent->maps, node) {
380 struct map *new = map__clone(map);
381 if (!new)
382 return -ENOMEM;
383 thread__insert_map(self, new);
384 }
385
386 return 0;
387}
388
389static struct map *thread__find_map(struct thread *self, u64 ip)
390{
391 struct map *pos;
392
393 if (self == NULL)
394 return NULL;
395
396 list_for_each_entry(pos, &self->maps, node)
397 if (ip >= pos->start && ip <= pos->end)
398 return pos;
399
400 return NULL;
401}
402
403static size_t threads__fprintf(FILE *fp)
404{
405 size_t ret = 0;
406 struct rb_node *nd;
407
408 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
409 struct thread *pos = rb_entry(nd, struct thread, rb_node);
410
411 ret += thread__fprintf(pos, fp);
412 }
413
414 return ret;
415}
416
417/*
418 * histogram, sorted on item, collects counts
419 */
420
421static struct rb_root hist;
422
423struct hist_entry {
424 struct rb_node rb_node;
425
426 struct thread *thread;
427 struct map *map;
428 struct dso *dso;
429 struct symbol *sym;
430 u64 ip;
431 char level;
432
433 uint32_t count;
434};
435
436/*
437 * configurable sorting bits
438 */
439
440struct sort_entry {
441 struct list_head list;
442
443 char *header;
444
445 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
446 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
447 size_t (*print)(FILE *fp, struct hist_entry *);
448};
449
450/* --sort pid */
451
452static int64_t
453sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
454{
455 return right->thread->pid - left->thread->pid;
456}
457
458static size_t
459sort__thread_print(FILE *fp, struct hist_entry *self)
460{
461 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
462}
463
464static struct sort_entry sort_thread = {
465 .header = " Command: Pid",
466 .cmp = sort__thread_cmp,
467 .print = sort__thread_print,
468};
469
470/* --sort comm */
471
472static int64_t
473sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
474{
475 return right->thread->pid - left->thread->pid;
476}
477
478static int64_t
479sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
480{
481 char *comm_l = left->thread->comm;
482 char *comm_r = right->thread->comm;
483
484 if (!comm_l || !comm_r) {
485 if (!comm_l && !comm_r)
486 return 0;
487 else if (!comm_l)
488 return -1;
489 else
490 return 1;
491 }
492
493 return strcmp(comm_l, comm_r);
494}
495
496static size_t
497sort__comm_print(FILE *fp, struct hist_entry *self)
498{
499 return fprintf(fp, "%16s", self->thread->comm);
500}
501
502static struct sort_entry sort_comm = {
503 .header = " Command",
504 .cmp = sort__comm_cmp,
505 .collapse = sort__comm_collapse,
506 .print = sort__comm_print,
507};
508
509/* --sort dso */
510
511static int64_t
512sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
513{
514 struct dso *dso_l = left->dso;
515 struct dso *dso_r = right->dso;
516
517 if (!dso_l || !dso_r) {
518 if (!dso_l && !dso_r)
519 return 0;
520 else if (!dso_l)
521 return -1;
522 else
523 return 1;
524 }
525
526 return strcmp(dso_l->name, dso_r->name);
527}
528
529static size_t
530sort__dso_print(FILE *fp, struct hist_entry *self)
531{
532 if (self->dso)
533 return fprintf(fp, "%-25s", self->dso->name);
534
535 return fprintf(fp, "%016llx ", (u64)self->ip);
536}
537
538static struct sort_entry sort_dso = {
539 .header = "Shared Object ",
540 .cmp = sort__dso_cmp,
541 .print = sort__dso_print,
542};
543
544/* --sort symbol */
545
546static int64_t
547sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
548{
549 u64 ip_l, ip_r;
550
551 if (left->sym == right->sym)
552 return 0;
553
554 ip_l = left->sym ? left->sym->start : left->ip;
555 ip_r = right->sym ? right->sym->start : right->ip;
556
557 return (int64_t)(ip_r - ip_l);
558}
559
560static size_t
561sort__sym_print(FILE *fp, struct hist_entry *self)
562{
563 size_t ret = 0;
564
565 if (verbose)
566 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
567
568 if (self->sym) {
569 ret += fprintf(fp, "[%c] %s",
570 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
571 } else {
572 ret += fprintf(fp, "%#016llx", (u64)self->ip);
573 }
574
575 return ret;
576}
577
578static struct sort_entry sort_sym = {
579 .header = "Symbol",
580 .cmp = sort__sym_cmp,
581 .print = sort__sym_print,
582};
583
584static int sort__need_collapse = 0;
585
586struct sort_dimension {
587 char *name;
588 struct sort_entry *entry;
589 int taken;
590};
591
592static struct sort_dimension sort_dimensions[] = {
593 { .name = "pid", .entry = &sort_thread, },
594 { .name = "comm", .entry = &sort_comm, },
595 { .name = "dso", .entry = &sort_dso, },
596 { .name = "symbol", .entry = &sort_sym, },
597};
598
599static LIST_HEAD(hist_entry__sort_list);
600
601static int sort_dimension__add(char *tok)
602{
603 int i;
604
605 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
606 struct sort_dimension *sd = &sort_dimensions[i];
607
608 if (sd->taken)
609 continue;
610
611 if (strncasecmp(tok, sd->name, strlen(tok)))
612 continue;
613
614 if (sd->entry->collapse)
615 sort__need_collapse = 1;
616
617 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
618 sd->taken = 1;
619
620 return 0;
621 }
622
623 return -ESRCH;
624}
625
626static int64_t
627hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
628{
629 struct sort_entry *se;
630 int64_t cmp = 0;
631
632 list_for_each_entry(se, &hist_entry__sort_list, list) {
633 cmp = se->cmp(left, right);
634 if (cmp)
635 break;
636 }
637
638 return cmp;
639}
640
641static int64_t
642hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
643{
644 struct sort_entry *se;
645 int64_t cmp = 0;
646
647 list_for_each_entry(se, &hist_entry__sort_list, list) {
648 int64_t (*f)(struct hist_entry *, struct hist_entry *);
649
650 f = se->collapse ?: se->cmp;
651
652 cmp = f(left, right);
653 if (cmp)
654 break;
655 }
656
657 return cmp;
658}
659
660/*
661 * collect histogram counts
662 */
663static void hist_hit(struct hist_entry *he, u64 ip)
664{
665 unsigned int sym_size, offset;
666 struct symbol *sym = he->sym;
667
668 he->count++;
669
670 if (!sym || !sym->hist)
671 return;
672
673 sym_size = sym->end - sym->start;
674 offset = ip - sym->start;
675
676 if (offset >= sym_size)
677 return;
678
679 sym->hist_sum++;
680 sym->hist[offset]++;
681
682 if (verbose >= 3)
683 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
684 (void *)(unsigned long)he->sym->start,
685 he->sym->name,
686 (void *)(unsigned long)ip, ip - he->sym->start,
687 sym->hist[offset]);
688}
689
690static int
691hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
692 struct symbol *sym, u64 ip, char level)
693{
694 struct rb_node **p = &hist.rb_node;
695 struct rb_node *parent = NULL;
696 struct hist_entry *he;
697 struct hist_entry entry = {
698 .thread = thread,
699 .map = map,
700 .dso = dso,
701 .sym = sym,
702 .ip = ip,
703 .level = level,
704 .count = 1,
705 };
706 int cmp;
707
708 while (*p != NULL) {
709 parent = *p;
710 he = rb_entry(parent, struct hist_entry, rb_node);
711
712 cmp = hist_entry__cmp(&entry, he);
713
714 if (!cmp) {
715 hist_hit(he, ip);
716
717 return 0;
718 }
719
720 if (cmp < 0)
721 p = &(*p)->rb_left;
722 else
723 p = &(*p)->rb_right;
724 }
725
726 he = malloc(sizeof(*he));
727 if (!he)
728 return -ENOMEM;
729 *he = entry;
730 rb_link_node(&he->rb_node, parent, p);
731 rb_insert_color(&he->rb_node, &hist);
732
733 return 0;
734}
735
736static void hist_entry__free(struct hist_entry *he)
737{
738 free(he);
739}
740
741/*
742 * collapse the histogram
743 */
744
745static struct rb_root collapse_hists;
746
747static void collapse__insert_entry(struct hist_entry *he)
748{
749 struct rb_node **p = &collapse_hists.rb_node;
750 struct rb_node *parent = NULL;
751 struct hist_entry *iter;
752 int64_t cmp;
753
754 while (*p != NULL) {
755 parent = *p;
756 iter = rb_entry(parent, struct hist_entry, rb_node);
757
758 cmp = hist_entry__collapse(iter, he);
759
760 if (!cmp) {
761 iter->count += he->count;
762 hist_entry__free(he);
763 return;
764 }
765
766 if (cmp < 0)
767 p = &(*p)->rb_left;
768 else
769 p = &(*p)->rb_right;
770 }
771
772 rb_link_node(&he->rb_node, parent, p);
773 rb_insert_color(&he->rb_node, &collapse_hists);
774}
775
776static void collapse__resort(void)
777{
778 struct rb_node *next;
779 struct hist_entry *n;
780
781 if (!sort__need_collapse)
782 return;
783
784 next = rb_first(&hist);
785 while (next) {
786 n = rb_entry(next, struct hist_entry, rb_node);
787 next = rb_next(&n->rb_node);
788
789 rb_erase(&n->rb_node, &hist);
790 collapse__insert_entry(n);
791 }
792}
793
794/*
795 * reverse the map, sort on count.
796 */
797
798static struct rb_root output_hists;
799
800static void output__insert_entry(struct hist_entry *he)
801{
802 struct rb_node **p = &output_hists.rb_node;
803 struct rb_node *parent = NULL;
804 struct hist_entry *iter;
805
806 while (*p != NULL) {
807 parent = *p;
808 iter = rb_entry(parent, struct hist_entry, rb_node);
809
810 if (he->count > iter->count)
811 p = &(*p)->rb_left;
812 else
813 p = &(*p)->rb_right;
814 }
815
816 rb_link_node(&he->rb_node, parent, p);
817 rb_insert_color(&he->rb_node, &output_hists);
818}
819
820static void output__resort(void)
821{
822 struct rb_node *next;
823 struct hist_entry *n;
824 struct rb_root *tree = &hist;
825
826 if (sort__need_collapse)
827 tree = &collapse_hists;
828
829 next = rb_first(tree);
830
831 while (next) {
832 n = rb_entry(next, struct hist_entry, rb_node);
833 next = rb_next(&n->rb_node);
834
835 rb_erase(&n->rb_node, tree);
836 output__insert_entry(n);
837 }
838}
839
840static void register_idle_thread(void)
841{
842 struct thread *thread = threads__findnew(0);
843
844 if (thread == NULL ||
845 thread__set_comm(thread, "[idle]")) {
846 fprintf(stderr, "problem inserting idle task.\n");
847 exit(-1);
848 }
849}
850
851static unsigned long total = 0,
852 total_mmap = 0,
853 total_comm = 0,
854 total_fork = 0,
855 total_unknown = 0;
856
857static int
858process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
859{
860 char level;
861 int show = 0;
862 struct dso *dso = NULL;
863 struct thread *thread = threads__findnew(event->ip.pid);
864 u64 ip = event->ip.ip;
865 struct map *map = NULL;
866
867 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
868 (void *)(offset + head),
869 (void *)(long)(event->header.size),
870 event->header.misc,
871 event->ip.pid,
872 (void *)(long)ip);
873
874 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
875
876 if (thread == NULL) {
877 fprintf(stderr, "problem processing %d event, skipping it.\n",
878 event->header.type);
879 return -1;
880 }
881
882 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
883 show = SHOW_KERNEL;
884 level = 'k';
885
886 dso = kernel_dso;
887
888 dprintf(" ...... dso: %s\n", dso->name);
889
890 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
891
892 show = SHOW_USER;
893 level = '.';
894
895 map = thread__find_map(thread, ip);
896 if (map != NULL) {
897 ip = map->map_ip(map, ip);
898 dso = map->dso;
899 } else {
900 /*
901 * If this is outside of all known maps,
902 * and is a negative address, try to look it
903 * up in the kernel dso, as it might be a
904 * vsyscall (which executes in user-mode):
905 */
906 if ((long long)ip < 0)
907 dso = kernel_dso;
908 }
909 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
910
911 } else {
912 show = SHOW_HV;
913 level = 'H';
914 dprintf(" ...... dso: [hypervisor]\n");
915 }
916
917 if (show & show_mask) {
918 struct symbol *sym = NULL;
919
920 if (dso)
921 sym = dso->find_symbol(dso, ip);
922
923 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
924 fprintf(stderr,
925 "problem incrementing symbol count, skipping event\n");
926 return -1;
927 }
928 }
929 total++;
930
931 return 0;
932}
933
934static int
935process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
936{
937 struct thread *thread = threads__findnew(event->mmap.pid);
938 struct map *map = map__new(&event->mmap);
939
940 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
941 (void *)(offset + head),
942 (void *)(long)(event->header.size),
943 event->mmap.pid,
944 (void *)(long)event->mmap.start,
945 (void *)(long)event->mmap.len,
946 (void *)(long)event->mmap.pgoff,
947 event->mmap.filename);
948
949 if (thread == NULL || map == NULL) {
950 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
951 return 0;
952 }
953
954 thread__insert_map(thread, map);
955 total_mmap++;
956
957 return 0;
958}
959
960static int
961process_comm_event(event_t *event, unsigned long offset, unsigned long head)
962{
963 struct thread *thread = threads__findnew(event->comm.pid);
964
965 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
966 (void *)(offset + head),
967 (void *)(long)(event->header.size),
968 event->comm.comm, event->comm.pid);
969
970 if (thread == NULL ||
971 thread__set_comm(thread, event->comm.comm)) {
972 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
973 return -1;
974 }
975 total_comm++;
976
977 return 0;
978}
979
980static int
981process_fork_event(event_t *event, unsigned long offset, unsigned long head)
982{
983 struct thread *thread = threads__findnew(event->fork.pid);
984 struct thread *parent = threads__findnew(event->fork.ppid);
985
986 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n",
987 (void *)(offset + head),
988 (void *)(long)(event->header.size),
989 event->fork.pid, event->fork.ppid);
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_period_event(event_t *event, unsigned long offset, unsigned long head)
1002{
1003 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
1004 (void *)(offset + head),
1005 (void *)(long)(event->header.size),
1006 event->period.time,
1007 event->period.id,
1008 event->period.sample_period);
1009
1010 return 0;
1011}
1012
1013static int
1014process_event(event_t *event, unsigned long offset, unsigned long head)
1015{
1016 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1017 return process_overflow_event(event, offset, head);
1018
1019 switch (event->header.type) {
1020 case PERF_EVENT_MMAP:
1021 return process_mmap_event(event, offset, head);
1022
1023 case PERF_EVENT_COMM:
1024 return process_comm_event(event, offset, head);
1025
1026 case PERF_EVENT_FORK:
1027 return process_fork_event(event, offset, head);
1028
1029 case PERF_EVENT_PERIOD:
1030 return process_period_event(event, offset, head);
1031 /*
1032 * We dont process them right now but they are fine:
1033 */
1034
1035 case PERF_EVENT_THROTTLE:
1036 case PERF_EVENT_UNTHROTTLE:
1037 return 0;
1038
1039 default:
1040 return -1;
1041 }
1042
1043 return 0;
1044}
1045
1046static char *get_color(double percent)
1047{
1048 char *color = PERF_COLOR_NORMAL;
1049
1050 /*
1051 * We color high-overhead entries in red, mid-overhead
1052 * entries in green - and keep the low overhead places
1053 * normal:
1054 */
1055 if (percent >= MIN_RED)
1056 color = PERF_COLOR_RED;
1057 else {
1058 if (percent > MIN_GREEN)
1059 color = PERF_COLOR_GREEN;
1060 }
1061 return color;
1062}
1063
1064static int
1065parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1066{
1067 char *line = NULL, *tmp, *tmp2;
1068 static const char *prev_line;
1069 static const char *prev_color;
1070 unsigned int offset;
1071 size_t line_len;
1072 u64 line_ip;
1073 int ret;
1074 char *c;
1075
1076 if (getline(&line, &line_len, file) < 0)
1077 return -1;
1078 if (!line)
1079 return -1;
1080
1081 c = strchr(line, '\n');
1082 if (c)
1083 *c = 0;
1084
1085 line_ip = -1;
1086 offset = 0;
1087 ret = -2;
1088
1089 /*
1090 * Strip leading spaces:
1091 */
1092 tmp = line;
1093 while (*tmp) {
1094 if (*tmp != ' ')
1095 break;
1096 tmp++;
1097 }
1098
1099 if (*tmp) {
1100 /*
1101 * Parse hexa addresses followed by ':'
1102 */
1103 line_ip = strtoull(tmp, &tmp2, 16);
1104 if (*tmp2 != ':')
1105 line_ip = -1;
1106 }
1107
1108 if (line_ip != -1) {
1109 const char *path = NULL;
1110 unsigned int hits = 0;
1111 double percent = 0.0;
1112 char *color;
1113 struct sym_ext *sym_ext = sym->priv;
1114
1115 offset = line_ip - start;
1116 if (offset < len)
1117 hits = sym->hist[offset];
1118
1119 if (offset < len && sym_ext) {
1120 path = sym_ext[offset].path;
1121 percent = sym_ext[offset].percent;
1122 } else if (sym->hist_sum)
1123 percent = 100.0 * hits / sym->hist_sum;
1124
1125 color = get_color(percent);
1126
1127 /*
1128 * Also color the filename and line if needed, with
1129 * the same color than the percentage. Don't print it
1130 * twice for close colored ip with the same filename:line
1131 */
1132 if (path) {
1133 if (!prev_line || strcmp(prev_line, path)
1134 || color != prev_color) {
1135 color_fprintf(stdout, color, " %s", path);
1136 prev_line = path;
1137 prev_color = color;
1138 }
1139 }
1140
1141 color_fprintf(stdout, color, " %7.2f", percent);
1142 printf(" : ");
1143 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line);
1144 } else {
1145 if (!*line)
1146 printf(" :\n");
1147 else
1148 printf(" : %s\n", line);
1149 }
1150
1151 return 0;
1152}
1153
1154static struct rb_root root_sym_ext;
1155
1156static void insert_source_line(struct sym_ext *sym_ext)
1157{
1158 struct sym_ext *iter;
1159 struct rb_node **p = &root_sym_ext.rb_node;
1160 struct rb_node *parent = NULL;
1161
1162 while (*p != NULL) {
1163 parent = *p;
1164 iter = rb_entry(parent, struct sym_ext, node);
1165
1166 if (sym_ext->percent > iter->percent)
1167 p = &(*p)->rb_left;
1168 else
1169 p = &(*p)->rb_right;
1170 }
1171
1172 rb_link_node(&sym_ext->node, parent, p);
1173 rb_insert_color(&sym_ext->node, &root_sym_ext);
1174}
1175
1176static void free_source_line(struct symbol *sym, int len)
1177{
1178 struct sym_ext *sym_ext = sym->priv;
1179 int i;
1180
1181 if (!sym_ext)
1182 return;
1183
1184 for (i = 0; i < len; i++)
1185 free(sym_ext[i].path);
1186 free(sym_ext);
1187
1188 sym->priv = NULL;
1189 root_sym_ext = RB_ROOT;
1190}
1191
1192/* Get the filename:line for the colored entries */
1193static void
1194get_source_line(struct symbol *sym, u64 start, int len, char *filename)
1195{
1196 int i;
1197 char cmd[PATH_MAX * 2];
1198 struct sym_ext *sym_ext;
1199
1200 if (!sym->hist_sum)
1201 return;
1202
1203 sym->priv = calloc(len, sizeof(struct sym_ext));
1204 if (!sym->priv)
1205 return;
1206
1207 sym_ext = sym->priv;
1208
1209 for (i = 0; i < len; i++) {
1210 char *path = NULL;
1211 size_t line_len;
1212 u64 offset;
1213 FILE *fp;
1214
1215 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum;
1216 if (sym_ext[i].percent <= 0.5)
1217 continue;
1218
1219 offset = start + i;
1220 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
1221 fp = popen(cmd, "r");
1222 if (!fp)
1223 continue;
1224
1225 if (getline(&path, &line_len, fp) < 0 || !line_len)
1226 goto next;
1227
1228 sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
1229 if (!sym_ext[i].path)
1230 goto next;
1231
1232 strcpy(sym_ext[i].path, path);
1233 insert_source_line(&sym_ext[i]);
1234
1235 next:
1236 pclose(fp);
1237 }
1238}
1239
1240static void print_summary(char *filename)
1241{
1242 struct sym_ext *sym_ext;
1243 struct rb_node *node;
1244
1245 printf("\nSorted summary for file %s\n", filename);
1246 printf("----------------------------------------------\n\n");
1247
1248 if (RB_EMPTY_ROOT(&root_sym_ext)) {
1249 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
1250 return;
1251 }
1252
1253 node = rb_first(&root_sym_ext);
1254 while (node) {
1255 double percent;
1256 char *color;
1257 char *path;
1258
1259 sym_ext = rb_entry(node, struct sym_ext, node);
1260 percent = sym_ext->percent;
1261 color = get_color(percent);
1262 path = sym_ext->path;
1263
1264 color_fprintf(stdout, color, " %7.2f %s", percent, path);
1265 node = rb_next(node);
1266 }
1267}
1268
1269static void annotate_sym(struct dso *dso, struct symbol *sym)
1270{
1271 char *filename = dso->name;
1272 u64 start, end, len;
1273 char command[PATH_MAX*2];
1274 FILE *file;
1275
1276 if (!filename)
1277 return;
1278 if (dso == kernel_dso)
1279 filename = vmlinux;
1280
1281 start = sym->obj_start;
1282 if (!start)
1283 start = sym->start;
1284
1285 end = start + sym->end - sym->start + 1;
1286 len = sym->end - sym->start;
1287
1288 if (print_line) {
1289 get_source_line(sym, start, len, filename);
1290 print_summary(filename);
1291 }
1292
1293 printf("\n\n------------------------------------------------\n");
1294 printf(" Percent | Source code & Disassembly of %s\n", filename);
1295 printf("------------------------------------------------\n");
1296
1297 if (verbose >= 2)
1298 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1299
1300 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename);
1301
1302 if (verbose >= 3)
1303 printf("doing: %s\n", command);
1304
1305 file = popen(command, "r");
1306 if (!file)
1307 return;
1308
1309 while (!feof(file)) {
1310 if (parse_line(file, sym, start, len) < 0)
1311 break;
1312 }
1313
1314 pclose(file);
1315 if (print_line)
1316 free_source_line(sym, len);
1317}
1318
1319static void find_annotations(void)
1320{
1321 struct rb_node *nd;
1322 struct dso *dso;
1323 int count = 0;
1324
1325 list_for_each_entry(dso, &dsos, node) {
1326
1327 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
1328 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
1329
1330 if (sym->hist) {
1331 annotate_sym(dso, sym);
1332 count++;
1333 }
1334 }
1335 }
1336
1337 if (!count)
1338 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
1339}
1340
1341static int __cmd_annotate(void)
1342{
1343 int ret, rc = EXIT_FAILURE;
1344 unsigned long offset = 0;
1345 unsigned long head = 0;
1346 struct stat stat;
1347 event_t *event;
1348 uint32_t size;
1349 char *buf;
1350
1351 register_idle_thread();
1352
1353 input = open(input_name, O_RDONLY);
1354 if (input < 0) {
1355 perror("failed to open file");
1356 exit(-1);
1357 }
1358
1359 ret = fstat(input, &stat);
1360 if (ret < 0) {
1361 perror("failed to stat file");
1362 exit(-1);
1363 }
1364
1365 if (!stat.st_size) {
1366 fprintf(stderr, "zero-sized file, nothing to do!\n");
1367 exit(0);
1368 }
1369
1370 if (load_kernel() < 0) {
1371 perror("failed to load kernel symbols");
1372 return EXIT_FAILURE;
1373 }
1374
1375remap:
1376 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1377 MAP_SHARED, input, offset);
1378 if (buf == MAP_FAILED) {
1379 perror("failed to mmap file");
1380 exit(-1);
1381 }
1382
1383more:
1384 event = (event_t *)(buf + head);
1385
1386 size = event->header.size;
1387 if (!size)
1388 size = 8;
1389
1390 if (head + event->header.size >= page_size * mmap_window) {
1391 unsigned long shift = page_size * (head / page_size);
1392 int ret;
1393
1394 ret = munmap(buf, page_size * mmap_window);
1395 assert(ret == 0);
1396
1397 offset += shift;
1398 head -= shift;
1399 goto remap;
1400 }
1401
1402 size = event->header.size;
1403
1404 dprintf("%p [%p]: event: %d\n",
1405 (void *)(offset + head),
1406 (void *)(long)event->header.size,
1407 event->header.type);
1408
1409 if (!size || process_event(event, offset, head) < 0) {
1410
1411 dprintf("%p [%p]: skipping unknown header type: %d\n",
1412 (void *)(offset + head),
1413 (void *)(long)(event->header.size),
1414 event->header.type);
1415
1416 total_unknown++;
1417
1418 /*
1419 * assume we lost track of the stream, check alignment, and
1420 * increment a single u64 in the hope to catch on again 'soon'.
1421 */
1422
1423 if (unlikely(head & 7))
1424 head &= ~7ULL;
1425
1426 size = 8;
1427 }
1428
1429 head += size;
1430
1431 if (offset + head < stat.st_size)
1432 goto more;
1433
1434 rc = EXIT_SUCCESS;
1435 close(input);
1436
1437 dprintf(" IP events: %10ld\n", total);
1438 dprintf(" mmap events: %10ld\n", total_mmap);
1439 dprintf(" comm events: %10ld\n", total_comm);
1440 dprintf(" fork events: %10ld\n", total_fork);
1441 dprintf(" unknown events: %10ld\n", total_unknown);
1442
1443 if (dump_trace)
1444 return 0;
1445
1446 if (verbose >= 3)
1447 threads__fprintf(stdout);
1448
1449 if (verbose >= 2)
1450 dsos__fprintf(stdout);
1451
1452 collapse__resort();
1453 output__resort();
1454
1455 find_annotations();
1456
1457 return rc;
1458}
1459
1460static const char * const annotate_usage[] = {
1461 "perf annotate [<options>] <command>",
1462 NULL
1463};
1464
1465static const struct option options[] = {
1466 OPT_STRING('i', "input", &input_name, "file",
1467 "input file name"),
1468 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
1469 "symbol to annotate"),
1470 OPT_BOOLEAN('v', "verbose", &verbose,
1471 "be more verbose (show symbol address, etc)"),
1472 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1473 "dump raw trace in ASCII"),
1474 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1475 OPT_BOOLEAN('l', "print-line", &print_line,
1476 "print matching source lines (may be slow)"),
1477 OPT_END()
1478};
1479
1480static void setup_sorting(void)
1481{
1482 char *tmp, *tok, *str = strdup(sort_order);
1483
1484 for (tok = strtok_r(str, ", ", &tmp);
1485 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1486 if (sort_dimension__add(tok) < 0) {
1487 error("Unknown --sort key: `%s'", tok);
1488 usage_with_options(annotate_usage, options);
1489 }
1490 }
1491
1492 free(str);
1493}
1494
1495int cmd_annotate(int argc, const char **argv, const char *prefix)
1496{
1497 symbol__init();
1498
1499 page_size = getpagesize();
1500
1501 argc = parse_options(argc, argv, options, annotate_usage, 0);
1502
1503 setup_sorting();
1504
1505 if (argc) {
1506 /*
1507 * Special case: if there's an argument left then assume tha
1508 * it's a symbol filter:
1509 */
1510 if (argc > 1)
1511 usage_with_options(annotate_usage, options);
1512
1513 sym_hist_filter = argv[0];
1514 }
1515
1516 if (!sym_hist_filter)
1517 usage_with_options(annotate_usage, options);
1518
1519 setup_pager();
1520
1521 return __cmd_annotate();
1522}
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
new file mode 100644
index 000000000000..0f32dc3f3c4c
--- /dev/null
+++ b/tools/perf/builtin-help.c
@@ -0,0 +1,461 @@
1/*
2 * builtin-help.c
3 *
4 * Builtin help command
5 */
6#include "util/cache.h"
7#include "builtin.h"
8#include "util/exec_cmd.h"
9#include "common-cmds.h"
10#include "util/parse-options.h"
11#include "util/run-command.h"
12#include "util/help.h"
13
14static struct man_viewer_list {
15 struct man_viewer_list *next;
16 char name[FLEX_ARRAY];
17} *man_viewer_list;
18
19static struct man_viewer_info_list {
20 struct man_viewer_info_list *next;
21 const char *info;
22 char name[FLEX_ARRAY];
23} *man_viewer_info_list;
24
25enum help_format {
26 HELP_FORMAT_MAN,
27 HELP_FORMAT_INFO,
28 HELP_FORMAT_WEB,
29};
30
31static int show_all = 0;
32static enum help_format help_format = HELP_FORMAT_MAN;
33static struct option builtin_help_options[] = {
34 OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
35 OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
36 OPT_SET_INT('w', "web", &help_format, "show manual in web browser",
37 HELP_FORMAT_WEB),
38 OPT_SET_INT('i', "info", &help_format, "show info page",
39 HELP_FORMAT_INFO),
40 OPT_END(),
41};
42
43static const char * const builtin_help_usage[] = {
44 "perf help [--all] [--man|--web|--info] [command]",
45 NULL
46};
47
48static enum help_format parse_help_format(const char *format)
49{
50 if (!strcmp(format, "man"))
51 return HELP_FORMAT_MAN;
52 if (!strcmp(format, "info"))
53 return HELP_FORMAT_INFO;
54 if (!strcmp(format, "web") || !strcmp(format, "html"))
55 return HELP_FORMAT_WEB;
56 die("unrecognized help format '%s'", format);
57}
58
59static const char *get_man_viewer_info(const char *name)
60{
61 struct man_viewer_info_list *viewer;
62
63 for (viewer = man_viewer_info_list; viewer; viewer = viewer->next)
64 {
65 if (!strcasecmp(name, viewer->name))
66 return viewer->info;
67 }
68 return NULL;
69}
70
71static int check_emacsclient_version(void)
72{
73 struct strbuf buffer = STRBUF_INIT;
74 struct child_process ec_process;
75 const char *argv_ec[] = { "emacsclient", "--version", NULL };
76 int version;
77
78 /* emacsclient prints its version number on stderr */
79 memset(&ec_process, 0, sizeof(ec_process));
80 ec_process.argv = argv_ec;
81 ec_process.err = -1;
82 ec_process.stdout_to_stderr = 1;
83 if (start_command(&ec_process)) {
84 fprintf(stderr, "Failed to start emacsclient.\n");
85 return -1;
86 }
87 strbuf_read(&buffer, ec_process.err, 20);
88 close(ec_process.err);
89
90 /*
91 * Don't bother checking return value, because "emacsclient --version"
92 * seems to always exits with code 1.
93 */
94 finish_command(&ec_process);
95
96 if (prefixcmp(buffer.buf, "emacsclient")) {
97 fprintf(stderr, "Failed to parse emacsclient version.\n");
98 strbuf_release(&buffer);
99 return -1;
100 }
101
102 strbuf_remove(&buffer, 0, strlen("emacsclient"));
103 version = atoi(buffer.buf);
104
105 if (version < 22) {
106 fprintf(stderr,
107 "emacsclient version '%d' too old (< 22).\n",
108 version);
109 strbuf_release(&buffer);
110 return -1;
111 }
112
113 strbuf_release(&buffer);
114 return 0;
115}
116
117static void exec_woman_emacs(const char* path, const char *page)
118{
119 if (!check_emacsclient_version()) {
120 /* This works only with emacsclient version >= 22. */
121 struct strbuf man_page = STRBUF_INIT;
122
123 if (!path)
124 path = "emacsclient";
125 strbuf_addf(&man_page, "(woman \"%s\")", page);
126 execlp(path, "emacsclient", "-e", man_page.buf, NULL);
127 warning("failed to exec '%s': %s", path, strerror(errno));
128 }
129}
130
131static void exec_man_konqueror(const char* path, const char *page)
132{
133 const char *display = getenv("DISPLAY");
134 if (display && *display) {
135 struct strbuf man_page = STRBUF_INIT;
136 const char *filename = "kfmclient";
137
138 /* It's simpler to launch konqueror using kfmclient. */
139 if (path) {
140 const char *file = strrchr(path, '/');
141 if (file && !strcmp(file + 1, "konqueror")) {
142 char *new = strdup(path);
143 char *dest = strrchr(new, '/');
144
145 /* strlen("konqueror") == strlen("kfmclient") */
146 strcpy(dest + 1, "kfmclient");
147 path = new;
148 }
149 if (file)
150 filename = file;
151 } else
152 path = "kfmclient";
153 strbuf_addf(&man_page, "man:%s(1)", page);
154 execlp(path, filename, "newTab", man_page.buf, NULL);
155 warning("failed to exec '%s': %s", path, strerror(errno));
156 }
157}
158
159static void exec_man_man(const char* path, const char *page)
160{
161 if (!path)
162 path = "man";
163 execlp(path, "man", page, NULL);
164 warning("failed to exec '%s': %s", path, strerror(errno));
165}
166
167static void exec_man_cmd(const char *cmd, const char *page)
168{
169 struct strbuf shell_cmd = STRBUF_INIT;
170 strbuf_addf(&shell_cmd, "%s %s", cmd, page);
171 execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
172 warning("failed to exec '%s': %s", cmd, strerror(errno));
173}
174
175static void add_man_viewer(const char *name)
176{
177 struct man_viewer_list **p = &man_viewer_list;
178 size_t len = strlen(name);
179
180 while (*p)
181 p = &((*p)->next);
182 *p = calloc(1, (sizeof(**p) + len + 1));
183 strncpy((*p)->name, name, len);
184}
185
186static int supported_man_viewer(const char *name, size_t len)
187{
188 return (!strncasecmp("man", name, len) ||
189 !strncasecmp("woman", name, len) ||
190 !strncasecmp("konqueror", name, len));
191}
192
193static void do_add_man_viewer_info(const char *name,
194 size_t len,
195 const char *value)
196{
197 struct man_viewer_info_list *new = calloc(1, sizeof(*new) + len + 1);
198
199 strncpy(new->name, name, len);
200 new->info = strdup(value);
201 new->next = man_viewer_info_list;
202 man_viewer_info_list = new;
203}
204
205static int add_man_viewer_path(const char *name,
206 size_t len,
207 const char *value)
208{
209 if (supported_man_viewer(name, len))
210 do_add_man_viewer_info(name, len, value);
211 else
212 warning("'%s': path for unsupported man viewer.\n"
213 "Please consider using 'man.<tool>.cmd' instead.",
214 name);
215
216 return 0;
217}
218
219static int add_man_viewer_cmd(const char *name,
220 size_t len,
221 const char *value)
222{
223 if (supported_man_viewer(name, len))
224 warning("'%s': cmd for supported man viewer.\n"
225 "Please consider using 'man.<tool>.path' instead.",
226 name);
227 else
228 do_add_man_viewer_info(name, len, value);
229
230 return 0;
231}
232
233static int add_man_viewer_info(const char *var, const char *value)
234{
235 const char *name = var + 4;
236 const char *subkey = strrchr(name, '.');
237
238 if (!subkey)
239 return error("Config with no key for man viewer: %s", name);
240
241 if (!strcmp(subkey, ".path")) {
242 if (!value)
243 return config_error_nonbool(var);
244 return add_man_viewer_path(name, subkey - name, value);
245 }
246 if (!strcmp(subkey, ".cmd")) {
247 if (!value)
248 return config_error_nonbool(var);
249 return add_man_viewer_cmd(name, subkey - name, value);
250 }
251
252 warning("'%s': unsupported man viewer sub key.", subkey);
253 return 0;
254}
255
256static int perf_help_config(const char *var, const char *value, void *cb)
257{
258 if (!strcmp(var, "help.format")) {
259 if (!value)
260 return config_error_nonbool(var);
261 help_format = parse_help_format(value);
262 return 0;
263 }
264 if (!strcmp(var, "man.viewer")) {
265 if (!value)
266 return config_error_nonbool(var);
267 add_man_viewer(value);
268 return 0;
269 }
270 if (!prefixcmp(var, "man."))
271 return add_man_viewer_info(var, value);
272
273 return perf_default_config(var, value, cb);
274}
275
276static struct cmdnames main_cmds, other_cmds;
277
278void list_common_cmds_help(void)
279{
280 int i, longest = 0;
281
282 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
283 if (longest < strlen(common_cmds[i].name))
284 longest = strlen(common_cmds[i].name);
285 }
286
287 puts(" The most commonly used perf commands are:");
288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
289 printf(" %s ", common_cmds[i].name);
290 mput_char(' ', longest - strlen(common_cmds[i].name));
291 puts(common_cmds[i].help);
292 }
293}
294
295static int is_perf_command(const char *s)
296{
297 return is_in_cmdlist(&main_cmds, s) ||
298 is_in_cmdlist(&other_cmds, s);
299}
300
301static const char *prepend(const char *prefix, const char *cmd)
302{
303 size_t pre_len = strlen(prefix);
304 size_t cmd_len = strlen(cmd);
305 char *p = malloc(pre_len + cmd_len + 1);
306 memcpy(p, prefix, pre_len);
307 strcpy(p + pre_len, cmd);
308 return p;
309}
310
311static const char *cmd_to_page(const char *perf_cmd)
312{
313 if (!perf_cmd)
314 return "perf";
315 else if (!prefixcmp(perf_cmd, "perf"))
316 return perf_cmd;
317 else if (is_perf_command(perf_cmd))
318 return prepend("perf-", perf_cmd);
319 else
320 return prepend("perf-", perf_cmd);
321}
322
323static void setup_man_path(void)
324{
325 struct strbuf new_path = STRBUF_INIT;
326 const char *old_path = getenv("MANPATH");
327
328 /* We should always put ':' after our path. If there is no
329 * old_path, the ':' at the end will let 'man' to try
330 * system-wide paths after ours to find the manual page. If
331 * there is old_path, we need ':' as delimiter. */
332 strbuf_addstr(&new_path, system_path(PERF_MAN_PATH));
333 strbuf_addch(&new_path, ':');
334 if (old_path)
335 strbuf_addstr(&new_path, old_path);
336
337 setenv("MANPATH", new_path.buf, 1);
338
339 strbuf_release(&new_path);
340}
341
342static void exec_viewer(const char *name, const char *page)
343{
344 const char *info = get_man_viewer_info(name);
345
346 if (!strcasecmp(name, "man"))
347 exec_man_man(info, page);
348 else if (!strcasecmp(name, "woman"))
349 exec_woman_emacs(info, page);
350 else if (!strcasecmp(name, "konqueror"))
351 exec_man_konqueror(info, page);
352 else if (info)
353 exec_man_cmd(info, page);
354 else
355 warning("'%s': unknown man viewer.", name);
356}
357
358static void show_man_page(const char *perf_cmd)
359{
360 struct man_viewer_list *viewer;
361 const char *page = cmd_to_page(perf_cmd);
362 const char *fallback = getenv("PERF_MAN_VIEWER");
363
364 setup_man_path();
365 for (viewer = man_viewer_list; viewer; viewer = viewer->next)
366 {
367 exec_viewer(viewer->name, page); /* will return when unable */
368 }
369 if (fallback)
370 exec_viewer(fallback, page);
371 exec_viewer("man", page);
372 die("no man viewer handled the request");
373}
374
375static void show_info_page(const char *perf_cmd)
376{
377 const char *page = cmd_to_page(perf_cmd);
378 setenv("INFOPATH", system_path(PERF_INFO_PATH), 1);
379 execlp("info", "info", "perfman", page, NULL);
380}
381
382static void get_html_page_path(struct strbuf *page_path, const char *page)
383{
384 struct stat st;
385 const char *html_path = system_path(PERF_HTML_PATH);
386
387 /* Check that we have a perf documentation directory. */
388 if (stat(mkpath("%s/perf.html", html_path), &st)
389 || !S_ISREG(st.st_mode))
390 die("'%s': not a documentation directory.", html_path);
391
392 strbuf_init(page_path, 0);
393 strbuf_addf(page_path, "%s/%s.html", html_path, page);
394}
395
396/*
397 * If open_html is not defined in a platform-specific way (see for
398 * example compat/mingw.h), we use the script web--browse to display
399 * HTML.
400 */
401#ifndef open_html
402static void open_html(const char *path)
403{
404 execl_perf_cmd("web--browse", "-c", "help.browser", path, NULL);
405}
406#endif
407
408static void show_html_page(const char *perf_cmd)
409{
410 const char *page = cmd_to_page(perf_cmd);
411 struct strbuf page_path; /* it leaks but we exec bellow */
412
413 get_html_page_path(&page_path, page);
414
415 open_html(page_path.buf);
416}
417
418int cmd_help(int argc, const char **argv, const char *prefix)
419{
420 const char *alias;
421 load_command_list("perf-", &main_cmds, &other_cmds);
422
423 perf_config(perf_help_config, NULL);
424
425 argc = parse_options(argc, argv, builtin_help_options,
426 builtin_help_usage, 0);
427
428 if (show_all) {
429 printf("\n usage: %s\n\n", perf_usage_string);
430 list_commands("perf commands", &main_cmds, &other_cmds);
431 printf(" %s\n\n", perf_more_info_string);
432 return 0;
433 }
434
435 if (!argv[0]) {
436 printf("\n usage: %s\n\n", perf_usage_string);
437 list_common_cmds_help();
438 printf("\n %s\n\n", perf_more_info_string);
439 return 0;
440 }
441
442 alias = alias_lookup(argv[0]);
443 if (alias && !is_perf_command(argv[0])) {
444 printf("`perf %s' is aliased to `%s'\n", argv[0], alias);
445 return 0;
446 }
447
448 switch (help_format) {
449 case HELP_FORMAT_MAN:
450 show_man_page(argv[0]);
451 break;
452 case HELP_FORMAT_INFO:
453 show_info_page(argv[0]);
454 break;
455 case HELP_FORMAT_WEB:
456 show_html_page(argv[0]);
457 break;
458 }
459
460 return 0;
461}
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
new file mode 100644
index 000000000000..fe60e37c96ef
--- /dev/null
+++ b/tools/perf/builtin-list.c
@@ -0,0 +1,20 @@
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-options.h"
14#include "util/parse-events.h"
15
16int cmd_list(int argc, const char **argv, const char *prefix)
17{
18 print_events();
19 return 0;
20}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
new file mode 100644
index 000000000000..d7ebbd757543
--- /dev/null
+++ b/tools/perf/builtin-record.c
@@ -0,0 +1,628 @@
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 <unistd.h>
18#include <sched.h>
19
20#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
21#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
22
23static int fd[MAX_NR_CPUS][MAX_COUNTERS];
24
25static long default_interval = 100000;
26
27static int nr_cpus = 0;
28static unsigned int page_size;
29static unsigned int mmap_pages = 128;
30static int freq = 0;
31static int output;
32static const char *output_name = "perf.data";
33static int group = 0;
34static unsigned int realtime_prio = 0;
35static int system_wide = 0;
36static pid_t target_pid = -1;
37static int inherit = 1;
38static int force = 0;
39static int append_file = 0;
40static int call_graph = 0;
41static int verbose = 0;
42
43static long samples;
44static struct timeval last_read;
45static struct timeval this_read;
46
47static u64 bytes_written;
48
49static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
50
51static int nr_poll;
52static int nr_cpu;
53
54static int file_new = 1;
55static struct perf_file_header file_header;
56
57struct mmap_event {
58 struct perf_event_header header;
59 u32 pid;
60 u32 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;
70 u32 tid;
71 char comm[16];
72};
73
74
75struct mmap_data {
76 int counter;
77 void *base;
78 unsigned int mask;
79 unsigned int prev;
80};
81
82static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
83
84static unsigned long mmap_read_head(struct mmap_data *md)
85{
86 struct perf_counter_mmap_page *pc = md->base;
87 long head;
88
89 head = pc->data_head;
90 rmb();
91
92 return head;
93}
94
95static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
96{
97 struct perf_counter_mmap_page *pc = md->base;
98
99 /*
100 * ensure all reads are done before we write the tail out.
101 */
102 /* mb(); */
103 pc->data_tail = tail;
104}
105
106static void write_output(void *buf, size_t size)
107{
108 while (size) {
109 int ret = write(output, buf, size);
110
111 if (ret < 0)
112 die("failed to write");
113
114 size -= ret;
115 buf += ret;
116
117 bytes_written += ret;
118 }
119}
120
121static void mmap_read(struct mmap_data *md)
122{
123 unsigned int head = mmap_read_head(md);
124 unsigned int old = md->prev;
125 unsigned char *data = md->base + page_size;
126 unsigned long size;
127 void *buf;
128 int diff;
129
130 gettimeofday(&this_read, NULL);
131
132 /*
133 * If we're further behind than half the buffer, there's a chance
134 * the writer will bite our tail and mess up the samples under us.
135 *
136 * If we somehow ended up ahead of the head, we got messed up.
137 *
138 * In either case, truncate and restart at head.
139 */
140 diff = head - old;
141 if (diff < 0) {
142 struct timeval iv;
143 unsigned long msecs;
144
145 timersub(&this_read, &last_read, &iv);
146 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
147
148 fprintf(stderr, "WARNING: failed to keep up with mmap data."
149 " Last read %lu msecs ago.\n", msecs);
150
151 /*
152 * head points to a known good entry, start there.
153 */
154 old = head;
155 }
156
157 last_read = this_read;
158
159 if (old != head)
160 samples++;
161
162 size = head - old;
163
164 if ((old & md->mask) + size != (head & md->mask)) {
165 buf = &data[old & md->mask];
166 size = md->mask + 1 - (old & md->mask);
167 old += size;
168
169 write_output(buf, size);
170 }
171
172 buf = &data[old & md->mask];
173 size = head - old;
174 old += size;
175
176 write_output(buf, size);
177
178 md->prev = old;
179 mmap_write_tail(md, old);
180}
181
182static volatile int done = 0;
183static volatile int signr = -1;
184
185static void sig_handler(int sig)
186{
187 done = 1;
188 signr = sig;
189}
190
191static void sig_atexit(void)
192{
193 if (signr == -1)
194 return;
195
196 signal(signr, SIG_DFL);
197 kill(getpid(), signr);
198}
199
200static void pid_synthesize_comm_event(pid_t pid, int full)
201{
202 struct comm_event comm_ev;
203 char filename[PATH_MAX];
204 char bf[BUFSIZ];
205 int fd;
206 size_t size;
207 char *field, *sep;
208 DIR *tasks;
209 struct dirent dirent, *next;
210
211 snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
212
213 fd = open(filename, O_RDONLY);
214 if (fd < 0) {
215 /*
216 * We raced with a task exiting - just return:
217 */
218 if (verbose)
219 fprintf(stderr, "couldn't open %s\n", filename);
220 return;
221 }
222 if (read(fd, bf, sizeof(bf)) < 0) {
223 fprintf(stderr, "couldn't read %s\n", filename);
224 exit(EXIT_FAILURE);
225 }
226 close(fd);
227
228 /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */
229 memset(&comm_ev, 0, sizeof(comm_ev));
230 field = strchr(bf, '(');
231 if (field == NULL)
232 goto out_failure;
233 sep = strchr(++field, ')');
234 if (sep == NULL)
235 goto out_failure;
236 size = sep - field;
237 memcpy(comm_ev.comm, field, size++);
238
239 comm_ev.pid = pid;
240 comm_ev.header.type = PERF_EVENT_COMM;
241 size = ALIGN(size, sizeof(u64));
242 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
243
244 if (!full) {
245 comm_ev.tid = pid;
246
247 write_output(&comm_ev, comm_ev.header.size);
248 return;
249 }
250
251 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
252
253 tasks = opendir(filename);
254 while (!readdir_r(tasks, &dirent, &next) && next) {
255 char *end;
256 pid = strtol(dirent.d_name, &end, 10);
257 if (*end)
258 continue;
259
260 comm_ev.tid = pid;
261
262 write_output(&comm_ev, comm_ev.header.size);
263 }
264 closedir(tasks);
265 return;
266
267out_failure:
268 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
269 filename);
270 exit(EXIT_FAILURE);
271}
272
273static void pid_synthesize_mmap_samples(pid_t pid)
274{
275 char filename[PATH_MAX];
276 FILE *fp;
277
278 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
279
280 fp = fopen(filename, "r");
281 if (fp == NULL) {
282 /*
283 * We raced with a task exiting - just return:
284 */
285 if (verbose)
286 fprintf(stderr, "couldn't open %s\n", filename);
287 return;
288 }
289 while (1) {
290 char bf[BUFSIZ], *pbf = bf;
291 struct mmap_event mmap_ev = {
292 .header.type = PERF_EVENT_MMAP,
293 };
294 int n;
295 size_t size;
296 if (fgets(bf, sizeof(bf), fp) == NULL)
297 break;
298
299 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
300 n = hex2u64(pbf, &mmap_ev.start);
301 if (n < 0)
302 continue;
303 pbf += n + 1;
304 n = hex2u64(pbf, &mmap_ev.len);
305 if (n < 0)
306 continue;
307 pbf += n + 3;
308 if (*pbf == 'x') { /* vm_exec */
309 char *execname = strrchr(bf, ' ');
310
311 if (execname == NULL || execname[1] != '/')
312 continue;
313
314 execname += 1;
315 size = strlen(execname);
316 execname[size - 1] = '\0'; /* Remove \n */
317 memcpy(mmap_ev.filename, execname, size);
318 size = ALIGN(size, sizeof(u64));
319 mmap_ev.len -= mmap_ev.start;
320 mmap_ev.header.size = (sizeof(mmap_ev) -
321 (sizeof(mmap_ev.filename) - size));
322 mmap_ev.pid = pid;
323 mmap_ev.tid = pid;
324
325 write_output(&mmap_ev, mmap_ev.header.size);
326 }
327 }
328
329 fclose(fp);
330}
331
332static void synthesize_samples(void)
333{
334 DIR *proc;
335 struct dirent dirent, *next;
336
337 proc = opendir("/proc");
338
339 while (!readdir_r(proc, &dirent, &next) && next) {
340 char *end;
341 pid_t pid;
342
343 pid = strtol(dirent.d_name, &end, 10);
344 if (*end) /* only interested in proper numerical dirents */
345 continue;
346
347 pid_synthesize_comm_event(pid, 1);
348 pid_synthesize_mmap_samples(pid);
349 }
350
351 closedir(proc);
352}
353
354static int group_fd;
355
356static void create_counter(int counter, int cpu, pid_t pid)
357{
358 struct perf_counter_attr *attr = attrs + counter;
359 int track = 1;
360
361 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
362
363 if (freq) {
364 attr->sample_type |= PERF_SAMPLE_PERIOD;
365 attr->freq = 1;
366 attr->sample_freq = freq;
367 }
368
369 if (call_graph)
370 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
371
372 if (file_new) {
373 file_header.sample_type = attr->sample_type;
374 } else {
375 if (file_header.sample_type != attr->sample_type) {
376 fprintf(stderr, "incompatible append\n");
377 exit(-1);
378 }
379 }
380
381 attr->mmap = track;
382 attr->comm = track;
383 attr->inherit = (cpu < 0) && inherit;
384 attr->disabled = 1;
385
386 track = 0; /* only the first counter needs these */
387
388try_again:
389 fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
390
391 if (fd[nr_cpu][counter] < 0) {
392 int err = errno;
393
394 if (err == EPERM)
395 die("Permission error - are you root?\n");
396
397 /*
398 * If it's cycles then fall back to hrtimer
399 * based cpu-clock-tick sw counter, which
400 * is always available even if no PMU support:
401 */
402 if (attr->type == PERF_TYPE_HARDWARE
403 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
404
405 if (verbose)
406 warning(" ... trying to fall back to cpu-clock-ticks\n");
407 attr->type = PERF_TYPE_SOFTWARE;
408 attr->config = PERF_COUNT_SW_CPU_CLOCK;
409 goto try_again;
410 }
411 printf("\n");
412 error("perfcounter syscall returned with %d (%s)\n",
413 fd[nr_cpu][counter], strerror(err));
414 die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n");
415 exit(-1);
416 }
417
418 assert(fd[nr_cpu][counter] >= 0);
419 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
420
421 /*
422 * First counter acts as the group leader:
423 */
424 if (group && group_fd == -1)
425 group_fd = fd[nr_cpu][counter];
426
427 event_array[nr_poll].fd = fd[nr_cpu][counter];
428 event_array[nr_poll].events = POLLIN;
429 nr_poll++;
430
431 mmap_array[nr_cpu][counter].counter = counter;
432 mmap_array[nr_cpu][counter].prev = 0;
433 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1;
434 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
435 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0);
436 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) {
437 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
438 exit(-1);
439 }
440
441 ioctl(fd[nr_cpu][counter], PERF_COUNTER_IOC_ENABLE);
442}
443
444static void open_counters(int cpu, pid_t pid)
445{
446 int counter;
447
448 if (pid > 0) {
449 pid_synthesize_comm_event(pid, 0);
450 pid_synthesize_mmap_samples(pid);
451 }
452
453 group_fd = -1;
454 for (counter = 0; counter < nr_counters; counter++)
455 create_counter(counter, cpu, pid);
456
457 nr_cpu++;
458}
459
460static void atexit_header(void)
461{
462 file_header.data_size += bytes_written;
463
464 if (pwrite(output, &file_header, sizeof(file_header), 0) == -1)
465 perror("failed to write on file headers");
466}
467
468static int __cmd_record(int argc, const char **argv)
469{
470 int i, counter;
471 struct stat st;
472 pid_t pid;
473 int flags;
474 int ret;
475
476 page_size = sysconf(_SC_PAGE_SIZE);
477 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
478 assert(nr_cpus <= MAX_NR_CPUS);
479 assert(nr_cpus >= 0);
480
481 atexit(sig_atexit);
482 signal(SIGCHLD, sig_handler);
483 signal(SIGINT, sig_handler);
484
485 if (!stat(output_name, &st) && !force && !append_file) {
486 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
487 output_name);
488 exit(-1);
489 }
490
491 flags = O_CREAT|O_RDWR;
492 if (append_file)
493 file_new = 0;
494 else
495 flags |= O_TRUNC;
496
497 output = open(output_name, flags, S_IRUSR|S_IWUSR);
498 if (output < 0) {
499 perror("failed to create output file");
500 exit(-1);
501 }
502
503 if (!file_new) {
504 if (read(output, &file_header, sizeof(file_header)) == -1) {
505 perror("failed to read file headers");
506 exit(-1);
507 }
508
509 lseek(output, file_header.data_size, SEEK_CUR);
510 }
511
512 atexit(atexit_header);
513
514 if (!system_wide) {
515 open_counters(-1, target_pid != -1 ? target_pid : getpid());
516 } else for (i = 0; i < nr_cpus; i++)
517 open_counters(i, target_pid);
518
519 if (target_pid == -1 && argc) {
520 pid = fork();
521 if (pid < 0)
522 perror("failed to fork");
523
524 if (!pid) {
525 if (execvp(argv[0], (char **)argv)) {
526 perror(argv[0]);
527 exit(-1);
528 }
529 }
530 }
531
532 if (realtime_prio) {
533 struct sched_param param;
534
535 param.sched_priority = realtime_prio;
536 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
537 printf("Could not set realtime priority.\n");
538 exit(-1);
539 }
540 }
541
542 if (system_wide)
543 synthesize_samples();
544
545 while (!done) {
546 int hits = samples;
547
548 for (i = 0; i < nr_cpu; i++) {
549 for (counter = 0; counter < nr_counters; counter++)
550 mmap_read(&mmap_array[i][counter]);
551 }
552
553 if (hits == samples)
554 ret = poll(event_array, nr_poll, 100);
555 }
556
557 /*
558 * Approximate RIP event size: 24 bytes.
559 */
560 fprintf(stderr,
561 "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n",
562 (double)bytes_written / 1024.0 / 1024.0,
563 output_name,
564 bytes_written / 24);
565
566 return 0;
567}
568
569static const char * const record_usage[] = {
570 "perf record [<options>] [<command>]",
571 "perf record [<options>] -- <command> [<options>]",
572 NULL
573};
574
575static const struct option options[] = {
576 OPT_CALLBACK('e', "event", NULL, "event",
577 "event selector. use 'perf list' to list available events",
578 parse_events),
579 OPT_INTEGER('p', "pid", &target_pid,
580 "record events on existing pid"),
581 OPT_INTEGER('r', "realtime", &realtime_prio,
582 "collect data with this RT SCHED_FIFO priority"),
583 OPT_BOOLEAN('a', "all-cpus", &system_wide,
584 "system-wide collection from all CPUs"),
585 OPT_BOOLEAN('A', "append", &append_file,
586 "append to the output file to do incremental profiling"),
587 OPT_BOOLEAN('f', "force", &force,
588 "overwrite existing data file"),
589 OPT_LONG('c', "count", &default_interval,
590 "event period to sample"),
591 OPT_STRING('o', "output", &output_name, "file",
592 "output file name"),
593 OPT_BOOLEAN('i', "inherit", &inherit,
594 "child tasks inherit counters"),
595 OPT_INTEGER('F', "freq", &freq,
596 "profile at this frequency"),
597 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
598 "number of mmap data pages"),
599 OPT_BOOLEAN('g', "call-graph", &call_graph,
600 "do call-graph (stack chain/backtrace) recording"),
601 OPT_BOOLEAN('v', "verbose", &verbose,
602 "be more verbose (show counter open errors, etc)"),
603 OPT_END()
604};
605
606int cmd_record(int argc, const char **argv, const char *prefix)
607{
608 int counter;
609
610 argc = parse_options(argc, argv, options, record_usage, 0);
611 if (!argc && target_pid == -1 && !system_wide)
612 usage_with_options(record_usage, options);
613
614 if (!nr_counters) {
615 nr_counters = 1;
616 attrs[0].type = PERF_TYPE_HARDWARE;
617 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
618 }
619
620 for (counter = 0; counter < nr_counters; counter++) {
621 if (attrs[counter].sample_period)
622 continue;
623
624 attrs[counter].sample_period = default_interval;
625 }
626
627 return __cmd_record(argc, argv);
628}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
new file mode 100644
index 000000000000..5eb5566f0c95
--- /dev/null
+++ b/tools/perf/builtin-report.c
@@ -0,0 +1,1581 @@
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 "util/list.h"
14#include "util/cache.h"
15#include "util/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 = NULL;
30
31static char default_sort_order[] = "comm,dso";
32static char *sort_order = default_sort_order;
33
34static int input;
35static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
36
37static int dump_trace = 0;
38#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
39#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
40
41static int verbose;
42#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
43
44static int full_paths;
45
46static unsigned long page_size;
47static unsigned long mmap_window = 32;
48
49static char default_parent_pattern[] = "^sys_|^do_page_fault";
50static char *parent_pattern = default_parent_pattern;
51static regex_t parent_regex;
52
53static int exclude_other = 1;
54
55struct ip_event {
56 struct perf_event_header header;
57 u64 ip;
58 u32 pid, tid;
59 unsigned char __more_data[];
60};
61
62struct ip_callchain {
63 u64 nr;
64 u64 ips[0];
65};
66
67struct mmap_event {
68 struct perf_event_header header;
69 u32 pid, tid;
70 u64 start;
71 u64 len;
72 u64 pgoff;
73 char filename[PATH_MAX];
74};
75
76struct comm_event {
77 struct perf_event_header header;
78 u32 pid, tid;
79 char comm[16];
80};
81
82struct fork_event {
83 struct perf_event_header header;
84 u32 pid, ppid;
85};
86
87struct period_event {
88 struct perf_event_header header;
89 u64 time;
90 u64 id;
91 u64 sample_period;
92};
93
94struct lost_event {
95 struct perf_event_header header;
96 u64 id;
97 u64 lost;
98};
99
100typedef union event_union {
101 struct perf_event_header header;
102 struct ip_event ip;
103 struct mmap_event mmap;
104 struct comm_event comm;
105 struct fork_event fork;
106 struct period_event period;
107 struct lost_event lost;
108} event_t;
109
110static LIST_HEAD(dsos);
111static struct dso *kernel_dso;
112static struct dso *vdso;
113
114static void dsos__add(struct dso *dso)
115{
116 list_add_tail(&dso->node, &dsos);
117}
118
119static struct dso *dsos__find(const char *name)
120{
121 struct dso *pos;
122
123 list_for_each_entry(pos, &dsos, node)
124 if (strcmp(pos->name, name) == 0)
125 return pos;
126 return NULL;
127}
128
129static struct dso *dsos__findnew(const char *name)
130{
131 struct dso *dso = dsos__find(name);
132 int nr;
133
134 if (dso)
135 return dso;
136
137 dso = dso__new(name, 0);
138 if (!dso)
139 goto out_delete_dso;
140
141 nr = dso__load(dso, NULL, verbose);
142 if (nr < 0) {
143 eprintf("Failed to open: %s\n", name);
144 goto out_delete_dso;
145 }
146 if (!nr)
147 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
148
149 dsos__add(dso);
150
151 return dso;
152
153out_delete_dso:
154 dso__delete(dso);
155 return NULL;
156}
157
158static void dsos__fprintf(FILE *fp)
159{
160 struct dso *pos;
161
162 list_for_each_entry(pos, &dsos, node)
163 dso__fprintf(pos, fp);
164}
165
166static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
167{
168 return dso__find_symbol(kernel_dso, ip);
169}
170
171static int load_kernel(void)
172{
173 int err;
174
175 kernel_dso = dso__new("[kernel]", 0);
176 if (!kernel_dso)
177 return -1;
178
179 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
180 if (err) {
181 dso__delete(kernel_dso);
182 kernel_dso = NULL;
183 } else
184 dsos__add(kernel_dso);
185
186 vdso = dso__new("[vdso]", 0);
187 if (!vdso)
188 return -1;
189
190 vdso->find_symbol = vdso__find_symbol;
191
192 dsos__add(vdso);
193
194 return err;
195}
196
197static char __cwd[PATH_MAX];
198static char *cwd = __cwd;
199static int cwdlen;
200
201static int strcommon(const char *pathname)
202{
203 int n = 0;
204
205 while (pathname[n] == cwd[n] && n < cwdlen)
206 ++n;
207
208 return n;
209}
210
211struct map {
212 struct list_head node;
213 u64 start;
214 u64 end;
215 u64 pgoff;
216 u64 (*map_ip)(struct map *, u64);
217 struct dso *dso;
218};
219
220static u64 map__map_ip(struct map *map, u64 ip)
221{
222 return ip - map->start + map->pgoff;
223}
224
225static u64 vdso__map_ip(struct map *map, u64 ip)
226{
227 return ip;
228}
229
230static inline int is_anon_memory(const char *filename)
231{
232 return strcmp(filename, "//anon") == 0;
233}
234
235static struct map *map__new(struct mmap_event *event)
236{
237 struct map *self = malloc(sizeof(*self));
238
239 if (self != NULL) {
240 const char *filename = event->filename;
241 char newfilename[PATH_MAX];
242 int anon;
243
244 if (cwd) {
245 int n = strcommon(filename);
246
247 if (n == cwdlen) {
248 snprintf(newfilename, sizeof(newfilename),
249 ".%s", filename + n);
250 filename = newfilename;
251 }
252 }
253
254 anon = is_anon_memory(filename);
255
256 if (anon) {
257 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
258 filename = newfilename;
259 }
260
261 self->start = event->start;
262 self->end = event->start + event->len;
263 self->pgoff = event->pgoff;
264
265 self->dso = dsos__findnew(filename);
266 if (self->dso == NULL)
267 goto out_delete;
268
269 if (self->dso == vdso || anon)
270 self->map_ip = vdso__map_ip;
271 else
272 self->map_ip = map__map_ip;
273 }
274 return self;
275out_delete:
276 free(self);
277 return NULL;
278}
279
280static struct map *map__clone(struct map *self)
281{
282 struct map *map = malloc(sizeof(*self));
283
284 if (!map)
285 return NULL;
286
287 memcpy(map, self, sizeof(*self));
288
289 return map;
290}
291
292static int map__overlap(struct map *l, struct map *r)
293{
294 if (l->start > r->start) {
295 struct map *t = l;
296 l = r;
297 r = t;
298 }
299
300 if (l->end > r->start)
301 return 1;
302
303 return 0;
304}
305
306static size_t map__fprintf(struct map *self, FILE *fp)
307{
308 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
309 self->start, self->end, self->pgoff, self->dso->name);
310}
311
312
313struct thread {
314 struct rb_node rb_node;
315 struct list_head maps;
316 pid_t pid;
317 char *comm;
318};
319
320static struct thread *thread__new(pid_t pid)
321{
322 struct thread *self = malloc(sizeof(*self));
323
324 if (self != NULL) {
325 self->pid = pid;
326 self->comm = malloc(32);
327 if (self->comm)
328 snprintf(self->comm, 32, ":%d", self->pid);
329 INIT_LIST_HEAD(&self->maps);
330 }
331
332 return self;
333}
334
335static int thread__set_comm(struct thread *self, const char *comm)
336{
337 if (self->comm)
338 free(self->comm);
339 self->comm = strdup(comm);
340 return self->comm ? 0 : -ENOMEM;
341}
342
343static size_t thread__fprintf(struct thread *self, FILE *fp)
344{
345 struct map *pos;
346 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
347
348 list_for_each_entry(pos, &self->maps, node)
349 ret += map__fprintf(pos, fp);
350
351 return ret;
352}
353
354
355static struct rb_root threads;
356static struct thread *last_match;
357
358static struct thread *threads__findnew(pid_t pid)
359{
360 struct rb_node **p = &threads.rb_node;
361 struct rb_node *parent = NULL;
362 struct thread *th;
363
364 /*
365 * Font-end cache - PID lookups come in blocks,
366 * so most of the time we dont have to look up
367 * the full rbtree:
368 */
369 if (last_match && last_match->pid == pid)
370 return last_match;
371
372 while (*p != NULL) {
373 parent = *p;
374 th = rb_entry(parent, struct thread, rb_node);
375
376 if (th->pid == pid) {
377 last_match = th;
378 return th;
379 }
380
381 if (pid < th->pid)
382 p = &(*p)->rb_left;
383 else
384 p = &(*p)->rb_right;
385 }
386
387 th = thread__new(pid);
388 if (th != NULL) {
389 rb_link_node(&th->rb_node, parent, p);
390 rb_insert_color(&th->rb_node, &threads);
391 last_match = th;
392 }
393
394 return th;
395}
396
397static void thread__insert_map(struct thread *self, struct map *map)
398{
399 struct map *pos, *tmp;
400
401 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
402 if (map__overlap(pos, map)) {
403 list_del_init(&pos->node);
404 /* XXX leaks dsos */
405 free(pos);
406 }
407 }
408
409 list_add_tail(&map->node, &self->maps);
410}
411
412static int thread__fork(struct thread *self, struct thread *parent)
413{
414 struct map *map;
415
416 if (self->comm)
417 free(self->comm);
418 self->comm = strdup(parent->comm);
419 if (!self->comm)
420 return -ENOMEM;
421
422 list_for_each_entry(map, &parent->maps, node) {
423 struct map *new = map__clone(map);
424 if (!new)
425 return -ENOMEM;
426 thread__insert_map(self, new);
427 }
428
429 return 0;
430}
431
432static struct map *thread__find_map(struct thread *self, u64 ip)
433{
434 struct map *pos;
435
436 if (self == NULL)
437 return NULL;
438
439 list_for_each_entry(pos, &self->maps, node)
440 if (ip >= pos->start && ip <= pos->end)
441 return pos;
442
443 return NULL;
444}
445
446static size_t threads__fprintf(FILE *fp)
447{
448 size_t ret = 0;
449 struct rb_node *nd;
450
451 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
452 struct thread *pos = rb_entry(nd, struct thread, rb_node);
453
454 ret += thread__fprintf(pos, fp);
455 }
456
457 return ret;
458}
459
460/*
461 * histogram, sorted on item, collects counts
462 */
463
464static struct rb_root hist;
465
466struct hist_entry {
467 struct rb_node rb_node;
468
469 struct thread *thread;
470 struct map *map;
471 struct dso *dso;
472 struct symbol *sym;
473 struct symbol *parent;
474 u64 ip;
475 char level;
476
477 u64 count;
478};
479
480/*
481 * configurable sorting bits
482 */
483
484struct sort_entry {
485 struct list_head list;
486
487 char *header;
488
489 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
490 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
491 size_t (*print)(FILE *fp, struct hist_entry *);
492};
493
494static int64_t cmp_null(void *l, void *r)
495{
496 if (!l && !r)
497 return 0;
498 else if (!l)
499 return -1;
500 else
501 return 1;
502}
503
504/* --sort pid */
505
506static int64_t
507sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
508{
509 return right->thread->pid - left->thread->pid;
510}
511
512static size_t
513sort__thread_print(FILE *fp, struct hist_entry *self)
514{
515 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
516}
517
518static struct sort_entry sort_thread = {
519 .header = " Command: Pid",
520 .cmp = sort__thread_cmp,
521 .print = sort__thread_print,
522};
523
524/* --sort comm */
525
526static int64_t
527sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
528{
529 return right->thread->pid - left->thread->pid;
530}
531
532static int64_t
533sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
534{
535 char *comm_l = left->thread->comm;
536 char *comm_r = right->thread->comm;
537
538 if (!comm_l || !comm_r)
539 return cmp_null(comm_l, comm_r);
540
541 return strcmp(comm_l, comm_r);
542}
543
544static size_t
545sort__comm_print(FILE *fp, struct hist_entry *self)
546{
547 return fprintf(fp, "%16s", self->thread->comm);
548}
549
550static struct sort_entry sort_comm = {
551 .header = " Command",
552 .cmp = sort__comm_cmp,
553 .collapse = sort__comm_collapse,
554 .print = sort__comm_print,
555};
556
557/* --sort dso */
558
559static int64_t
560sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
561{
562 struct dso *dso_l = left->dso;
563 struct dso *dso_r = right->dso;
564
565 if (!dso_l || !dso_r)
566 return cmp_null(dso_l, dso_r);
567
568 return strcmp(dso_l->name, dso_r->name);
569}
570
571static size_t
572sort__dso_print(FILE *fp, struct hist_entry *self)
573{
574 if (self->dso)
575 return fprintf(fp, "%-25s", self->dso->name);
576
577 return fprintf(fp, "%016llx ", (u64)self->ip);
578}
579
580static struct sort_entry sort_dso = {
581 .header = "Shared Object ",
582 .cmp = sort__dso_cmp,
583 .print = sort__dso_print,
584};
585
586/* --sort symbol */
587
588static int64_t
589sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
590{
591 u64 ip_l, ip_r;
592
593 if (left->sym == right->sym)
594 return 0;
595
596 ip_l = left->sym ? left->sym->start : left->ip;
597 ip_r = right->sym ? right->sym->start : right->ip;
598
599 return (int64_t)(ip_r - ip_l);
600}
601
602static size_t
603sort__sym_print(FILE *fp, struct hist_entry *self)
604{
605 size_t ret = 0;
606
607 if (verbose)
608 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
609
610 if (self->sym) {
611 ret += fprintf(fp, "[%c] %s",
612 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
613 } else {
614 ret += fprintf(fp, "%#016llx", (u64)self->ip);
615 }
616
617 return ret;
618}
619
620static struct sort_entry sort_sym = {
621 .header = "Symbol",
622 .cmp = sort__sym_cmp,
623 .print = sort__sym_print,
624};
625
626/* --sort parent */
627
628static int64_t
629sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
630{
631 struct symbol *sym_l = left->parent;
632 struct symbol *sym_r = right->parent;
633
634 if (!sym_l || !sym_r)
635 return cmp_null(sym_l, sym_r);
636
637 return strcmp(sym_l->name, sym_r->name);
638}
639
640static size_t
641sort__parent_print(FILE *fp, struct hist_entry *self)
642{
643 size_t ret = 0;
644
645 ret += fprintf(fp, "%-20s", self->parent ? self->parent->name : "[other]");
646
647 return ret;
648}
649
650static struct sort_entry sort_parent = {
651 .header = "Parent symbol ",
652 .cmp = sort__parent_cmp,
653 .print = sort__parent_print,
654};
655
656static int sort__need_collapse = 0;
657static int sort__has_parent = 0;
658
659struct sort_dimension {
660 char *name;
661 struct sort_entry *entry;
662 int taken;
663};
664
665static struct sort_dimension sort_dimensions[] = {
666 { .name = "pid", .entry = &sort_thread, },
667 { .name = "comm", .entry = &sort_comm, },
668 { .name = "dso", .entry = &sort_dso, },
669 { .name = "symbol", .entry = &sort_sym, },
670 { .name = "parent", .entry = &sort_parent, },
671};
672
673static LIST_HEAD(hist_entry__sort_list);
674
675static int sort_dimension__add(char *tok)
676{
677 int i;
678
679 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
680 struct sort_dimension *sd = &sort_dimensions[i];
681
682 if (sd->taken)
683 continue;
684
685 if (strncasecmp(tok, sd->name, strlen(tok)))
686 continue;
687
688 if (sd->entry->collapse)
689 sort__need_collapse = 1;
690
691 if (sd->entry == &sort_parent) {
692 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
693 if (ret) {
694 char err[BUFSIZ];
695
696 regerror(ret, &parent_regex, err, sizeof(err));
697 fprintf(stderr, "Invalid regex: %s\n%s",
698 parent_pattern, err);
699 exit(-1);
700 }
701 sort__has_parent = 1;
702 }
703
704 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
705 sd->taken = 1;
706
707 return 0;
708 }
709
710 return -ESRCH;
711}
712
713static int64_t
714hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
715{
716 struct sort_entry *se;
717 int64_t cmp = 0;
718
719 list_for_each_entry(se, &hist_entry__sort_list, list) {
720 cmp = se->cmp(left, right);
721 if (cmp)
722 break;
723 }
724
725 return cmp;
726}
727
728static int64_t
729hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
730{
731 struct sort_entry *se;
732 int64_t cmp = 0;
733
734 list_for_each_entry(se, &hist_entry__sort_list, list) {
735 int64_t (*f)(struct hist_entry *, struct hist_entry *);
736
737 f = se->collapse ?: se->cmp;
738
739 cmp = f(left, right);
740 if (cmp)
741 break;
742 }
743
744 return cmp;
745}
746
747static size_t
748hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
749{
750 struct sort_entry *se;
751 size_t ret;
752
753 if (exclude_other && !self->parent)
754 return 0;
755
756 if (total_samples) {
757 double percent = self->count * 100.0 / total_samples;
758 char *color = PERF_COLOR_NORMAL;
759
760 /*
761 * We color high-overhead entries in red, mid-overhead
762 * entries in green - and keep the low overhead places
763 * normal:
764 */
765 if (percent >= 5.0) {
766 color = PERF_COLOR_RED;
767 } else {
768 if (percent >= 0.5)
769 color = PERF_COLOR_GREEN;
770 }
771
772 ret = color_fprintf(fp, color, " %6.2f%%",
773 (self->count * 100.0) / total_samples);
774 } else
775 ret = fprintf(fp, "%12Ld ", self->count);
776
777 list_for_each_entry(se, &hist_entry__sort_list, list) {
778 if (exclude_other && (se == &sort_parent))
779 continue;
780
781 fprintf(fp, " ");
782 ret += se->print(fp, self);
783 }
784
785 ret += fprintf(fp, "\n");
786
787 return ret;
788}
789
790/*
791 *
792 */
793
794static struct symbol *
795resolve_symbol(struct thread *thread, struct map **mapp,
796 struct dso **dsop, u64 *ipp)
797{
798 struct dso *dso = dsop ? *dsop : NULL;
799 struct map *map = mapp ? *mapp : NULL;
800 uint64_t ip = *ipp;
801
802 if (!thread)
803 return NULL;
804
805 if (dso)
806 goto got_dso;
807
808 if (map)
809 goto got_map;
810
811 map = thread__find_map(thread, ip);
812 if (map != NULL) {
813 if (mapp)
814 *mapp = map;
815got_map:
816 ip = map->map_ip(map, ip);
817 *ipp = ip;
818
819 dso = map->dso;
820 } else {
821 /*
822 * If this is outside of all known maps,
823 * and is a negative address, try to look it
824 * up in the kernel dso, as it might be a
825 * vsyscall (which executes in user-mode):
826 */
827 if ((long long)ip < 0)
828 dso = kernel_dso;
829 }
830 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
831
832 if (dsop)
833 *dsop = dso;
834
835 if (!dso)
836 return NULL;
837got_dso:
838 return dso->find_symbol(dso, ip);
839}
840
841static int call__match(struct symbol *sym)
842{
843 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
844 return 1;
845
846 return 0;
847}
848
849/*
850 * collect histogram counts
851 */
852
853static int
854hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
855 struct symbol *sym, u64 ip, struct ip_callchain *chain,
856 char level, u64 count)
857{
858 struct rb_node **p = &hist.rb_node;
859 struct rb_node *parent = NULL;
860 struct hist_entry *he;
861 struct hist_entry entry = {
862 .thread = thread,
863 .map = map,
864 .dso = dso,
865 .sym = sym,
866 .ip = ip,
867 .level = level,
868 .count = count,
869 .parent = NULL,
870 };
871 int cmp;
872
873 if (sort__has_parent && chain) {
874 u64 context = PERF_CONTEXT_MAX;
875 int i;
876
877 for (i = 0; i < chain->nr; i++) {
878 u64 ip = chain->ips[i];
879 struct dso *dso = NULL;
880 struct symbol *sym;
881
882 if (ip >= PERF_CONTEXT_MAX) {
883 context = ip;
884 continue;
885 }
886
887 switch (context) {
888 case PERF_CONTEXT_KERNEL:
889 dso = kernel_dso;
890 break;
891 default:
892 break;
893 }
894
895 sym = resolve_symbol(thread, NULL, &dso, &ip);
896
897 if (sym && call__match(sym)) {
898 entry.parent = sym;
899 break;
900 }
901 }
902 }
903
904 while (*p != NULL) {
905 parent = *p;
906 he = rb_entry(parent, struct hist_entry, rb_node);
907
908 cmp = hist_entry__cmp(&entry, he);
909
910 if (!cmp) {
911 he->count += count;
912 return 0;
913 }
914
915 if (cmp < 0)
916 p = &(*p)->rb_left;
917 else
918 p = &(*p)->rb_right;
919 }
920
921 he = malloc(sizeof(*he));
922 if (!he)
923 return -ENOMEM;
924 *he = entry;
925 rb_link_node(&he->rb_node, parent, p);
926 rb_insert_color(&he->rb_node, &hist);
927
928 return 0;
929}
930
931static void hist_entry__free(struct hist_entry *he)
932{
933 free(he);
934}
935
936/*
937 * collapse the histogram
938 */
939
940static struct rb_root collapse_hists;
941
942static void collapse__insert_entry(struct hist_entry *he)
943{
944 struct rb_node **p = &collapse_hists.rb_node;
945 struct rb_node *parent = NULL;
946 struct hist_entry *iter;
947 int64_t cmp;
948
949 while (*p != NULL) {
950 parent = *p;
951 iter = rb_entry(parent, struct hist_entry, rb_node);
952
953 cmp = hist_entry__collapse(iter, he);
954
955 if (!cmp) {
956 iter->count += he->count;
957 hist_entry__free(he);
958 return;
959 }
960
961 if (cmp < 0)
962 p = &(*p)->rb_left;
963 else
964 p = &(*p)->rb_right;
965 }
966
967 rb_link_node(&he->rb_node, parent, p);
968 rb_insert_color(&he->rb_node, &collapse_hists);
969}
970
971static void collapse__resort(void)
972{
973 struct rb_node *next;
974 struct hist_entry *n;
975
976 if (!sort__need_collapse)
977 return;
978
979 next = rb_first(&hist);
980 while (next) {
981 n = rb_entry(next, struct hist_entry, rb_node);
982 next = rb_next(&n->rb_node);
983
984 rb_erase(&n->rb_node, &hist);
985 collapse__insert_entry(n);
986 }
987}
988
989/*
990 * reverse the map, sort on count.
991 */
992
993static struct rb_root output_hists;
994
995static void output__insert_entry(struct hist_entry *he)
996{
997 struct rb_node **p = &output_hists.rb_node;
998 struct rb_node *parent = NULL;
999 struct hist_entry *iter;
1000
1001 while (*p != NULL) {
1002 parent = *p;
1003 iter = rb_entry(parent, struct hist_entry, rb_node);
1004
1005 if (he->count > iter->count)
1006 p = &(*p)->rb_left;
1007 else
1008 p = &(*p)->rb_right;
1009 }
1010
1011 rb_link_node(&he->rb_node, parent, p);
1012 rb_insert_color(&he->rb_node, &output_hists);
1013}
1014
1015static void output__resort(void)
1016{
1017 struct rb_node *next;
1018 struct hist_entry *n;
1019 struct rb_root *tree = &hist;
1020
1021 if (sort__need_collapse)
1022 tree = &collapse_hists;
1023
1024 next = rb_first(tree);
1025
1026 while (next) {
1027 n = rb_entry(next, struct hist_entry, rb_node);
1028 next = rb_next(&n->rb_node);
1029
1030 rb_erase(&n->rb_node, tree);
1031 output__insert_entry(n);
1032 }
1033}
1034
1035static size_t output__fprintf(FILE *fp, u64 total_samples)
1036{
1037 struct hist_entry *pos;
1038 struct sort_entry *se;
1039 struct rb_node *nd;
1040 size_t ret = 0;
1041
1042 fprintf(fp, "\n");
1043 fprintf(fp, "#\n");
1044 fprintf(fp, "# (%Ld samples)\n", (u64)total_samples);
1045 fprintf(fp, "#\n");
1046
1047 fprintf(fp, "# Overhead");
1048 list_for_each_entry(se, &hist_entry__sort_list, list) {
1049 if (exclude_other && (se == &sort_parent))
1050 continue;
1051 fprintf(fp, " %s", se->header);
1052 }
1053 fprintf(fp, "\n");
1054
1055 fprintf(fp, "# ........");
1056 list_for_each_entry(se, &hist_entry__sort_list, list) {
1057 int i;
1058
1059 if (exclude_other && (se == &sort_parent))
1060 continue;
1061
1062 fprintf(fp, " ");
1063 for (i = 0; i < strlen(se->header); i++)
1064 fprintf(fp, ".");
1065 }
1066 fprintf(fp, "\n");
1067
1068 fprintf(fp, "#\n");
1069
1070 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1071 pos = rb_entry(nd, struct hist_entry, rb_node);
1072 ret += hist_entry__fprintf(fp, pos, total_samples);
1073 }
1074
1075 if (sort_order == default_sort_order &&
1076 parent_pattern == default_parent_pattern) {
1077 fprintf(fp, "#\n");
1078 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n");
1079 fprintf(fp, "#\n");
1080 }
1081 fprintf(fp, "\n");
1082
1083 return ret;
1084}
1085
1086static void register_idle_thread(void)
1087{
1088 struct thread *thread = threads__findnew(0);
1089
1090 if (thread == NULL ||
1091 thread__set_comm(thread, "[idle]")) {
1092 fprintf(stderr, "problem inserting idle task.\n");
1093 exit(-1);
1094 }
1095}
1096
1097static unsigned long total = 0,
1098 total_mmap = 0,
1099 total_comm = 0,
1100 total_fork = 0,
1101 total_unknown = 0,
1102 total_lost = 0;
1103
1104static int validate_chain(struct ip_callchain *chain, event_t *event)
1105{
1106 unsigned int chain_size;
1107
1108 chain_size = event->header.size;
1109 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
1110
1111 if (chain->nr*sizeof(u64) > chain_size)
1112 return -1;
1113
1114 return 0;
1115}
1116
1117static int
1118process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
1119{
1120 char level;
1121 int show = 0;
1122 struct dso *dso = NULL;
1123 struct thread *thread = threads__findnew(event->ip.pid);
1124 u64 ip = event->ip.ip;
1125 u64 period = 1;
1126 struct map *map = NULL;
1127 void *more_data = event->ip.__more_data;
1128 struct ip_callchain *chain = NULL;
1129
1130 if (event->header.type & PERF_SAMPLE_PERIOD) {
1131 period = *(u64 *)more_data;
1132 more_data += sizeof(u64);
1133 }
1134
1135 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n",
1136 (void *)(offset + head),
1137 (void *)(long)(event->header.size),
1138 event->header.misc,
1139 event->ip.pid,
1140 (void *)(long)ip,
1141 (long long)period);
1142
1143 if (event->header.type & PERF_SAMPLE_CALLCHAIN) {
1144 int i;
1145
1146 chain = (void *)more_data;
1147
1148 dprintf("... chain: nr:%Lu\n", chain->nr);
1149
1150 if (validate_chain(chain, event) < 0) {
1151 eprintf("call-chain problem with event, skipping it.\n");
1152 return 0;
1153 }
1154
1155 if (dump_trace) {
1156 for (i = 0; i < chain->nr; i++)
1157 dprintf("..... %2d: %016Lx\n", i, chain->ips[i]);
1158 }
1159 }
1160
1161 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1162
1163 if (thread == NULL) {
1164 eprintf("problem processing %d event, skipping it.\n",
1165 event->header.type);
1166 return -1;
1167 }
1168
1169 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
1170 show = SHOW_KERNEL;
1171 level = 'k';
1172
1173 dso = kernel_dso;
1174
1175 dprintf(" ...... dso: %s\n", dso->name);
1176
1177 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
1178
1179 show = SHOW_USER;
1180 level = '.';
1181
1182 } else {
1183 show = SHOW_HV;
1184 level = 'H';
1185 dprintf(" ...... dso: [hypervisor]\n");
1186 }
1187
1188 if (show & show_mask) {
1189 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1190
1191 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1192 eprintf("problem incrementing symbol count, skipping event\n");
1193 return -1;
1194 }
1195 }
1196 total += period;
1197
1198 return 0;
1199}
1200
1201static int
1202process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1203{
1204 struct thread *thread = threads__findnew(event->mmap.pid);
1205 struct map *map = map__new(&event->mmap);
1206
1207 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
1208 (void *)(offset + head),
1209 (void *)(long)(event->header.size),
1210 event->mmap.pid,
1211 (void *)(long)event->mmap.start,
1212 (void *)(long)event->mmap.len,
1213 (void *)(long)event->mmap.pgoff,
1214 event->mmap.filename);
1215
1216 if (thread == NULL || map == NULL) {
1217 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
1218 return 0;
1219 }
1220
1221 thread__insert_map(thread, map);
1222 total_mmap++;
1223
1224 return 0;
1225}
1226
1227static int
1228process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1229{
1230 struct thread *thread = threads__findnew(event->comm.pid);
1231
1232 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
1233 (void *)(offset + head),
1234 (void *)(long)(event->header.size),
1235 event->comm.comm, event->comm.pid);
1236
1237 if (thread == NULL ||
1238 thread__set_comm(thread, event->comm.comm)) {
1239 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
1240 return -1;
1241 }
1242 total_comm++;
1243
1244 return 0;
1245}
1246
1247static int
1248process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1249{
1250 struct thread *thread = threads__findnew(event->fork.pid);
1251 struct thread *parent = threads__findnew(event->fork.ppid);
1252
1253 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n",
1254 (void *)(offset + head),
1255 (void *)(long)(event->header.size),
1256 event->fork.pid, event->fork.ppid);
1257
1258 if (!thread || !parent || thread__fork(thread, parent)) {
1259 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
1260 return -1;
1261 }
1262 total_fork++;
1263
1264 return 0;
1265}
1266
1267static int
1268process_period_event(event_t *event, unsigned long offset, unsigned long head)
1269{
1270 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
1271 (void *)(offset + head),
1272 (void *)(long)(event->header.size),
1273 event->period.time,
1274 event->period.id,
1275 event->period.sample_period);
1276
1277 return 0;
1278}
1279
1280static int
1281process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1282{
1283 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
1284 (void *)(offset + head),
1285 (void *)(long)(event->header.size),
1286 event->lost.id,
1287 event->lost.lost);
1288
1289 total_lost += event->lost.lost;
1290
1291 return 0;
1292}
1293
1294static void trace_event(event_t *event)
1295{
1296 unsigned char *raw_event = (void *)event;
1297 char *color = PERF_COLOR_BLUE;
1298 int i, j;
1299
1300 if (!dump_trace)
1301 return;
1302
1303 dprintf(".");
1304 cdprintf("\n. ... raw event: size %d bytes\n", event->header.size);
1305
1306 for (i = 0; i < event->header.size; i++) {
1307 if ((i & 15) == 0) {
1308 dprintf(".");
1309 cdprintf(" %04x: ", i);
1310 }
1311
1312 cdprintf(" %02x", raw_event[i]);
1313
1314 if (((i & 15) == 15) || i == event->header.size-1) {
1315 cdprintf(" ");
1316 for (j = 0; j < 15-(i & 15); j++)
1317 cdprintf(" ");
1318 for (j = 0; j < (i & 15); j++) {
1319 if (isprint(raw_event[i-15+j]))
1320 cdprintf("%c", raw_event[i-15+j]);
1321 else
1322 cdprintf(".");
1323 }
1324 cdprintf("\n");
1325 }
1326 }
1327 dprintf(".\n");
1328}
1329
1330static int
1331process_event(event_t *event, unsigned long offset, unsigned long head)
1332{
1333 trace_event(event);
1334
1335 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1336 return process_overflow_event(event, offset, head);
1337
1338 switch (event->header.type) {
1339 case PERF_EVENT_MMAP:
1340 return process_mmap_event(event, offset, head);
1341
1342 case PERF_EVENT_COMM:
1343 return process_comm_event(event, offset, head);
1344
1345 case PERF_EVENT_FORK:
1346 return process_fork_event(event, offset, head);
1347
1348 case PERF_EVENT_PERIOD:
1349 return process_period_event(event, offset, head);
1350
1351 case PERF_EVENT_LOST:
1352 return process_lost_event(event, offset, head);
1353
1354 /*
1355 * We dont process them right now but they are fine:
1356 */
1357
1358 case PERF_EVENT_THROTTLE:
1359 case PERF_EVENT_UNTHROTTLE:
1360 return 0;
1361
1362 default:
1363 return -1;
1364 }
1365
1366 return 0;
1367}
1368
1369static struct perf_file_header file_header;
1370
1371static int __cmd_report(void)
1372{
1373 int ret, rc = EXIT_FAILURE;
1374 unsigned long offset = 0;
1375 unsigned long head = sizeof(file_header);
1376 struct stat stat;
1377 event_t *event;
1378 uint32_t size;
1379 char *buf;
1380
1381 register_idle_thread();
1382
1383 input = open(input_name, O_RDONLY);
1384 if (input < 0) {
1385 fprintf(stderr, " failed to open file: %s", input_name);
1386 if (!strcmp(input_name, "perf.data"))
1387 fprintf(stderr, " (try 'perf record' first)");
1388 fprintf(stderr, "\n");
1389 exit(-1);
1390 }
1391
1392 ret = fstat(input, &stat);
1393 if (ret < 0) {
1394 perror("failed to stat file");
1395 exit(-1);
1396 }
1397
1398 if (!stat.st_size) {
1399 fprintf(stderr, "zero-sized file, nothing to do!\n");
1400 exit(0);
1401 }
1402
1403 if (read(input, &file_header, sizeof(file_header)) == -1) {
1404 perror("failed to read file headers");
1405 exit(-1);
1406 }
1407
1408 if (sort__has_parent &&
1409 !(file_header.sample_type & PERF_SAMPLE_CALLCHAIN)) {
1410 fprintf(stderr, "selected --sort parent, but no callchain data\n");
1411 exit(-1);
1412 }
1413
1414 if (load_kernel() < 0) {
1415 perror("failed to load kernel symbols");
1416 return EXIT_FAILURE;
1417 }
1418
1419 if (!full_paths) {
1420 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1421 perror("failed to get the current directory");
1422 return EXIT_FAILURE;
1423 }
1424 cwdlen = strlen(cwd);
1425 } else {
1426 cwd = NULL;
1427 cwdlen = 0;
1428 }
1429remap:
1430 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1431 MAP_SHARED, input, offset);
1432 if (buf == MAP_FAILED) {
1433 perror("failed to mmap file");
1434 exit(-1);
1435 }
1436
1437more:
1438 event = (event_t *)(buf + head);
1439
1440 size = event->header.size;
1441 if (!size)
1442 size = 8;
1443
1444 if (head + event->header.size >= page_size * mmap_window) {
1445 unsigned long shift = page_size * (head / page_size);
1446 int ret;
1447
1448 ret = munmap(buf, page_size * mmap_window);
1449 assert(ret == 0);
1450
1451 offset += shift;
1452 head -= shift;
1453 goto remap;
1454 }
1455
1456 size = event->header.size;
1457
1458 dprintf("\n%p [%p]: event: %d\n",
1459 (void *)(offset + head),
1460 (void *)(long)event->header.size,
1461 event->header.type);
1462
1463 if (!size || process_event(event, offset, head) < 0) {
1464
1465 dprintf("%p [%p]: skipping unknown header type: %d\n",
1466 (void *)(offset + head),
1467 (void *)(long)(event->header.size),
1468 event->header.type);
1469
1470 total_unknown++;
1471
1472 /*
1473 * assume we lost track of the stream, check alignment, and
1474 * increment a single u64 in the hope to catch on again 'soon'.
1475 */
1476
1477 if (unlikely(head & 7))
1478 head &= ~7ULL;
1479
1480 size = 8;
1481 }
1482
1483 head += size;
1484
1485 if (offset + head >= sizeof(file_header) + file_header.data_size)
1486 goto done;
1487
1488 if (offset + head < stat.st_size)
1489 goto more;
1490
1491done:
1492 rc = EXIT_SUCCESS;
1493 close(input);
1494
1495 dprintf(" IP events: %10ld\n", total);
1496 dprintf(" mmap events: %10ld\n", total_mmap);
1497 dprintf(" comm events: %10ld\n", total_comm);
1498 dprintf(" fork events: %10ld\n", total_fork);
1499 dprintf(" lost events: %10ld\n", total_lost);
1500 dprintf(" unknown events: %10ld\n", total_unknown);
1501
1502 if (dump_trace)
1503 return 0;
1504
1505 if (verbose >= 3)
1506 threads__fprintf(stdout);
1507
1508 if (verbose >= 2)
1509 dsos__fprintf(stdout);
1510
1511 collapse__resort();
1512 output__resort();
1513 output__fprintf(stdout, total);
1514
1515 return rc;
1516}
1517
1518static const char * const report_usage[] = {
1519 "perf report [<options>] <command>",
1520 NULL
1521};
1522
1523static const struct option options[] = {
1524 OPT_STRING('i', "input", &input_name, "file",
1525 "input file name"),
1526 OPT_BOOLEAN('v', "verbose", &verbose,
1527 "be more verbose (show symbol address, etc)"),
1528 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1529 "dump raw trace in ASCII"),
1530 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1531 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1532 "sort by key(s): pid, comm, dso, symbol, parent"),
1533 OPT_BOOLEAN('P', "full-paths", &full_paths,
1534 "Don't shorten the pathnames taking into account the cwd"),
1535 OPT_STRING('p', "parent", &parent_pattern, "regex",
1536 "regex filter to identify parent, see: '--sort parent'"),
1537 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1538 "Only display entries with parent-match"),
1539 OPT_END()
1540};
1541
1542static void setup_sorting(void)
1543{
1544 char *tmp, *tok, *str = strdup(sort_order);
1545
1546 for (tok = strtok_r(str, ", ", &tmp);
1547 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1548 if (sort_dimension__add(tok) < 0) {
1549 error("Unknown --sort key: `%s'", tok);
1550 usage_with_options(report_usage, options);
1551 }
1552 }
1553
1554 free(str);
1555}
1556
1557int cmd_report(int argc, const char **argv, const char *prefix)
1558{
1559 symbol__init();
1560
1561 page_size = getpagesize();
1562
1563 argc = parse_options(argc, argv, options, report_usage, 0);
1564
1565 setup_sorting();
1566
1567 if (parent_pattern != default_parent_pattern)
1568 sort_dimension__add("parent");
1569 else
1570 exclude_other = 0;
1571
1572 /*
1573 * Any (unrecognized) arguments left?
1574 */
1575 if (argc)
1576 usage_with_options(report_usage, options);
1577
1578 setup_pager();
1579
1580 return __cmd_report();
1581}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
new file mode 100644
index 000000000000..6d3eeac1ea25
--- /dev/null
+++ b/tools/perf/builtin-stat.c
@@ -0,0 +1,521 @@
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 *
36 * Released under the GPL v2. (and only v2, not any later version)
37 */
38
39#include "perf.h"
40#include "builtin.h"
41#include "util/util.h"
42#include "util/parse-options.h"
43#include "util/parse-events.h"
44
45#include <sys/prctl.h>
46#include <math.h>
47
48static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
49
50 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
51 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
52 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
53 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
54
55 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
56 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
57 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES},
58 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
59
60};
61
62static int system_wide = 0;
63static int inherit = 1;
64static int verbose = 0;
65
66static int fd[MAX_NR_CPUS][MAX_COUNTERS];
67
68static int target_pid = -1;
69static int nr_cpus = 0;
70static unsigned int page_size;
71
72static int scale = 1;
73
74static const unsigned int default_count[] = {
75 1000000,
76 1000000,
77 10000,
78 10000,
79 1000000,
80 10000,
81};
82
83#define MAX_RUN 100
84
85static int run_count = 1;
86static int run_idx = 0;
87
88static u64 event_res[MAX_RUN][MAX_COUNTERS][3];
89static u64 event_scaled[MAX_RUN][MAX_COUNTERS];
90
91//static u64 event_hist[MAX_RUN][MAX_COUNTERS][3];
92
93
94static u64 runtime_nsecs[MAX_RUN];
95static u64 walltime_nsecs[MAX_RUN];
96static u64 runtime_cycles[MAX_RUN];
97
98static u64 event_res_avg[MAX_COUNTERS][3];
99static u64 event_res_noise[MAX_COUNTERS][3];
100
101static u64 event_scaled_avg[MAX_COUNTERS];
102
103static u64 runtime_nsecs_avg;
104static u64 runtime_nsecs_noise;
105
106static u64 walltime_nsecs_avg;
107static u64 walltime_nsecs_noise;
108
109static u64 runtime_cycles_avg;
110static u64 runtime_cycles_noise;
111
112static void create_perf_stat_counter(int counter)
113{
114 struct perf_counter_attr *attr = attrs + counter;
115
116 if (scale)
117 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
118 PERF_FORMAT_TOTAL_TIME_RUNNING;
119
120 if (system_wide) {
121 int cpu;
122 for (cpu = 0; cpu < nr_cpus; cpu ++) {
123 fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
124 if (fd[cpu][counter] < 0 && verbose) {
125 printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[cpu][counter], strerror(errno));
126 }
127 }
128 } else {
129 attr->inherit = inherit;
130 attr->disabled = 1;
131
132 fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0);
133 if (fd[0][counter] < 0 && verbose) {
134 printf("Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n", counter, fd[0][counter], strerror(errno));
135 }
136 }
137}
138
139/*
140 * Does the counter have nsecs as a unit?
141 */
142static inline int nsec_counter(int counter)
143{
144 if (attrs[counter].type != PERF_TYPE_SOFTWARE)
145 return 0;
146
147 if (attrs[counter].config == PERF_COUNT_SW_CPU_CLOCK)
148 return 1;
149
150 if (attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
151 return 1;
152
153 return 0;
154}
155
156/*
157 * Read out the results of a single counter:
158 */
159static void read_counter(int counter)
160{
161 u64 *count, single_count[3];
162 ssize_t res;
163 int cpu, nv;
164 int scaled;
165
166 count = event_res[run_idx][counter];
167
168 count[0] = count[1] = count[2] = 0;
169
170 nv = scale ? 3 : 1;
171 for (cpu = 0; cpu < nr_cpus; cpu ++) {
172 if (fd[cpu][counter] < 0)
173 continue;
174
175 res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
176 assert(res == nv * sizeof(u64));
177 close(fd[cpu][counter]);
178 fd[cpu][counter] = -1;
179
180 count[0] += single_count[0];
181 if (scale) {
182 count[1] += single_count[1];
183 count[2] += single_count[2];
184 }
185 }
186
187 scaled = 0;
188 if (scale) {
189 if (count[2] == 0) {
190 event_scaled[run_idx][counter] = -1;
191 count[0] = 0;
192 return;
193 }
194
195 if (count[2] < count[1]) {
196 event_scaled[run_idx][counter] = 1;
197 count[0] = (unsigned long long)
198 ((double)count[0] * count[1] / count[2] + 0.5);
199 }
200 }
201 /*
202 * Save the full runtime - to allow normalization during printout:
203 */
204 if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
205 attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK)
206 runtime_nsecs[run_idx] = count[0];
207 if (attrs[counter].type == PERF_TYPE_HARDWARE &&
208 attrs[counter].config == PERF_COUNT_HW_CPU_CYCLES)
209 runtime_cycles[run_idx] = count[0];
210}
211
212static int run_perf_stat(int argc, const char **argv)
213{
214 unsigned long long t0, t1;
215 int status = 0;
216 int counter;
217 int pid;
218
219 if (!system_wide)
220 nr_cpus = 1;
221
222 for (counter = 0; counter < nr_counters; counter++)
223 create_perf_stat_counter(counter);
224
225 /*
226 * Enable counters and exec the command:
227 */
228 t0 = rdclock();
229 prctl(PR_TASK_PERF_COUNTERS_ENABLE);
230
231 if ((pid = fork()) < 0)
232 perror("failed to fork");
233
234 if (!pid) {
235 if (execvp(argv[0], (char **)argv)) {
236 perror(argv[0]);
237 exit(-1);
238 }
239 }
240
241 wait(&status);
242
243 prctl(PR_TASK_PERF_COUNTERS_DISABLE);
244 t1 = rdclock();
245
246 walltime_nsecs[run_idx] = t1 - t0;
247
248 for (counter = 0; counter < nr_counters; counter++)
249 read_counter(counter);
250
251 return WEXITSTATUS(status);
252}
253
254static void print_noise(u64 *count, u64 *noise)
255{
256 if (run_count > 1)
257 fprintf(stderr, " ( +- %7.3f%% )",
258 (double)noise[0]/(count[0]+1)*100.0);
259}
260
261static void nsec_printout(int counter, u64 *count, u64 *noise)
262{
263 double msecs = (double)count[0] / 1000000;
264
265 fprintf(stderr, " %14.6f %-20s", msecs, event_name(counter));
266
267 if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
268 attrs[counter].config == PERF_COUNT_SW_TASK_CLOCK) {
269
270 if (walltime_nsecs_avg)
271 fprintf(stderr, " # %10.3f CPUs ",
272 (double)count[0] / (double)walltime_nsecs_avg);
273 }
274 print_noise(count, noise);
275}
276
277static void abs_printout(int counter, u64 *count, u64 *noise)
278{
279 fprintf(stderr, " %14Ld %-20s", count[0], event_name(counter));
280
281 if (runtime_cycles_avg &&
282 attrs[counter].type == PERF_TYPE_HARDWARE &&
283 attrs[counter].config == PERF_COUNT_HW_INSTRUCTIONS) {
284
285 fprintf(stderr, " # %10.3f IPC ",
286 (double)count[0] / (double)runtime_cycles_avg);
287 } else {
288 if (runtime_nsecs_avg) {
289 fprintf(stderr, " # %10.3f M/sec",
290 (double)count[0]/runtime_nsecs_avg*1000.0);
291 }
292 }
293 print_noise(count, noise);
294}
295
296/*
297 * Print out the results of a single counter:
298 */
299static void print_counter(int counter)
300{
301 u64 *count, *noise;
302 int scaled;
303
304 count = event_res_avg[counter];
305 noise = event_res_noise[counter];
306 scaled = event_scaled_avg[counter];
307
308 if (scaled == -1) {
309 fprintf(stderr, " %14s %-20s\n",
310 "<not counted>", event_name(counter));
311 return;
312 }
313
314 if (nsec_counter(counter))
315 nsec_printout(counter, count, noise);
316 else
317 abs_printout(counter, count, noise);
318
319 if (scaled)
320 fprintf(stderr, " (scaled from %.2f%%)",
321 (double) count[2] / count[1] * 100);
322
323 fprintf(stderr, "\n");
324}
325
326/*
327 * normalize_noise noise values down to stddev:
328 */
329static void normalize_noise(u64 *val)
330{
331 double res;
332
333 res = (double)*val / (run_count * sqrt((double)run_count));
334
335 *val = (u64)res;
336}
337
338static void update_avg(const char *name, int idx, u64 *avg, u64 *val)
339{
340 *avg += *val;
341
342 if (verbose > 1)
343 fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val);
344}
345/*
346 * Calculate the averages and noises:
347 */
348static void calc_avg(void)
349{
350 int i, j;
351
352 if (verbose > 1)
353 fprintf(stderr, "\n");
354
355 for (i = 0; i < run_count; i++) {
356 update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i);
357 update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i);
358 update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i);
359
360 for (j = 0; j < nr_counters; j++) {
361 update_avg("counter/0", j,
362 event_res_avg[j]+0, event_res[i][j]+0);
363 update_avg("counter/1", j,
364 event_res_avg[j]+1, event_res[i][j]+1);
365 update_avg("counter/2", j,
366 event_res_avg[j]+2, event_res[i][j]+2);
367 update_avg("scaled", j,
368 event_scaled_avg + j, event_scaled[i]+j);
369 }
370 }
371 runtime_nsecs_avg /= run_count;
372 walltime_nsecs_avg /= run_count;
373 runtime_cycles_avg /= run_count;
374
375 for (j = 0; j < nr_counters; j++) {
376 event_res_avg[j][0] /= run_count;
377 event_res_avg[j][1] /= run_count;
378 event_res_avg[j][2] /= run_count;
379 }
380
381 for (i = 0; i < run_count; i++) {
382 runtime_nsecs_noise +=
383 abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg));
384 walltime_nsecs_noise +=
385 abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg));
386 runtime_cycles_noise +=
387 abs((s64)(runtime_cycles[i] - runtime_cycles_avg));
388
389 for (j = 0; j < nr_counters; j++) {
390 event_res_noise[j][0] +=
391 abs((s64)(event_res[i][j][0] - event_res_avg[j][0]));
392 event_res_noise[j][1] +=
393 abs((s64)(event_res[i][j][1] - event_res_avg[j][1]));
394 event_res_noise[j][2] +=
395 abs((s64)(event_res[i][j][2] - event_res_avg[j][2]));
396 }
397 }
398
399 normalize_noise(&runtime_nsecs_noise);
400 normalize_noise(&walltime_nsecs_noise);
401 normalize_noise(&runtime_cycles_noise);
402
403 for (j = 0; j < nr_counters; j++) {
404 normalize_noise(&event_res_noise[j][0]);
405 normalize_noise(&event_res_noise[j][1]);
406 normalize_noise(&event_res_noise[j][2]);
407 }
408}
409
410static void print_stat(int argc, const char **argv)
411{
412 int i, counter;
413
414 calc_avg();
415
416 fflush(stdout);
417
418 fprintf(stderr, "\n");
419 fprintf(stderr, " Performance counter stats for \'%s", argv[0]);
420
421 for (i = 1; i < argc; i++)
422 fprintf(stderr, " %s", argv[i]);
423
424 fprintf(stderr, "\'");
425 if (run_count > 1)
426 fprintf(stderr, " (%d runs)", run_count);
427 fprintf(stderr, ":\n\n");
428
429 for (counter = 0; counter < nr_counters; counter++)
430 print_counter(counter);
431
432
433 fprintf(stderr, "\n");
434 fprintf(stderr, " %14.9f seconds time elapsed.\n",
435 (double)walltime_nsecs_avg/1e9);
436 fprintf(stderr, "\n");
437}
438
439static volatile int signr = -1;
440
441static void skip_signal(int signo)
442{
443 signr = signo;
444}
445
446static void sig_atexit(void)
447{
448 if (signr == -1)
449 return;
450
451 signal(signr, SIG_DFL);
452 kill(getpid(), signr);
453}
454
455static const char * const stat_usage[] = {
456 "perf stat [<options>] <command>",
457 NULL
458};
459
460static const struct option options[] = {
461 OPT_CALLBACK('e', "event", NULL, "event",
462 "event selector. use 'perf list' to list available events",
463 parse_events),
464 OPT_BOOLEAN('i', "inherit", &inherit,
465 "child tasks inherit counters"),
466 OPT_INTEGER('p', "pid", &target_pid,
467 "stat events on existing pid"),
468 OPT_BOOLEAN('a', "all-cpus", &system_wide,
469 "system-wide collection from all CPUs"),
470 OPT_BOOLEAN('S', "scale", &scale,
471 "scale/normalize counters"),
472 OPT_BOOLEAN('v', "verbose", &verbose,
473 "be more verbose (show counter open errors, etc)"),
474 OPT_INTEGER('r', "repeat", &run_count,
475 "repeat command and print average + stddev (max: 100)"),
476 OPT_END()
477};
478
479int cmd_stat(int argc, const char **argv, const char *prefix)
480{
481 int status;
482
483 page_size = sysconf(_SC_PAGE_SIZE);
484
485 memcpy(attrs, default_attrs, sizeof(attrs));
486
487 argc = parse_options(argc, argv, options, stat_usage, 0);
488 if (!argc)
489 usage_with_options(stat_usage, options);
490 if (run_count <= 0 || run_count > MAX_RUN)
491 usage_with_options(stat_usage, options);
492
493 if (!nr_counters)
494 nr_counters = 8;
495
496 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
497 assert(nr_cpus <= MAX_NR_CPUS);
498 assert(nr_cpus >= 0);
499
500 /*
501 * We dont want to block the signals - that would cause
502 * child tasks to inherit that and Ctrl-C would not work.
503 * What we want is for Ctrl-C to work in the exec()-ed
504 * task, but being ignored by perf stat itself:
505 */
506 atexit(sig_atexit);
507 signal(SIGINT, skip_signal);
508 signal(SIGALRM, skip_signal);
509 signal(SIGABRT, skip_signal);
510
511 status = 0;
512 for (run_idx = 0; run_idx < run_count; run_idx++) {
513 if (run_count != 1 && verbose)
514 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx+1);
515 status = run_perf_stat(argc, argv);
516 }
517
518 print_stat(argc, argv);
519
520 return status;
521}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
new file mode 100644
index 000000000000..5352b5e352ed
--- /dev/null
+++ b/tools/perf/builtin-top.c
@@ -0,0 +1,736 @@
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 "util/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
35#include <errno.h>
36#include <time.h>
37#include <sched.h>
38#include <pthread.h>
39
40#include <sys/syscall.h>
41#include <sys/ioctl.h>
42#include <sys/poll.h>
43#include <sys/prctl.h>
44#include <sys/wait.h>
45#include <sys/uio.h>
46#include <sys/mman.h>
47
48#include <linux/unistd.h>
49#include <linux/types.h>
50
51static int fd[MAX_NR_CPUS][MAX_COUNTERS];
52
53static int system_wide = 0;
54
55static int default_interval = 100000;
56
57static u64 count_filter = 5;
58static int print_entries = 15;
59
60static int target_pid = -1;
61static int profile_cpu = -1;
62static int nr_cpus = 0;
63static unsigned int realtime_prio = 0;
64static int group = 0;
65static unsigned int page_size;
66static unsigned int mmap_pages = 16;
67static int freq = 0;
68static int verbose = 0;
69
70static char *sym_filter;
71static unsigned long filter_start;
72static unsigned long filter_end;
73
74static int delay_secs = 2;
75static int zero;
76static int dump_symtab;
77
78/*
79 * Symbols
80 */
81
82static u64 min_ip;
83static u64 max_ip = -1ll;
84
85struct sym_entry {
86 struct rb_node rb_node;
87 struct list_head node;
88 unsigned long count[MAX_COUNTERS];
89 unsigned long snap_count;
90 double weight;
91 int skip;
92};
93
94struct sym_entry *sym_filter_entry;
95
96struct dso *kernel_dso;
97
98/*
99 * Symbols will be added here in record_ip and will get out
100 * after decayed.
101 */
102static LIST_HEAD(active_symbols);
103static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER;
104
105/*
106 * Ordering weight: count-1 * count-2 * ... / count-n
107 */
108static double sym_weight(const struct sym_entry *sym)
109{
110 double weight = sym->snap_count;
111 int counter;
112
113 for (counter = 1; counter < nr_counters-1; counter++)
114 weight *= sym->count[counter];
115
116 weight /= (sym->count[counter] + 1);
117
118 return weight;
119}
120
121static long samples;
122static long userspace_samples;
123static const char CONSOLE_CLEAR[] = "";
124
125static void __list_insert_active_sym(struct sym_entry *syme)
126{
127 list_add(&syme->node, &active_symbols);
128}
129
130static void list_remove_active_sym(struct sym_entry *syme)
131{
132 pthread_mutex_lock(&active_symbols_lock);
133 list_del_init(&syme->node);
134 pthread_mutex_unlock(&active_symbols_lock);
135}
136
137static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
138{
139 struct rb_node **p = &tree->rb_node;
140 struct rb_node *parent = NULL;
141 struct sym_entry *iter;
142
143 while (*p != NULL) {
144 parent = *p;
145 iter = rb_entry(parent, struct sym_entry, rb_node);
146
147 if (se->weight > iter->weight)
148 p = &(*p)->rb_left;
149 else
150 p = &(*p)->rb_right;
151 }
152
153 rb_link_node(&se->rb_node, parent, p);
154 rb_insert_color(&se->rb_node, tree);
155}
156
157static void print_sym_table(void)
158{
159 int printed = 0, j;
160 int counter;
161 float samples_per_sec = samples/delay_secs;
162 float ksamples_per_sec = (samples-userspace_samples)/delay_secs;
163 float sum_ksamples = 0.0;
164 struct sym_entry *syme, *n;
165 struct rb_root tmp = RB_ROOT;
166 struct rb_node *nd;
167
168 samples = userspace_samples = 0;
169
170 /* Sort the active symbols */
171 pthread_mutex_lock(&active_symbols_lock);
172 syme = list_entry(active_symbols.next, struct sym_entry, node);
173 pthread_mutex_unlock(&active_symbols_lock);
174
175 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
176 syme->snap_count = syme->count[0];
177 if (syme->snap_count != 0) {
178 syme->weight = sym_weight(syme);
179 rb_insert_active_sym(&tmp, syme);
180 sum_ksamples += syme->snap_count;
181
182 for (j = 0; j < nr_counters; j++)
183 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
184 } else
185 list_remove_active_sym(syme);
186 }
187
188 puts(CONSOLE_CLEAR);
189
190 printf(
191"------------------------------------------------------------------------------\n");
192 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [",
193 samples_per_sec,
194 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
195
196 if (nr_counters == 1) {
197 printf("%Ld", (u64)attrs[0].sample_period);
198 if (freq)
199 printf("Hz ");
200 else
201 printf(" ");
202 }
203
204 for (counter = 0; counter < nr_counters; counter++) {
205 if (counter)
206 printf("/");
207
208 printf("%s", event_name(counter));
209 }
210
211 printf( "], ");
212
213 if (target_pid != -1)
214 printf(" (target_pid: %d", target_pid);
215 else
216 printf(" (all");
217
218 if (profile_cpu != -1)
219 printf(", cpu: %d)\n", profile_cpu);
220 else {
221 if (target_pid != -1)
222 printf(")\n");
223 else
224 printf(", %d CPUs)\n", nr_cpus);
225 }
226
227 printf("------------------------------------------------------------------------------\n\n");
228
229 if (nr_counters == 1)
230 printf(" samples pcnt");
231 else
232 printf(" weight samples pcnt");
233
234 printf(" RIP kernel function\n"
235 " ______ _______ _____ ________________ _______________\n\n"
236 );
237
238 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
239 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
240 struct symbol *sym = (struct symbol *)(syme + 1);
241 char *color = PERF_COLOR_NORMAL;
242 double pcnt;
243
244 if (++printed > print_entries || syme->snap_count < count_filter)
245 continue;
246
247 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
248 sum_ksamples));
249
250 /*
251 * We color high-overhead entries in red, mid-overhead
252 * entries in green - and keep the low overhead places
253 * normal:
254 */
255 if (pcnt >= 5.0) {
256 color = PERF_COLOR_RED;
257 } else {
258 if (pcnt >= 0.5)
259 color = PERF_COLOR_GREEN;
260 }
261
262 if (nr_counters == 1)
263 printf("%20.2f - ", syme->weight);
264 else
265 printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
266
267 color_fprintf(stdout, color, "%4.1f%%", pcnt);
268 printf(" - %016llx : %s\n", sym->start, sym->name);
269 }
270}
271
272static void *display_thread(void *arg)
273{
274 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
275 int delay_msecs = delay_secs * 1000;
276
277 printf("PerfTop refresh period: %d seconds\n", delay_secs);
278
279 do {
280 print_sym_table();
281 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
282
283 printf("key pressed - exiting.\n");
284 exit(0);
285
286 return NULL;
287}
288
289static int symbol_filter(struct dso *self, struct symbol *sym)
290{
291 static int filter_match;
292 struct sym_entry *syme;
293 const char *name = sym->name;
294
295 if (!strcmp(name, "_text") ||
296 !strcmp(name, "_etext") ||
297 !strcmp(name, "_sinittext") ||
298 !strncmp("init_module", name, 11) ||
299 !strncmp("cleanup_module", name, 14) ||
300 strstr(name, "_text_start") ||
301 strstr(name, "_text_end"))
302 return 1;
303
304 syme = dso__sym_priv(self, sym);
305 /* Tag samples to be skipped. */
306 if (!strcmp("default_idle", name) ||
307 !strcmp("cpu_idle", name) ||
308 !strcmp("enter_idle", name) ||
309 !strcmp("exit_idle", name) ||
310 !strcmp("mwait_idle", name))
311 syme->skip = 1;
312
313 if (filter_match == 1) {
314 filter_end = sym->start;
315 filter_match = -1;
316 if (filter_end - filter_start > 10000) {
317 fprintf(stderr,
318 "hm, too large filter symbol <%s> - skipping.\n",
319 sym_filter);
320 fprintf(stderr, "symbol filter start: %016lx\n",
321 filter_start);
322 fprintf(stderr, " end: %016lx\n",
323 filter_end);
324 filter_end = filter_start = 0;
325 sym_filter = NULL;
326 sleep(1);
327 }
328 }
329
330 if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) {
331 filter_match = 1;
332 filter_start = sym->start;
333 }
334
335
336 return 0;
337}
338
339static int parse_symbols(void)
340{
341 struct rb_node *node;
342 struct symbol *sym;
343
344 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
345 if (kernel_dso == NULL)
346 return -1;
347
348 if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0)
349 goto out_delete_dso;
350
351 node = rb_first(&kernel_dso->syms);
352 sym = rb_entry(node, struct symbol, rb_node);
353 min_ip = sym->start;
354
355 node = rb_last(&kernel_dso->syms);
356 sym = rb_entry(node, struct symbol, rb_node);
357 max_ip = sym->end;
358
359 if (dump_symtab)
360 dso__fprintf(kernel_dso, stderr);
361
362 return 0;
363
364out_delete_dso:
365 dso__delete(kernel_dso);
366 kernel_dso = NULL;
367 return -1;
368}
369
370#define TRACE_COUNT 3
371
372/*
373 * Binary search in the histogram table and record the hit:
374 */
375static void record_ip(u64 ip, int counter)
376{
377 struct symbol *sym = dso__find_symbol(kernel_dso, ip);
378
379 if (sym != NULL) {
380 struct sym_entry *syme = dso__sym_priv(kernel_dso, sym);
381
382 if (!syme->skip) {
383 syme->count[counter]++;
384 pthread_mutex_lock(&active_symbols_lock);
385 if (list_empty(&syme->node) || !syme->node.next)
386 __list_insert_active_sym(syme);
387 pthread_mutex_unlock(&active_symbols_lock);
388 return;
389 }
390 }
391
392 samples--;
393}
394
395static void process_event(u64 ip, int counter)
396{
397 samples++;
398
399 if (ip < min_ip || ip > max_ip) {
400 userspace_samples++;
401 return;
402 }
403
404 record_ip(ip, counter);
405}
406
407struct mmap_data {
408 int counter;
409 void *base;
410 unsigned int mask;
411 unsigned int prev;
412};
413
414static unsigned int mmap_read_head(struct mmap_data *md)
415{
416 struct perf_counter_mmap_page *pc = md->base;
417 int head;
418
419 head = pc->data_head;
420 rmb();
421
422 return head;
423}
424
425struct timeval last_read, this_read;
426
427static void mmap_read_counter(struct mmap_data *md)
428{
429 unsigned int head = mmap_read_head(md);
430 unsigned int old = md->prev;
431 unsigned char *data = md->base + page_size;
432 int diff;
433
434 gettimeofday(&this_read, NULL);
435
436 /*
437 * If we're further behind than half the buffer, there's a chance
438 * the writer will bite our tail and mess up the samples under us.
439 *
440 * If we somehow ended up ahead of the head, we got messed up.
441 *
442 * In either case, truncate and restart at head.
443 */
444 diff = head - old;
445 if (diff > md->mask / 2 || diff < 0) {
446 struct timeval iv;
447 unsigned long msecs;
448
449 timersub(&this_read, &last_read, &iv);
450 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
451
452 fprintf(stderr, "WARNING: failed to keep up with mmap data."
453 " Last read %lu msecs ago.\n", msecs);
454
455 /*
456 * head points to a known good entry, start there.
457 */
458 old = head;
459 }
460
461 last_read = this_read;
462
463 for (; old != head;) {
464 struct ip_event {
465 struct perf_event_header header;
466 u64 ip;
467 u32 pid, target_pid;
468 };
469 struct mmap_event {
470 struct perf_event_header header;
471 u32 pid, target_pid;
472 u64 start;
473 u64 len;
474 u64 pgoff;
475 char filename[PATH_MAX];
476 };
477
478 typedef union event_union {
479 struct perf_event_header header;
480 struct ip_event ip;
481 struct mmap_event mmap;
482 } event_t;
483
484 event_t *event = (event_t *)&data[old & md->mask];
485
486 event_t event_copy;
487
488 size_t size = event->header.size;
489
490 /*
491 * Event straddles the mmap boundary -- header should always
492 * be inside due to u64 alignment of output.
493 */
494 if ((old & md->mask) + size != ((old + size) & md->mask)) {
495 unsigned int offset = old;
496 unsigned int len = min(sizeof(*event), size), cpy;
497 void *dst = &event_copy;
498
499 do {
500 cpy = min(md->mask + 1 - (offset & md->mask), len);
501 memcpy(dst, &data[offset & md->mask], cpy);
502 offset += cpy;
503 dst += cpy;
504 len -= cpy;
505 } while (len);
506
507 event = &event_copy;
508 }
509
510 old += size;
511
512 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
513 if (event->header.type & PERF_SAMPLE_IP)
514 process_event(event->ip.ip, md->counter);
515 }
516 }
517
518 md->prev = old;
519}
520
521static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
522static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
523
524static void mmap_read(void)
525{
526 int i, counter;
527
528 for (i = 0; i < nr_cpus; i++) {
529 for (counter = 0; counter < nr_counters; counter++)
530 mmap_read_counter(&mmap_array[i][counter]);
531 }
532}
533
534int nr_poll;
535int group_fd;
536
537static void start_counter(int i, int counter)
538{
539 struct perf_counter_attr *attr;
540 unsigned int cpu;
541
542 cpu = profile_cpu;
543 if (target_pid == -1 && profile_cpu == -1)
544 cpu = i;
545
546 attr = attrs + counter;
547
548 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
549 attr->freq = freq;
550
551try_again:
552 fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0);
553
554 if (fd[i][counter] < 0) {
555 int err = errno;
556
557 if (err == EPERM)
558 die("No permission - are you root?\n");
559 /*
560 * If it's cycles then fall back to hrtimer
561 * based cpu-clock-tick sw counter, which
562 * is always available even if no PMU support:
563 */
564 if (attr->type == PERF_TYPE_HARDWARE
565 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
566
567 if (verbose)
568 warning(" ... trying to fall back to cpu-clock-ticks\n");
569
570 attr->type = PERF_TYPE_SOFTWARE;
571 attr->config = PERF_COUNT_SW_CPU_CLOCK;
572 goto try_again;
573 }
574 printf("\n");
575 error("perfcounter syscall returned with %d (%s)\n",
576 fd[i][counter], strerror(err));
577 die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n");
578 exit(-1);
579 }
580 assert(fd[i][counter] >= 0);
581 fcntl(fd[i][counter], F_SETFL, O_NONBLOCK);
582
583 /*
584 * First counter acts as the group leader:
585 */
586 if (group && group_fd == -1)
587 group_fd = fd[i][counter];
588
589 event_array[nr_poll].fd = fd[i][counter];
590 event_array[nr_poll].events = POLLIN;
591 nr_poll++;
592
593 mmap_array[i][counter].counter = counter;
594 mmap_array[i][counter].prev = 0;
595 mmap_array[i][counter].mask = mmap_pages*page_size - 1;
596 mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
597 PROT_READ, MAP_SHARED, fd[i][counter], 0);
598 if (mmap_array[i][counter].base == MAP_FAILED)
599 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
600}
601
602static int __cmd_top(void)
603{
604 pthread_t thread;
605 int i, counter;
606 int ret;
607
608 for (i = 0; i < nr_cpus; i++) {
609 group_fd = -1;
610 for (counter = 0; counter < nr_counters; counter++)
611 start_counter(i, counter);
612 }
613
614 /* Wait for a minimal set of events before starting the snapshot */
615 poll(event_array, nr_poll, 100);
616
617 mmap_read();
618
619 if (pthread_create(&thread, NULL, display_thread, NULL)) {
620 printf("Could not create display thread.\n");
621 exit(-1);
622 }
623
624 if (realtime_prio) {
625 struct sched_param param;
626
627 param.sched_priority = realtime_prio;
628 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
629 printf("Could not set realtime priority.\n");
630 exit(-1);
631 }
632 }
633
634 while (1) {
635 int hits = samples;
636
637 mmap_read();
638
639 if (hits == samples)
640 ret = poll(event_array, nr_poll, 100);
641 }
642
643 return 0;
644}
645
646static const char * const top_usage[] = {
647 "perf top [<options>]",
648 NULL
649};
650
651static const struct option options[] = {
652 OPT_CALLBACK('e', "event", NULL, "event",
653 "event selector. use 'perf list' to list available events",
654 parse_events),
655 OPT_INTEGER('c', "count", &default_interval,
656 "event period to sample"),
657 OPT_INTEGER('p', "pid", &target_pid,
658 "profile events on existing pid"),
659 OPT_BOOLEAN('a', "all-cpus", &system_wide,
660 "system-wide collection from all CPUs"),
661 OPT_INTEGER('C', "CPU", &profile_cpu,
662 "CPU to profile on"),
663 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
664 "number of mmap data pages"),
665 OPT_INTEGER('r', "realtime", &realtime_prio,
666 "collect data with this RT SCHED_FIFO priority"),
667 OPT_INTEGER('d', "delay", &delay_secs,
668 "number of seconds to delay between refreshes"),
669 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
670 "dump the symbol table used for profiling"),
671 OPT_INTEGER('f', "count-filter", &count_filter,
672 "only display functions with more events than this"),
673 OPT_BOOLEAN('g', "group", &group,
674 "put the counters into a counter group"),
675 OPT_STRING('s', "sym-filter", &sym_filter, "pattern",
676 "only display symbols matchig this pattern"),
677 OPT_BOOLEAN('z', "zero", &group,
678 "zero history across updates"),
679 OPT_INTEGER('F', "freq", &freq,
680 "profile at this frequency"),
681 OPT_INTEGER('E', "entries", &print_entries,
682 "display this many functions"),
683 OPT_BOOLEAN('v', "verbose", &verbose,
684 "be more verbose (show counter open errors, etc)"),
685 OPT_END()
686};
687
688int cmd_top(int argc, const char **argv, const char *prefix)
689{
690 int counter;
691
692 page_size = sysconf(_SC_PAGE_SIZE);
693
694 argc = parse_options(argc, argv, options, top_usage, 0);
695 if (argc)
696 usage_with_options(top_usage, options);
697
698 if (freq) {
699 default_interval = freq;
700 freq = 1;
701 }
702
703 /* CPU and PID are mutually exclusive */
704 if (target_pid != -1 && profile_cpu != -1) {
705 printf("WARNING: PID switch overriding CPU\n");
706 sleep(1);
707 profile_cpu = -1;
708 }
709
710 if (!nr_counters)
711 nr_counters = 1;
712
713 if (delay_secs < 1)
714 delay_secs = 1;
715
716 parse_symbols();
717
718 /*
719 * Fill in the ones not specifically initialized via -c:
720 */
721 for (counter = 0; counter < nr_counters; counter++) {
722 if (attrs[counter].sample_period)
723 continue;
724
725 attrs[counter].sample_period = default_interval;
726 }
727
728 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
729 assert(nr_cpus <= MAX_NR_CPUS);
730 assert(nr_cpus >= 0);
731
732 if (target_pid != -1 || profile_cpu != -1)
733 nr_cpus = 1;
734
735 return __cmd_top();
736}
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..4eb725933703
--- /dev/null
+++ b/tools/perf/perf.c
@@ -0,0 +1,428 @@
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
16const char perf_usage_string[] =
17 "perf [--version] [--help] COMMAND [ARGS]";
18
19const char perf_more_info_string[] =
20 "See 'perf help COMMAND' for more information on a specific command.";
21
22static int use_pager = -1;
23struct pager_config {
24 const char *cmd;
25 int val;
26};
27
28static int pager_command_config(const char *var, const char *value, void *data)
29{
30 struct pager_config *c = data;
31 if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd))
32 c->val = perf_config_bool(var, value);
33 return 0;
34}
35
36/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
37int check_pager_config(const char *cmd)
38{
39 struct pager_config c;
40 c.cmd = cmd;
41 c.val = -1;
42 perf_config(pager_command_config, &c);
43 return c.val;
44}
45
46static void commit_pager_choice(void) {
47 switch (use_pager) {
48 case 0:
49 setenv("PERF_PAGER", "cat", 1);
50 break;
51 case 1:
52 /* setup_pager(); */
53 break;
54 default:
55 break;
56 }
57}
58
59static int handle_options(const char*** argv, int* argc, int* envchanged)
60{
61 int handled = 0;
62
63 while (*argc > 0) {
64 const char *cmd = (*argv)[0];
65 if (cmd[0] != '-')
66 break;
67
68 /*
69 * For legacy reasons, the "version" and "help"
70 * commands can be written with "--" prepended
71 * to make them look like flags.
72 */
73 if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
74 break;
75
76 /*
77 * Check remaining flags.
78 */
79 if (!prefixcmp(cmd, "--exec-path")) {
80 cmd += 11;
81 if (*cmd == '=')
82 perf_set_argv_exec_path(cmd + 1);
83 else {
84 puts(perf_exec_path());
85 exit(0);
86 }
87 } else if (!strcmp(cmd, "--html-path")) {
88 puts(system_path(PERF_HTML_PATH));
89 exit(0);
90 } else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
91 use_pager = 1;
92 } else if (!strcmp(cmd, "--no-pager")) {
93 use_pager = 0;
94 if (envchanged)
95 *envchanged = 1;
96 } else if (!strcmp(cmd, "--perf-dir")) {
97 if (*argc < 2) {
98 fprintf(stderr, "No directory given for --perf-dir.\n" );
99 usage(perf_usage_string);
100 }
101 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1);
102 if (envchanged)
103 *envchanged = 1;
104 (*argv)++;
105 (*argc)--;
106 handled++;
107 } else if (!prefixcmp(cmd, "--perf-dir=")) {
108 setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1);
109 if (envchanged)
110 *envchanged = 1;
111 } else if (!strcmp(cmd, "--work-tree")) {
112 if (*argc < 2) {
113 fprintf(stderr, "No directory given for --work-tree.\n" );
114 usage(perf_usage_string);
115 }
116 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
117 if (envchanged)
118 *envchanged = 1;
119 (*argv)++;
120 (*argc)--;
121 } else if (!prefixcmp(cmd, "--work-tree=")) {
122 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
123 if (envchanged)
124 *envchanged = 1;
125 } else {
126 fprintf(stderr, "Unknown option: %s\n", cmd);
127 usage(perf_usage_string);
128 }
129
130 (*argv)++;
131 (*argc)--;
132 handled++;
133 }
134 return handled;
135}
136
137static int handle_alias(int *argcp, const char ***argv)
138{
139 int envchanged = 0, ret = 0, saved_errno = errno;
140 int count, option_count;
141 const char** new_argv;
142 const char *alias_command;
143 char *alias_string;
144
145 alias_command = (*argv)[0];
146 alias_string = alias_lookup(alias_command);
147 if (alias_string) {
148 if (alias_string[0] == '!') {
149 if (*argcp > 1) {
150 struct strbuf buf;
151
152 strbuf_init(&buf, PATH_MAX);
153 strbuf_addstr(&buf, alias_string);
154 sq_quote_argv(&buf, (*argv) + 1, PATH_MAX);
155 free(alias_string);
156 alias_string = buf.buf;
157 }
158 ret = system(alias_string + 1);
159 if (ret >= 0 && WIFEXITED(ret) &&
160 WEXITSTATUS(ret) != 127)
161 exit(WEXITSTATUS(ret));
162 die("Failed to run '%s' when expanding alias '%s'",
163 alias_string + 1, alias_command);
164 }
165 count = split_cmdline(alias_string, &new_argv);
166 if (count < 0)
167 die("Bad alias.%s string", alias_command);
168 option_count = handle_options(&new_argv, &count, &envchanged);
169 if (envchanged)
170 die("alias '%s' changes environment variables\n"
171 "You can use '!perf' in the alias to do this.",
172 alias_command);
173 memmove(new_argv - option_count, new_argv,
174 count * sizeof(char *));
175 new_argv -= option_count;
176
177 if (count < 1)
178 die("empty alias for %s", alias_command);
179
180 if (!strcmp(alias_command, new_argv[0]))
181 die("recursive alias: %s", alias_command);
182
183 new_argv = realloc(new_argv, sizeof(char*) *
184 (count + *argcp + 1));
185 /* insert after command name */
186 memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp);
187 new_argv[count+*argcp] = NULL;
188
189 *argv = new_argv;
190 *argcp += count - 1;
191
192 ret = 1;
193 }
194
195 errno = saved_errno;
196
197 return ret;
198}
199
200const char perf_version_string[] = PERF_VERSION;
201
202#define RUN_SETUP (1<<0)
203#define USE_PAGER (1<<1)
204/*
205 * require working tree to be present -- anything uses this needs
206 * RUN_SETUP for reading from the configuration file.
207 */
208#define NEED_WORK_TREE (1<<2)
209
210struct cmd_struct {
211 const char *cmd;
212 int (*fn)(int, const char **, const char *);
213 int option;
214};
215
216static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
217{
218 int status;
219 struct stat st;
220 const char *prefix;
221
222 prefix = NULL;
223 if (p->option & RUN_SETUP)
224 prefix = NULL; /* setup_perf_directory(); */
225
226 if (use_pager == -1 && p->option & RUN_SETUP)
227 use_pager = check_pager_config(p->cmd);
228 if (use_pager == -1 && p->option & USE_PAGER)
229 use_pager = 1;
230 commit_pager_choice();
231
232 if (p->option & NEED_WORK_TREE)
233 /* setup_work_tree() */;
234
235 status = p->fn(argc, argv, prefix);
236 if (status)
237 return status & 0xff;
238
239 /* Somebody closed stdout? */
240 if (fstat(fileno(stdout), &st))
241 return 0;
242 /* Ignore write errors for pipes and sockets.. */
243 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
244 return 0;
245
246 /* Check for ENOSPC and EIO errors.. */
247 if (fflush(stdout))
248 die("write failure on standard output: %s", strerror(errno));
249 if (ferror(stdout))
250 die("unknown write failure on standard output");
251 if (fclose(stdout))
252 die("close failed on standard output: %s", strerror(errno));
253 return 0;
254}
255
256static void handle_internal_command(int argc, const char **argv)
257{
258 const char *cmd = argv[0];
259 static struct cmd_struct commands[] = {
260 { "help", cmd_help, 0 },
261 { "list", cmd_list, 0 },
262 { "record", cmd_record, 0 },
263 { "report", cmd_report, 0 },
264 { "stat", cmd_stat, 0 },
265 { "top", cmd_top, 0 },
266 { "annotate", cmd_annotate, 0 },
267 { "version", cmd_version, 0 },
268 };
269 int i;
270 static const char ext[] = STRIP_EXTENSION;
271
272 if (sizeof(ext) > 1) {
273 i = strlen(argv[0]) - strlen(ext);
274 if (i > 0 && !strcmp(argv[0] + i, ext)) {
275 char *argv0 = strdup(argv[0]);
276 argv[0] = cmd = argv0;
277 argv0[i] = '\0';
278 }
279 }
280
281 /* Turn "perf cmd --help" into "perf help cmd" */
282 if (argc > 1 && !strcmp(argv[1], "--help")) {
283 argv[1] = argv[0];
284 argv[0] = cmd = "help";
285 }
286
287 for (i = 0; i < ARRAY_SIZE(commands); i++) {
288 struct cmd_struct *p = commands+i;
289 if (strcmp(p->cmd, cmd))
290 continue;
291 exit(run_builtin(p, argc, argv));
292 }
293}
294
295static void execv_dashed_external(const char **argv)
296{
297 struct strbuf cmd = STRBUF_INIT;
298 const char *tmp;
299 int status;
300
301 strbuf_addf(&cmd, "perf-%s", argv[0]);
302
303 /*
304 * argv[0] must be the perf command, but the argv array
305 * belongs to the caller, and may be reused in
306 * subsequent loop iterations. Save argv[0] and
307 * restore it on error.
308 */
309 tmp = argv[0];
310 argv[0] = cmd.buf;
311
312 /*
313 * if we fail because the command is not found, it is
314 * OK to return. Otherwise, we just pass along the status code.
315 */
316 status = run_command_v_opt(argv, 0);
317 if (status != -ERR_RUN_COMMAND_EXEC) {
318 if (IS_RUN_COMMAND_ERR(status))
319 die("unable to run '%s'", argv[0]);
320 exit(-status);
321 }
322 errno = ENOENT; /* as if we called execvp */
323
324 argv[0] = tmp;
325
326 strbuf_release(&cmd);
327}
328
329static int run_argv(int *argcp, const char ***argv)
330{
331 int done_alias = 0;
332
333 while (1) {
334 /* See if it's an internal command */
335 handle_internal_command(*argcp, *argv);
336
337 /* .. then try the external ones */
338 execv_dashed_external(*argv);
339
340 /* It could be an alias -- this works around the insanity
341 * of overriding "perf log" with "perf show" by having
342 * alias.log = show
343 */
344 if (done_alias || !handle_alias(argcp, argv))
345 break;
346 done_alias = 1;
347 }
348
349 return done_alias;
350}
351
352
353int main(int argc, const char **argv)
354{
355 const char *cmd;
356
357 cmd = perf_extract_argv0_path(argv[0]);
358 if (!cmd)
359 cmd = "perf-help";
360
361 /*
362 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
363 *
364 * - cannot take flags in between the "perf" and the "xxxx".
365 * - cannot execute it externally (since it would just do
366 * the same thing over again)
367 *
368 * So we just directly call the internal command handler, and
369 * die if that one cannot handle it.
370 */
371 if (!prefixcmp(cmd, "perf-")) {
372 cmd += 5;
373 argv[0] = cmd;
374 handle_internal_command(argc, argv);
375 die("cannot handle %s internally", cmd);
376 }
377
378 /* Look for flags.. */
379 argv++;
380 argc--;
381 handle_options(&argv, &argc, NULL);
382 commit_pager_choice();
383 if (argc > 0) {
384 if (!prefixcmp(argv[0], "--"))
385 argv[0] += 2;
386 } else {
387 /* The user didn't specify a command; give them help */
388 printf("\n usage: %s\n\n", perf_usage_string);
389 list_common_cmds_help();
390 printf("\n %s\n\n", perf_more_info_string);
391 exit(1);
392 }
393 cmd = argv[0];
394
395 /*
396 * We use PATH to find perf commands, but we prepend some higher
397 * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH
398 * environment, and the $(perfexecdir) from the Makefile at build
399 * time.
400 */
401 setup_path();
402
403 while (1) {
404 static int done_help = 0;
405 static int was_alias = 0;
406
407 was_alias = run_argv(&argc, &argv);
408 if (errno != ENOENT)
409 break;
410
411 if (was_alias) {
412 fprintf(stderr, "Expansion of alias '%s' failed; "
413 "'%s' is not a perf-command\n",
414 cmd, argv[0]);
415 exit(1);
416 }
417 if (!done_help) {
418 cmd = argv[0] = help_unknown_cmd(cmd);
419 done_help = 1;
420 } else
421 break;
422 }
423
424 fprintf(stderr, "Failed to run command '%s': %s\n",
425 cmd, strerror(errno));
426
427 return 1;
428}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
new file mode 100644
index 000000000000..ceb68aa51f7f
--- /dev/null
+++ b/tools/perf/perf.h
@@ -0,0 +1,81 @@
1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H
3
4#if defined(__x86_64__) || defined(__i386__)
5#include "../../arch/x86/include/asm/unistd.h"
6#define rmb() asm volatile("lfence" ::: "memory")
7#define cpu_relax() asm volatile("rep; nop" ::: "memory");
8#endif
9
10#ifdef __powerpc__
11#include "../../arch/powerpc/include/asm/unistd.h"
12#define rmb() asm volatile ("sync" ::: "memory")
13#define cpu_relax() asm volatile ("" ::: "memory");
14#endif
15
16#ifdef __s390__
17#include "../../arch/s390/include/asm/unistd.h"
18#define rmb() asm volatile("bcr 15,0" ::: "memory")
19#define cpu_relax() asm volatile("" ::: "memory");
20#endif
21
22#include <time.h>
23#include <unistd.h>
24#include <sys/types.h>
25#include <sys/syscall.h>
26
27#include "../../include/linux/perf_counter.h"
28#include "types.h"
29
30/*
31 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
32 * counters in the current task.
33 */
34#define PR_TASK_PERF_COUNTERS_DISABLE 31
35#define PR_TASK_PERF_COUNTERS_ENABLE 32
36
37#ifndef NSEC_PER_SEC
38# define NSEC_PER_SEC 1000000000ULL
39#endif
40
41static inline unsigned long long rdclock(void)
42{
43 struct timespec ts;
44
45 clock_gettime(CLOCK_MONOTONIC, &ts);
46 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
47}
48
49/*
50 * Pick up some kernel type conventions:
51 */
52#define __user
53#define asmlinkage
54
55#define unlikely(x) __builtin_expect(!!(x), 0)
56#define min(x, y) ({ \
57 typeof(x) _min1 = (x); \
58 typeof(y) _min2 = (y); \
59 (void) (&_min1 == &_min2); \
60 _min1 < _min2 ? _min1 : _min2; })
61
62static inline int
63sys_perf_counter_open(struct perf_counter_attr *attr,
64 pid_t pid, int cpu, int group_fd,
65 unsigned long flags)
66{
67 attr->size = sizeof(*attr);
68 return syscall(__NR_perf_counter_open, attr, pid, cpu,
69 group_fd, flags);
70}
71
72#define MAX_COUNTERS 256
73#define MAX_NR_CPUS 256
74
75struct perf_file_header {
76 u64 version;
77 u64 sample_type;
78 u64 data_size;
79};
80
81#endif
diff --git a/tools/perf/types.h b/tools/perf/types.h
new file mode 100644
index 000000000000..5e75f9005940
--- /dev/null
+++ b/tools/perf/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/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..9b3dd2b428df
--- /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)
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..393d6146d13b
--- /dev/null
+++ b/tools/perf/util/cache.h
@@ -0,0 +1,119 @@
1#ifndef CACHE_H
2#define CACHE_H
3
4#include "util.h"
5#include "strbuf.h"
6
7#define PERF_DIR_ENVIRONMENT "PERF_DIR"
8#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
9#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
10#define DB_ENVIRONMENT "PERF_OBJECT_DIRECTORY"
11#define INDEX_ENVIRONMENT "PERF_INDEX_FILE"
12#define GRAFT_ENVIRONMENT "PERF_GRAFT_FILE"
13#define TEMPLATE_DIR_ENVIRONMENT "PERF_TEMPLATE_DIR"
14#define CONFIG_ENVIRONMENT "PERF_CONFIG"
15#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH"
16#define CEILING_DIRECTORIES_ENVIRONMENT "PERF_CEILING_DIRECTORIES"
17#define PERFATTRIBUTES_FILE ".perfattributes"
18#define INFOATTRIBUTES_FILE "info/attributes"
19#define ATTRIBUTE_MACRO_PREFIX "[attr]"
20
21typedef int (*config_fn_t)(const char *, const char *, void *);
22extern int perf_default_config(const char *, const char *, void *);
23extern int perf_config_from_file(config_fn_t fn, const char *, void *);
24extern int perf_config(config_fn_t fn, void *);
25extern int perf_parse_ulong(const char *, unsigned long *);
26extern int perf_config_int(const char *, const char *);
27extern unsigned long perf_config_ulong(const char *, const char *);
28extern int perf_config_bool_or_int(const char *, const char *, int *);
29extern int perf_config_bool(const char *, const char *);
30extern int perf_config_string(const char **, const char *, const char *);
31extern int perf_config_set(const char *, const char *);
32extern int perf_config_set_multivar(const char *, const char *, const char *, int);
33extern int perf_config_rename_section(const char *, const char *);
34extern const char *perf_etc_perfconfig(void);
35extern int check_repository_format_version(const char *var, const char *value, void *cb);
36extern int perf_config_system(void);
37extern int perf_config_global(void);
38extern int config_error_nonbool(const char *);
39extern const char *config_exclusive_filename;
40
41#define MAX_PERFNAME (1000)
42extern char perf_default_email[MAX_PERFNAME];
43extern char perf_default_name[MAX_PERFNAME];
44extern int user_ident_explicitly_given;
45
46extern const char *perf_log_output_encoding;
47extern const char *perf_mailmap_file;
48
49/* IO helper functions */
50extern void maybe_flush_or_die(FILE *, const char *);
51extern int copy_fd(int ifd, int ofd);
52extern int copy_file(const char *dst, const char *src, int mode);
53extern ssize_t read_in_full(int fd, void *buf, size_t count);
54extern ssize_t write_in_full(int fd, const void *buf, size_t count);
55extern void write_or_die(int fd, const void *buf, size_t count);
56extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
57extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
58extern void fsync_or_die(int fd, const char *);
59
60/* pager.c */
61extern void setup_pager(void);
62extern const char *pager_program;
63extern int pager_in_use(void);
64extern int pager_use_color;
65
66extern const char *editor_program;
67extern const char *excludes_file;
68
69char *alias_lookup(const char *alias);
70int split_cmdline(char *cmdline, const char ***argv);
71
72#define alloc_nr(x) (((x)+16)*3/2)
73
74/*
75 * Realloc the buffer pointed at by variable 'x' so that it can hold
76 * at least 'nr' entries; the number of entries currently allocated
77 * is 'alloc', using the standard growing factor alloc_nr() macro.
78 *
79 * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
80 */
81#define ALLOC_GROW(x, nr, alloc) \
82 do { \
83 if ((nr) > alloc) { \
84 if (alloc_nr(alloc) < (nr)) \
85 alloc = (nr); \
86 else \
87 alloc = alloc_nr(alloc); \
88 x = xrealloc((x), alloc * sizeof(*(x))); \
89 } \
90 } while(0)
91
92
93static inline int is_absolute_path(const char *path)
94{
95 return path[0] == '/';
96}
97
98const char *make_absolute_path(const char *path);
99const char *make_nonrelative_path(const char *path);
100const char *make_relative_path(const char *abs, const char *base);
101int normalize_path_copy(char *dst, const char *src);
102int longest_ancestor_length(const char *path, const char *prefix_list);
103char *strip_path_suffix(const char *path, const char *suffix);
104
105extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
106extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
107/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
108extern int perf_mkstemp(char *path, size_t len, const char *template);
109
110extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
111 __attribute__((format (printf, 3, 4)));
112extern char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
113 __attribute__((format (printf, 3, 4)));
114extern char *perf_pathdup(const char *fmt, ...)
115 __attribute__((format (printf, 1, 2)));
116
117extern size_t strlcpy(char *dest, const char *src, size_t size);
118
119#endif /* CACHE_H */
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
new file mode 100644
index 000000000000..9a8c20ccc53e
--- /dev/null
+++ b/tools/perf/util/color.c
@@ -0,0 +1,241 @@
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 for (i = 0; i < ARRAY_SIZE(color_names); i++) {
15 const char *str = color_names[i];
16 if (!strncasecmp(name, str, len) && !str[len])
17 return i - 1;
18 }
19 i = strtol(name, &end, 10);
20 if (end - name == len && i >= -1 && i <= 255)
21 return i;
22 return -2;
23}
24
25static int parse_attr(const char *name, int len)
26{
27 static const int attr_values[] = { 1, 2, 4, 5, 7 };
28 static const char * const attr_names[] = {
29 "bold", "dim", "ul", "blink", "reverse"
30 };
31 int i;
32 for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
33 const char *str = attr_names[i];
34 if (!strncasecmp(name, str, len) && !str[len])
35 return attr_values[i];
36 }
37 return -1;
38}
39
40void color_parse(const char *value, const char *var, char *dst)
41{
42 color_parse_mem(value, strlen(value), var, dst);
43}
44
45void color_parse_mem(const char *value, int value_len, const char *var,
46 char *dst)
47{
48 const char *ptr = value;
49 int len = value_len;
50 int attr = -1;
51 int fg = -2;
52 int bg = -2;
53
54 if (!strncasecmp(value, "reset", len)) {
55 strcpy(dst, PERF_COLOR_RESET);
56 return;
57 }
58
59 /* [fg [bg]] [attr] */
60 while (len > 0) {
61 const char *word = ptr;
62 int val, wordlen = 0;
63
64 while (len > 0 && !isspace(word[wordlen])) {
65 wordlen++;
66 len--;
67 }
68
69 ptr = word + wordlen;
70 while (len > 0 && isspace(*ptr)) {
71 ptr++;
72 len--;
73 }
74
75 val = parse_color(word, wordlen);
76 if (val >= -1) {
77 if (fg == -2) {
78 fg = val;
79 continue;
80 }
81 if (bg == -2) {
82 bg = val;
83 continue;
84 }
85 goto bad;
86 }
87 val = parse_attr(word, wordlen);
88 if (val < 0 || attr != -1)
89 goto bad;
90 attr = val;
91 }
92
93 if (attr >= 0 || fg >= 0 || bg >= 0) {
94 int sep = 0;
95
96 *dst++ = '\033';
97 *dst++ = '[';
98 if (attr >= 0) {
99 *dst++ = '0' + attr;
100 sep++;
101 }
102 if (fg >= 0) {
103 if (sep++)
104 *dst++ = ';';
105 if (fg < 8) {
106 *dst++ = '3';
107 *dst++ = '0' + fg;
108 } else {
109 dst += sprintf(dst, "38;5;%d", fg);
110 }
111 }
112 if (bg >= 0) {
113 if (sep++)
114 *dst++ = ';';
115 if (bg < 8) {
116 *dst++ = '4';
117 *dst++ = '0' + bg;
118 } else {
119 dst += sprintf(dst, "48;5;%d", bg);
120 }
121 }
122 *dst++ = 'm';
123 }
124 *dst = 0;
125 return;
126bad:
127 die("bad color value '%.*s' for variable '%s'", value_len, value, var);
128}
129
130int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
131{
132 if (value) {
133 if (!strcasecmp(value, "never"))
134 return 0;
135 if (!strcasecmp(value, "always"))
136 return 1;
137 if (!strcasecmp(value, "auto"))
138 goto auto_color;
139 }
140
141 /* Missing or explicit false to turn off colorization */
142 if (!perf_config_bool(var, value))
143 return 0;
144
145 /* any normal truth value defaults to 'auto' */
146 auto_color:
147 if (stdout_is_tty < 0)
148 stdout_is_tty = isatty(1);
149 if (stdout_is_tty || (pager_in_use() && pager_use_color)) {
150 char *term = getenv("TERM");
151 if (term && strcmp(term, "dumb"))
152 return 1;
153 }
154 return 0;
155}
156
157int perf_color_default_config(const char *var, const char *value, void *cb)
158{
159 if (!strcmp(var, "color.ui")) {
160 perf_use_color_default = perf_config_colorbool(var, value, -1);
161 return 0;
162 }
163
164 return perf_default_config(var, value, cb);
165}
166
167static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
168 va_list args, const char *trail)
169{
170 int r = 0;
171
172 /*
173 * Auto-detect:
174 */
175 if (perf_use_color_default < 0) {
176 if (isatty(1) || pager_in_use())
177 perf_use_color_default = 1;
178 else
179 perf_use_color_default = 0;
180 }
181
182 if (perf_use_color_default && *color)
183 r += fprintf(fp, "%s", color);
184 r += vfprintf(fp, fmt, args);
185 if (perf_use_color_default && *color)
186 r += fprintf(fp, "%s", PERF_COLOR_RESET);
187 if (trail)
188 r += fprintf(fp, "%s", trail);
189 return r;
190}
191
192
193
194int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
195{
196 va_list args;
197 int r;
198
199 va_start(args, fmt);
200 r = color_vfprintf(fp, color, fmt, args, NULL);
201 va_end(args);
202 return r;
203}
204
205int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
206{
207 va_list args;
208 int r;
209 va_start(args, fmt);
210 r = color_vfprintf(fp, color, fmt, args, "\n");
211 va_end(args);
212 return r;
213}
214
215/*
216 * This function splits the buffer by newlines and colors the lines individually.
217 *
218 * Returns 0 on success.
219 */
220int color_fwrite_lines(FILE *fp, const char *color,
221 size_t count, const char *buf)
222{
223 if (!*color)
224 return fwrite(buf, count, 1, fp) != 1;
225 while (count) {
226 char *p = memchr(buf, '\n', count);
227 if (p != buf && (fputs(color, fp) < 0 ||
228 fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
229 fputs(PERF_COLOR_RESET, fp) < 0))
230 return -1;
231 if (!p)
232 return 0;
233 if (fputc('\n', fp) < 0)
234 return -1;
235 count -= p + 1 - buf;
236 buf = p + 1;
237 }
238 return 0;
239}
240
241
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
new file mode 100644
index 000000000000..5abfd379582b
--- /dev/null
+++ b/tools/perf/util/color.h
@@ -0,0 +1,36 @@
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/*
19 * This variable stores the value of color.ui
20 */
21extern int perf_use_color_default;
22
23
24/*
25 * Use this instead of perf_default_config if you need the value of color.ui.
26 */
27int perf_color_default_config(const char *var, const char *value, void *cb);
28
29int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
30void color_parse(const char *value, const char *var, char *dst);
31void color_parse_mem(const char *value, int len, const char *var, char *dst);
32int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
33int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
34int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
35
36#endif /* COLOR_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
new file mode 100644
index 000000000000..3dd13faa6a27
--- /dev/null
+++ b/tools/perf/util/config.c
@@ -0,0 +1,873 @@
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, len = 0, space = 0;
51
52 for (;;) {
53 int c = get_next_char();
54 if (len >= sizeof(value) - 1)
55 return NULL;
56 if (c == '\n') {
57 if (quote)
58 return NULL;
59 value[len] = 0;
60 return value;
61 }
62 if (comment)
63 continue;
64 if (isspace(c) && !quote) {
65 space = 1;
66 continue;
67 }
68 if (!quote) {
69 if (c == ';' || c == '#') {
70 comment = 1;
71 continue;
72 }
73 }
74 if (space) {
75 if (len)
76 value[len++] = ' ';
77 space = 0;
78 }
79 if (c == '\\') {
80 c = get_next_char();
81 switch (c) {
82 case '\n':
83 continue;
84 case 't':
85 c = '\t';
86 break;
87 case 'b':
88 c = '\b';
89 break;
90 case 'n':
91 c = '\n';
92 break;
93 /* Some characters escape as themselves */
94 case '\\': case '"':
95 break;
96 /* Reject unknown escape sequences */
97 default:
98 return NULL;
99 }
100 value[len++] = c;
101 continue;
102 }
103 if (c == '"') {
104 quote = 1-quote;
105 continue;
106 }
107 value[len++] = c;
108 }
109}
110
111static inline int iskeychar(int c)
112{
113 return isalnum(c) || c == '-';
114}
115
116static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
117{
118 int c;
119 char *value;
120
121 /* Get the full name */
122 for (;;) {
123 c = get_next_char();
124 if (config_file_eof)
125 break;
126 if (!iskeychar(c))
127 break;
128 name[len++] = tolower(c);
129 if (len >= MAXNAME)
130 return -1;
131 }
132 name[len] = 0;
133 while (c == ' ' || c == '\t')
134 c = get_next_char();
135
136 value = NULL;
137 if (c != '\n') {
138 if (c != '=')
139 return -1;
140 value = parse_value();
141 if (!value)
142 return -1;
143 }
144 return fn(name, value, data);
145}
146
147static int get_extended_base_var(char *name, int baselen, int c)
148{
149 do {
150 if (c == '\n')
151 return -1;
152 c = get_next_char();
153 } while (isspace(c));
154
155 /* We require the format to be '[base "extension"]' */
156 if (c != '"')
157 return -1;
158 name[baselen++] = '.';
159
160 for (;;) {
161 int c = get_next_char();
162 if (c == '\n')
163 return -1;
164 if (c == '"')
165 break;
166 if (c == '\\') {
167 c = get_next_char();
168 if (c == '\n')
169 return -1;
170 }
171 name[baselen++] = c;
172 if (baselen > MAXNAME / 2)
173 return -1;
174 }
175
176 /* Final ']' */
177 if (get_next_char() != ']')
178 return -1;
179 return baselen;
180}
181
182static int get_base_var(char *name)
183{
184 int baselen = 0;
185
186 for (;;) {
187 int c = get_next_char();
188 if (config_file_eof)
189 return -1;
190 if (c == ']')
191 return baselen;
192 if (isspace(c))
193 return get_extended_base_var(name, baselen, c);
194 if (!iskeychar(c) && c != '.')
195 return -1;
196 if (baselen > MAXNAME / 2)
197 return -1;
198 name[baselen++] = tolower(c);
199 }
200}
201
202static int perf_parse_file(config_fn_t fn, void *data)
203{
204 int comment = 0;
205 int baselen = 0;
206 static char var[MAXNAME];
207
208 /* U+FEFF Byte Order Mark in UTF8 */
209 static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
210 const unsigned char *bomptr = utf8_bom;
211
212 for (;;) {
213 int c = get_next_char();
214 if (bomptr && *bomptr) {
215 /* We are at the file beginning; skip UTF8-encoded BOM
216 * if present. Sane editors won't put this in on their
217 * own, but e.g. Windows Notepad will do it happily. */
218 if ((unsigned char) c == *bomptr) {
219 bomptr++;
220 continue;
221 } else {
222 /* Do not tolerate partial BOM. */
223 if (bomptr != utf8_bom)
224 break;
225 /* No BOM at file beginning. Cool. */
226 bomptr = NULL;
227 }
228 }
229 if (c == '\n') {
230 if (config_file_eof)
231 return 0;
232 comment = 0;
233 continue;
234 }
235 if (comment || isspace(c))
236 continue;
237 if (c == '#' || c == ';') {
238 comment = 1;
239 continue;
240 }
241 if (c == '[') {
242 baselen = get_base_var(var);
243 if (baselen <= 0)
244 break;
245 var[baselen++] = '.';
246 var[baselen] = 0;
247 continue;
248 }
249 if (!isalpha(c))
250 break;
251 var[baselen] = tolower(c);
252 if (get_value(fn, data, var, baselen+1) < 0)
253 break;
254 }
255 die("bad config file line %d in %s", config_linenr, config_file_name);
256}
257
258static int parse_unit_factor(const char *end, unsigned long *val)
259{
260 if (!*end)
261 return 1;
262 else if (!strcasecmp(end, "k")) {
263 *val *= 1024;
264 return 1;
265 }
266 else if (!strcasecmp(end, "m")) {
267 *val *= 1024 * 1024;
268 return 1;
269 }
270 else if (!strcasecmp(end, "g")) {
271 *val *= 1024 * 1024 * 1024;
272 return 1;
273 }
274 return 0;
275}
276
277static int perf_parse_long(const char *value, long *ret)
278{
279 if (value && *value) {
280 char *end;
281 long val = strtol(value, &end, 0);
282 unsigned long factor = 1;
283 if (!parse_unit_factor(end, &factor))
284 return 0;
285 *ret = val * factor;
286 return 1;
287 }
288 return 0;
289}
290
291int perf_parse_ulong(const char *value, unsigned long *ret)
292{
293 if (value && *value) {
294 char *end;
295 unsigned long val = strtoul(value, &end, 0);
296 if (!parse_unit_factor(end, &val))
297 return 0;
298 *ret = val;
299 return 1;
300 }
301 return 0;
302}
303
304static void die_bad_config(const char *name)
305{
306 if (config_file_name)
307 die("bad config value for '%s' in %s", name, config_file_name);
308 die("bad config value for '%s'", name);
309}
310
311int perf_config_int(const char *name, const char *value)
312{
313 long ret = 0;
314 if (!perf_parse_long(value, &ret))
315 die_bad_config(name);
316 return ret;
317}
318
319unsigned long perf_config_ulong(const char *name, const char *value)
320{
321 unsigned long ret;
322 if (!perf_parse_ulong(value, &ret))
323 die_bad_config(name);
324 return ret;
325}
326
327int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
328{
329 *is_bool = 1;
330 if (!value)
331 return 1;
332 if (!*value)
333 return 0;
334 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
335 return 1;
336 if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
337 return 0;
338 *is_bool = 0;
339 return perf_config_int(name, value);
340}
341
342int perf_config_bool(const char *name, const char *value)
343{
344 int discard;
345 return !!perf_config_bool_or_int(name, value, &discard);
346}
347
348int perf_config_string(const char **dest, const char *var, const char *value)
349{
350 if (!value)
351 return config_error_nonbool(var);
352 *dest = strdup(value);
353 return 0;
354}
355
356static int perf_default_core_config(const char *var, const char *value)
357{
358 /* Add other config variables here and to Documentation/config.txt. */
359 return 0;
360}
361
362int perf_default_config(const char *var, const char *value, void *dummy)
363{
364 if (!prefixcmp(var, "core."))
365 return perf_default_core_config(var, value);
366
367 /* Add other config variables here and to Documentation/config.txt. */
368 return 0;
369}
370
371int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
372{
373 int ret;
374 FILE *f = fopen(filename, "r");
375
376 ret = -1;
377 if (f) {
378 config_file = f;
379 config_file_name = filename;
380 config_linenr = 1;
381 config_file_eof = 0;
382 ret = perf_parse_file(fn, data);
383 fclose(f);
384 config_file_name = NULL;
385 }
386 return ret;
387}
388
389const char *perf_etc_perfconfig(void)
390{
391 static const char *system_wide;
392 if (!system_wide)
393 system_wide = system_path(ETC_PERFCONFIG);
394 return system_wide;
395}
396
397static int perf_env_bool(const char *k, int def)
398{
399 const char *v = getenv(k);
400 return v ? perf_config_bool(k, v) : def;
401}
402
403int perf_config_system(void)
404{
405 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
406}
407
408int perf_config_global(void)
409{
410 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
411}
412
413int perf_config(config_fn_t fn, void *data)
414{
415 int ret = 0, found = 0;
416 char *repo_config = NULL;
417 const char *home = NULL;
418
419 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
420 if (config_exclusive_filename)
421 return perf_config_from_file(fn, config_exclusive_filename, data);
422 if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
423 ret += perf_config_from_file(fn, perf_etc_perfconfig(),
424 data);
425 found += 1;
426 }
427
428 home = getenv("HOME");
429 if (perf_config_global() && home) {
430 char *user_config = strdup(mkpath("%s/.perfconfig", home));
431 if (!access(user_config, R_OK)) {
432 ret += perf_config_from_file(fn, user_config, data);
433 found += 1;
434 }
435 free(user_config);
436 }
437
438 repo_config = perf_pathdup("config");
439 if (!access(repo_config, R_OK)) {
440 ret += perf_config_from_file(fn, repo_config, data);
441 found += 1;
442 }
443 free(repo_config);
444 if (found == 0)
445 return -1;
446 return ret;
447}
448
449/*
450 * Find all the stuff for perf_config_set() below.
451 */
452
453#define MAX_MATCHES 512
454
455static struct {
456 int baselen;
457 char* key;
458 int do_not_match;
459 regex_t* value_regex;
460 int multi_replace;
461 size_t offset[MAX_MATCHES];
462 enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
463 int seen;
464} store;
465
466static int matches(const char* key, const char* value)
467{
468 return !strcmp(key, store.key) &&
469 (store.value_regex == NULL ||
470 (store.do_not_match ^
471 !regexec(store.value_regex, value, 0, NULL, 0)));
472}
473
474static int store_aux(const char* key, const char* value, void *cb)
475{
476 const char *ep;
477 size_t section_len;
478
479 switch (store.state) {
480 case KEY_SEEN:
481 if (matches(key, value)) {
482 if (store.seen == 1 && store.multi_replace == 0) {
483 warning("%s has multiple values", key);
484 } else if (store.seen >= MAX_MATCHES) {
485 error("too many matches for %s", key);
486 return 1;
487 }
488
489 store.offset[store.seen] = ftell(config_file);
490 store.seen++;
491 }
492 break;
493 case SECTION_SEEN:
494 /*
495 * What we are looking for is in store.key (both
496 * section and var), and its section part is baselen
497 * long. We found key (again, both section and var).
498 * We would want to know if this key is in the same
499 * section as what we are looking for. We already
500 * know we are in the same section as what should
501 * hold store.key.
502 */
503 ep = strrchr(key, '.');
504 section_len = ep - key;
505
506 if ((section_len != store.baselen) ||
507 memcmp(key, store.key, section_len+1)) {
508 store.state = SECTION_END_SEEN;
509 break;
510 }
511
512 /*
513 * Do not increment matches: this is no match, but we
514 * just made sure we are in the desired section.
515 */
516 store.offset[store.seen] = ftell(config_file);
517 /* fallthru */
518 case SECTION_END_SEEN:
519 case START:
520 if (matches(key, value)) {
521 store.offset[store.seen] = ftell(config_file);
522 store.state = KEY_SEEN;
523 store.seen++;
524 } else {
525 if (strrchr(key, '.') - key == store.baselen &&
526 !strncmp(key, store.key, store.baselen)) {
527 store.state = SECTION_SEEN;
528 store.offset[store.seen] = ftell(config_file);
529 }
530 }
531 }
532 return 0;
533}
534
535static int store_write_section(int fd, const char* key)
536{
537 const char *dot;
538 int i, success;
539 struct strbuf sb = STRBUF_INIT;
540
541 dot = memchr(key, '.', store.baselen);
542 if (dot) {
543 strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
544 for (i = dot - key + 1; i < store.baselen; i++) {
545 if (key[i] == '"' || key[i] == '\\')
546 strbuf_addch(&sb, '\\');
547 strbuf_addch(&sb, key[i]);
548 }
549 strbuf_addstr(&sb, "\"]\n");
550 } else {
551 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
552 }
553
554 success = write_in_full(fd, sb.buf, sb.len) == sb.len;
555 strbuf_release(&sb);
556
557 return success;
558}
559
560static int store_write_pair(int fd, const char* key, const char* value)
561{
562 int i, success;
563 int length = strlen(key + store.baselen + 1);
564 const char *quote = "";
565 struct strbuf sb = STRBUF_INIT;
566
567 /*
568 * Check to see if the value needs to be surrounded with a dq pair.
569 * Note that problematic characters are always backslash-quoted; this
570 * check is about not losing leading or trailing SP and strings that
571 * follow beginning-of-comment characters (i.e. ';' and '#') by the
572 * configuration parser.
573 */
574 if (value[0] == ' ')
575 quote = "\"";
576 for (i = 0; value[i]; i++)
577 if (value[i] == ';' || value[i] == '#')
578 quote = "\"";
579 if (i && value[i - 1] == ' ')
580 quote = "\"";
581
582 strbuf_addf(&sb, "\t%.*s = %s",
583 length, key + store.baselen + 1, quote);
584
585 for (i = 0; value[i]; i++)
586 switch (value[i]) {
587 case '\n':
588 strbuf_addstr(&sb, "\\n");
589 break;
590 case '\t':
591 strbuf_addstr(&sb, "\\t");
592 break;
593 case '"':
594 case '\\':
595 strbuf_addch(&sb, '\\');
596 default:
597 strbuf_addch(&sb, value[i]);
598 break;
599 }
600 strbuf_addf(&sb, "%s\n", quote);
601
602 success = write_in_full(fd, sb.buf, sb.len) == sb.len;
603 strbuf_release(&sb);
604
605 return success;
606}
607
608static ssize_t find_beginning_of_line(const char* contents, size_t size,
609 size_t offset_, int* found_bracket)
610{
611 size_t equal_offset = size, bracket_offset = size;
612 ssize_t offset;
613
614contline:
615 for (offset = offset_-2; offset > 0
616 && contents[offset] != '\n'; offset--)
617 switch (contents[offset]) {
618 case '=': equal_offset = offset; break;
619 case ']': bracket_offset = offset; break;
620 }
621 if (offset > 0 && contents[offset-1] == '\\') {
622 offset_ = offset;
623 goto contline;
624 }
625 if (bracket_offset < equal_offset) {
626 *found_bracket = 1;
627 offset = bracket_offset+1;
628 } else
629 offset++;
630
631 return offset;
632}
633
634int perf_config_set(const char* key, const char* value)
635{
636 return perf_config_set_multivar(key, value, NULL, 0);
637}
638
639/*
640 * If value==NULL, unset in (remove from) config,
641 * if value_regex!=NULL, disregard key/value pairs where value does not match.
642 * if multi_replace==0, nothing, or only one matching key/value is replaced,
643 * else all matching key/values (regardless how many) are removed,
644 * before the new pair is written.
645 *
646 * Returns 0 on success.
647 *
648 * This function does this:
649 *
650 * - it locks the config file by creating ".perf/config.lock"
651 *
652 * - it then parses the config using store_aux() as validator to find
653 * the position on the key/value pair to replace. If it is to be unset,
654 * it must be found exactly once.
655 *
656 * - the config file is mmap()ed and the part before the match (if any) is
657 * written to the lock file, then the changed part and the rest.
658 *
659 * - the config file is removed and the lock file rename()d to it.
660 *
661 */
662int perf_config_set_multivar(const char* key, const char* value,
663 const char* value_regex, int multi_replace)
664{
665 int i, dot;
666 int fd = -1, in_fd;
667 int ret = 0;
668 char* config_filename;
669 const char* last_dot = strrchr(key, '.');
670
671 if (config_exclusive_filename)
672 config_filename = strdup(config_exclusive_filename);
673 else
674 config_filename = perf_pathdup("config");
675
676 /*
677 * Since "key" actually contains the section name and the real
678 * key name separated by a dot, we have to know where the dot is.
679 */
680
681 if (last_dot == NULL) {
682 error("key does not contain a section: %s", key);
683 ret = 2;
684 goto out_free;
685 }
686 store.baselen = last_dot - key;
687
688 store.multi_replace = multi_replace;
689
690 /*
691 * Validate the key and while at it, lower case it for matching.
692 */
693 store.key = malloc(strlen(key) + 1);
694 dot = 0;
695 for (i = 0; key[i]; i++) {
696 unsigned char c = key[i];
697 if (c == '.')
698 dot = 1;
699 /* Leave the extended basename untouched.. */
700 if (!dot || i > store.baselen) {
701 if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
702 error("invalid key: %s", key);
703 free(store.key);
704 ret = 1;
705 goto out_free;
706 }
707 c = tolower(c);
708 } else if (c == '\n') {
709 error("invalid key (newline): %s", key);
710 free(store.key);
711 ret = 1;
712 goto out_free;
713 }
714 store.key[i] = c;
715 }
716 store.key[i] = 0;
717
718 /*
719 * If .perf/config does not exist yet, write a minimal version.
720 */
721 in_fd = open(config_filename, O_RDONLY);
722 if ( in_fd < 0 ) {
723 free(store.key);
724
725 if ( ENOENT != errno ) {
726 error("opening %s: %s", config_filename,
727 strerror(errno));
728 ret = 3; /* same as "invalid config file" */
729 goto out_free;
730 }
731 /* if nothing to unset, error out */
732 if (value == NULL) {
733 ret = 5;
734 goto out_free;
735 }
736
737 store.key = (char*)key;
738 if (!store_write_section(fd, key) ||
739 !store_write_pair(fd, key, value))
740 goto write_err_out;
741 } else {
742 struct stat st;
743 char* contents;
744 size_t contents_sz, copy_begin, copy_end;
745 int i, new_line = 0;
746
747 if (value_regex == NULL)
748 store.value_regex = NULL;
749 else {
750 if (value_regex[0] == '!') {
751 store.do_not_match = 1;
752 value_regex++;
753 } else
754 store.do_not_match = 0;
755
756 store.value_regex = (regex_t*)malloc(sizeof(regex_t));
757 if (regcomp(store.value_regex, value_regex,
758 REG_EXTENDED)) {
759 error("invalid pattern: %s", value_regex);
760 free(store.value_regex);
761 ret = 6;
762 goto out_free;
763 }
764 }
765
766 store.offset[0] = 0;
767 store.state = START;
768 store.seen = 0;
769
770 /*
771 * After this, store.offset will contain the *end* offset
772 * of the last match, or remain at 0 if no match was found.
773 * As a side effect, we make sure to transform only a valid
774 * existing config file.
775 */
776 if (perf_config_from_file(store_aux, config_filename, NULL)) {
777 error("invalid config file %s", config_filename);
778 free(store.key);
779 if (store.value_regex != NULL) {
780 regfree(store.value_regex);
781 free(store.value_regex);
782 }
783 ret = 3;
784 goto out_free;
785 }
786
787 free(store.key);
788 if (store.value_regex != NULL) {
789 regfree(store.value_regex);
790 free(store.value_regex);
791 }
792
793 /* if nothing to unset, or too many matches, error out */
794 if ((store.seen == 0 && value == NULL) ||
795 (store.seen > 1 && multi_replace == 0)) {
796 ret = 5;
797 goto out_free;
798 }
799
800 fstat(in_fd, &st);
801 contents_sz = xsize_t(st.st_size);
802 contents = mmap(NULL, contents_sz, PROT_READ,
803 MAP_PRIVATE, in_fd, 0);
804 close(in_fd);
805
806 if (store.seen == 0)
807 store.seen = 1;
808
809 for (i = 0, copy_begin = 0; i < store.seen; i++) {
810 if (store.offset[i] == 0) {
811 store.offset[i] = copy_end = contents_sz;
812 } else if (store.state != KEY_SEEN) {
813 copy_end = store.offset[i];
814 } else
815 copy_end = find_beginning_of_line(
816 contents, contents_sz,
817 store.offset[i]-2, &new_line);
818
819 if (copy_end > 0 && contents[copy_end-1] != '\n')
820 new_line = 1;
821
822 /* write the first part of the config */
823 if (copy_end > copy_begin) {
824 if (write_in_full(fd, contents + copy_begin,
825 copy_end - copy_begin) <
826 copy_end - copy_begin)
827 goto write_err_out;
828 if (new_line &&
829 write_in_full(fd, "\n", 1) != 1)
830 goto write_err_out;
831 }
832 copy_begin = store.offset[i];
833 }
834
835 /* write the pair (value == NULL means unset) */
836 if (value != NULL) {
837 if (store.state == START) {
838 if (!store_write_section(fd, key))
839 goto write_err_out;
840 }
841 if (!store_write_pair(fd, key, value))
842 goto write_err_out;
843 }
844
845 /* write the rest of the config */
846 if (copy_begin < contents_sz)
847 if (write_in_full(fd, contents + copy_begin,
848 contents_sz - copy_begin) <
849 contents_sz - copy_begin)
850 goto write_err_out;
851
852 munmap(contents, contents_sz);
853 }
854
855 ret = 0;
856
857out_free:
858 free(config_filename);
859 return ret;
860
861write_err_out:
862 goto out_free;
863
864}
865
866/*
867 * Call this to report error for your variable that should not
868 * get a boolean value (i.e. "[my] var" means "true").
869 */
870int config_error_nonbool(const char *var)
871{
872 return error("Missing value for '%s'", var);
873}
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..d39292263153
--- /dev/null
+++ b/tools/perf/util/exec_cmd.c
@@ -0,0 +1,165 @@
1#include "cache.h"
2#include "exec_cmd.h"
3#include "quote.h"
4#define MAX_ARGS 32
5
6extern char **environ;
7static const char *argv_exec_path;
8static const char *argv0_path;
9
10const char *system_path(const char *path)
11{
12#ifdef RUNTIME_PREFIX
13 static const char *prefix;
14#else
15 static const char *prefix = PREFIX;
16#endif
17 struct strbuf d = STRBUF_INIT;
18
19 if (is_absolute_path(path))
20 return path;
21
22#ifdef RUNTIME_PREFIX
23 assert(argv0_path);
24 assert(is_absolute_path(argv0_path));
25
26 if (!prefix &&
27 !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) &&
28 !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
29 !(prefix = strip_path_suffix(argv0_path, "perf"))) {
30 prefix = PREFIX;
31 fprintf(stderr, "RUNTIME_PREFIX requested, "
32 "but prefix computation failed. "
33 "Using static fallback '%s'.\n", prefix);
34 }
35#endif
36
37 strbuf_addf(&d, "%s/%s", prefix, path);
38 path = strbuf_detach(&d, NULL);
39 return path;
40}
41
42const char *perf_extract_argv0_path(const char *argv0)
43{
44 const char *slash;
45
46 if (!argv0 || !*argv0)
47 return NULL;
48 slash = argv0 + strlen(argv0);
49
50 while (argv0 <= slash && !is_dir_sep(*slash))
51 slash--;
52
53 if (slash >= argv0) {
54 argv0_path = strndup(argv0, slash - argv0);
55 return slash + 1;
56 }
57
58 return argv0;
59}
60
61void perf_set_argv_exec_path(const char *exec_path)
62{
63 argv_exec_path = exec_path;
64 /*
65 * Propagate this setting to external programs.
66 */
67 setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
68}
69
70
71/* Returns the highest-priority, location to look for perf programs. */
72const char *perf_exec_path(void)
73{
74 const char *env;
75
76 if (argv_exec_path)
77 return argv_exec_path;
78
79 env = getenv(EXEC_PATH_ENVIRONMENT);
80 if (env && *env) {
81 return env;
82 }
83
84 return system_path(PERF_EXEC_PATH);
85}
86
87static void add_path(struct strbuf *out, const char *path)
88{
89 if (path && *path) {
90 if (is_absolute_path(path))
91 strbuf_addstr(out, path);
92 else
93 strbuf_addstr(out, make_nonrelative_path(path));
94
95 strbuf_addch(out, PATH_SEP);
96 }
97}
98
99void setup_path(void)
100{
101 const char *old_path = getenv("PATH");
102 struct strbuf new_path = STRBUF_INIT;
103
104 add_path(&new_path, perf_exec_path());
105 add_path(&new_path, argv0_path);
106
107 if (old_path)
108 strbuf_addstr(&new_path, old_path);
109 else
110 strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
111
112 setenv("PATH", new_path.buf, 1);
113
114 strbuf_release(&new_path);
115}
116
117const char **prepare_perf_cmd(const char **argv)
118{
119 int argc;
120 const char **nargv;
121
122 for (argc = 0; argv[argc]; argc++)
123 ; /* just counting */
124 nargv = malloc(sizeof(*nargv) * (argc + 2));
125
126 nargv[0] = "perf";
127 for (argc = 0; argv[argc]; argc++)
128 nargv[argc + 1] = argv[argc];
129 nargv[argc + 1] = NULL;
130 return nargv;
131}
132
133int execv_perf_cmd(const char **argv) {
134 const char **nargv = prepare_perf_cmd(argv);
135
136 /* execvp() can only ever return if it fails */
137 execvp("perf", (char **)nargv);
138
139 free(nargv);
140 return -1;
141}
142
143
144int execl_perf_cmd(const char *cmd,...)
145{
146 int argc;
147 const char *argv[MAX_ARGS + 1];
148 const char *arg;
149 va_list param;
150
151 va_start(param, cmd);
152 argv[0] = cmd;
153 argc = 1;
154 while (argc < MAX_ARGS) {
155 arg = argv[argc++] = va_arg(param, char *);
156 if (!arg)
157 break;
158 }
159 va_end(param);
160 if (MAX_ARGS <= argc)
161 return error("too many args to run %s", cmd);
162
163 argv[argc] = NULL;
164 return execv_perf_cmd(argv);
165}
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/help.c b/tools/perf/util/help.c
new file mode 100644
index 000000000000..6653f7dd1d78
--- /dev/null
+++ b/tools/perf/util/help.c
@@ -0,0 +1,367 @@
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, int 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 int i;
44 for (i = 0; i < cmds->cnt; ++i)
45 free(cmds->names[i]);
46 free(cmds->names);
47 cmds->cnt = 0;
48 cmds->alloc = 0;
49}
50
51static int cmdname_compare(const void *a_, const void *b_)
52{
53 struct cmdname *a = *(struct cmdname **)a_;
54 struct cmdname *b = *(struct cmdname **)b_;
55 return strcmp(a->name, b->name);
56}
57
58static void uniq(struct cmdnames *cmds)
59{
60 int i, j;
61
62 if (!cmds->cnt)
63 return;
64
65 for (i = j = 1; i < cmds->cnt; i++)
66 if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
67 cmds->names[j++] = cmds->names[i];
68
69 cmds->cnt = j;
70}
71
72void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
73{
74 int ci, cj, ei;
75 int cmp;
76
77 ci = cj = ei = 0;
78 while (ci < cmds->cnt && ei < excludes->cnt) {
79 cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
80 if (cmp < 0)
81 cmds->names[cj++] = cmds->names[ci++];
82 else if (cmp == 0)
83 ci++, ei++;
84 else if (cmp > 0)
85 ei++;
86 }
87
88 while (ci < cmds->cnt)
89 cmds->names[cj++] = cmds->names[ci++];
90
91 cmds->cnt = cj;
92}
93
94static void pretty_print_string_list(struct cmdnames *cmds, int longest)
95{
96 int cols = 1, rows;
97 int space = longest + 1; /* min 1 SP between words */
98 int max_cols = term_columns() - 1; /* don't print *on* the edge */
99 int i, j;
100
101 if (space < max_cols)
102 cols = max_cols / space;
103 rows = (cmds->cnt + cols - 1) / cols;
104
105 for (i = 0; i < rows; i++) {
106 printf(" ");
107
108 for (j = 0; j < cols; j++) {
109 int n = j * rows + i;
110 int size = space;
111 if (n >= cmds->cnt)
112 break;
113 if (j == cols-1 || n + rows >= cmds->cnt)
114 size = 1;
115 printf("%-*s", size, cmds->names[n]->name);
116 }
117 putchar('\n');
118 }
119}
120
121static int is_executable(const char *name)
122{
123 struct stat st;
124
125 if (stat(name, &st) || /* stat, not lstat */
126 !S_ISREG(st.st_mode))
127 return 0;
128
129#ifdef __MINGW32__
130 /* cannot trust the executable bit, peek into the file instead */
131 char buf[3] = { 0 };
132 int n;
133 int fd = open(name, O_RDONLY);
134 st.st_mode &= ~S_IXUSR;
135 if (fd >= 0) {
136 n = read(fd, buf, 2);
137 if (n == 2)
138 /* DOS executables start with "MZ" */
139 if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
140 st.st_mode |= S_IXUSR;
141 close(fd);
142 }
143#endif
144 return st.st_mode & S_IXUSR;
145}
146
147static void list_commands_in_dir(struct cmdnames *cmds,
148 const char *path,
149 const char *prefix)
150{
151 int prefix_len;
152 DIR *dir = opendir(path);
153 struct dirent *de;
154 struct strbuf buf = STRBUF_INIT;
155 int len;
156
157 if (!dir)
158 return;
159 if (!prefix)
160 prefix = "perf-";
161 prefix_len = strlen(prefix);
162
163 strbuf_addf(&buf, "%s/", path);
164 len = buf.len;
165
166 while ((de = readdir(dir)) != NULL) {
167 int entlen;
168
169 if (prefixcmp(de->d_name, prefix))
170 continue;
171
172 strbuf_setlen(&buf, len);
173 strbuf_addstr(&buf, de->d_name);
174 if (!is_executable(buf.buf))
175 continue;
176
177 entlen = strlen(de->d_name) - prefix_len;
178 if (has_extension(de->d_name, ".exe"))
179 entlen -= 4;
180
181 add_cmdname(cmds, de->d_name + prefix_len, entlen);
182 }
183 closedir(dir);
184 strbuf_release(&buf);
185}
186
187void load_command_list(const char *prefix,
188 struct cmdnames *main_cmds,
189 struct cmdnames *other_cmds)
190{
191 const char *env_path = getenv("PATH");
192 const char *exec_path = perf_exec_path();
193
194 if (exec_path) {
195 list_commands_in_dir(main_cmds, exec_path, prefix);
196 qsort(main_cmds->names, main_cmds->cnt,
197 sizeof(*main_cmds->names), cmdname_compare);
198 uniq(main_cmds);
199 }
200
201 if (env_path) {
202 char *paths, *path, *colon;
203 path = paths = strdup(env_path);
204 while (1) {
205 if ((colon = strchr(path, PATH_SEP)))
206 *colon = 0;
207 if (!exec_path || strcmp(path, exec_path))
208 list_commands_in_dir(other_cmds, path, prefix);
209
210 if (!colon)
211 break;
212 path = colon + 1;
213 }
214 free(paths);
215
216 qsort(other_cmds->names, other_cmds->cnt,
217 sizeof(*other_cmds->names), cmdname_compare);
218 uniq(other_cmds);
219 }
220 exclude_cmds(other_cmds, main_cmds);
221}
222
223void list_commands(const char *title, struct cmdnames *main_cmds,
224 struct cmdnames *other_cmds)
225{
226 int i, longest = 0;
227
228 for (i = 0; i < main_cmds->cnt; i++)
229 if (longest < main_cmds->names[i]->len)
230 longest = main_cmds->names[i]->len;
231 for (i = 0; i < other_cmds->cnt; i++)
232 if (longest < other_cmds->names[i]->len)
233 longest = other_cmds->names[i]->len;
234
235 if (main_cmds->cnt) {
236 const char *exec_path = perf_exec_path();
237 printf("available %s in '%s'\n", title, exec_path);
238 printf("----------------");
239 mput_char('-', strlen(title) + strlen(exec_path));
240 putchar('\n');
241 pretty_print_string_list(main_cmds, longest);
242 putchar('\n');
243 }
244
245 if (other_cmds->cnt) {
246 printf("%s available from elsewhere on your $PATH\n", title);
247 printf("---------------------------------------");
248 mput_char('-', strlen(title));
249 putchar('\n');
250 pretty_print_string_list(other_cmds, longest);
251 putchar('\n');
252 }
253}
254
255int is_in_cmdlist(struct cmdnames *c, const char *s)
256{
257 int i;
258 for (i = 0; i < c->cnt; i++)
259 if (!strcmp(s, c->names[i]->name))
260 return 1;
261 return 0;
262}
263
264static int autocorrect;
265static struct cmdnames aliases;
266
267static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
268{
269 if (!strcmp(var, "help.autocorrect"))
270 autocorrect = perf_config_int(var,value);
271 /* Also use aliases for command lookup */
272 if (!prefixcmp(var, "alias."))
273 add_cmdname(&aliases, var + 6, strlen(var + 6));
274
275 return perf_default_config(var, value, cb);
276}
277
278static int levenshtein_compare(const void *p1, const void *p2)
279{
280 const struct cmdname *const *c1 = p1, *const *c2 = p2;
281 const char *s1 = (*c1)->name, *s2 = (*c2)->name;
282 int l1 = (*c1)->len;
283 int l2 = (*c2)->len;
284 return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
285}
286
287static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
288{
289 int i;
290 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
291
292 for (i = 0; i < old->cnt; i++)
293 cmds->names[cmds->cnt++] = old->names[i];
294 free(old->names);
295 old->cnt = 0;
296 old->names = NULL;
297}
298
299const char *help_unknown_cmd(const char *cmd)
300{
301 int i, n = 0, best_similarity = 0;
302 struct cmdnames main_cmds, other_cmds;
303
304 memset(&main_cmds, 0, sizeof(main_cmds));
305 memset(&other_cmds, 0, sizeof(main_cmds));
306 memset(&aliases, 0, sizeof(aliases));
307
308 perf_config(perf_unknown_cmd_config, NULL);
309
310 load_command_list("perf-", &main_cmds, &other_cmds);
311
312 add_cmd_list(&main_cmds, &aliases);
313 add_cmd_list(&main_cmds, &other_cmds);
314 qsort(main_cmds.names, main_cmds.cnt,
315 sizeof(main_cmds.names), cmdname_compare);
316 uniq(&main_cmds);
317
318 if (main_cmds.cnt) {
319 /* This reuses cmdname->len for similarity index */
320 for (i = 0; i < main_cmds.cnt; ++i)
321 main_cmds.names[i]->len =
322 levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
323
324 qsort(main_cmds.names, main_cmds.cnt,
325 sizeof(*main_cmds.names), levenshtein_compare);
326
327 best_similarity = main_cmds.names[0]->len;
328 n = 1;
329 while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
330 ++n;
331 }
332
333 if (autocorrect && n == 1) {
334 const char *assumed = main_cmds.names[0]->name;
335
336 main_cmds.names[0] = NULL;
337 clean_cmdnames(&main_cmds);
338 fprintf(stderr, "WARNING: You called a Git program named '%s', "
339 "which does not exist.\n"
340 "Continuing under the assumption that you meant '%s'\n",
341 cmd, assumed);
342 if (autocorrect > 0) {
343 fprintf(stderr, "in %0.1f seconds automatically...\n",
344 (float)autocorrect/10.0);
345 poll(NULL, 0, autocorrect * 100);
346 }
347 return assumed;
348 }
349
350 fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
351
352 if (main_cmds.cnt && best_similarity < 6) {
353 fprintf(stderr, "\nDid you mean %s?\n",
354 n < 2 ? "this": "one of these");
355
356 for (i = 0; i < n; i++)
357 fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
358 }
359
360 exit(1);
361}
362
363int cmd_version(int argc, const char **argv, const char *prefix)
364{
365 printf("perf version %s\n", perf_version_string);
366 return 0;
367}
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
new file mode 100644
index 000000000000..56bc15406ffc
--- /dev/null
+++ b/tools/perf/util/help.h
@@ -0,0 +1,29 @@
1#ifndef HELP_H
2#define HELP_H
3
4struct cmdnames {
5 int alloc;
6 int 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, int 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/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/list.h b/tools/perf/util/list.h
new file mode 100644
index 000000000000..e2548e8072cf
--- /dev/null
+++ b/tools/perf/util/list.h
@@ -0,0 +1,603 @@
1#ifndef _LINUX_LIST_H
2#define _LINUX_LIST_H
3/*
4 Copyright (C) Cast of dozens, comes from the Linux kernel
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of version 2 of the GNU General Public License as
8 published by the Free Software Foundation.
9*/
10
11#include <stddef.h>
12
13/*
14 * These are non-NULL pointers that will result in page faults
15 * under normal circumstances, used to verify that nobody uses
16 * non-initialized list entries.
17 */
18#define LIST_POISON1 ((void *)0x00100100)
19#define LIST_POISON2 ((void *)0x00200200)
20
21/**
22 * container_of - cast a member of a structure out to the containing structure
23 * @ptr: the pointer to the member.
24 * @type: the type of the container struct this is embedded in.
25 * @member: the name of the member within the struct.
26 *
27 */
28#define container_of(ptr, type, member) ({ \
29 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
30 (type *)( (char *)__mptr - offsetof(type,member) );})
31
32/*
33 * Simple doubly linked list implementation.
34 *
35 * Some of the internal functions ("__xxx") are useful when
36 * manipulating whole lists rather than single entries, as
37 * sometimes we already know the next/prev entries and we can
38 * generate better code by using them directly rather than
39 * using the generic single-entry routines.
40 */
41
42struct list_head {
43 struct list_head *next, *prev;
44};
45
46#define LIST_HEAD_INIT(name) { &(name), &(name) }
47
48#define LIST_HEAD(name) \
49 struct list_head name = LIST_HEAD_INIT(name)
50
51static inline void INIT_LIST_HEAD(struct list_head *list)
52{
53 list->next = list;
54 list->prev = list;
55}
56
57/*
58 * Insert a new entry between two known consecutive entries.
59 *
60 * This is only for internal list manipulation where we know
61 * the prev/next entries already!
62 */
63static inline void __list_add(struct list_head *new,
64 struct list_head *prev,
65 struct list_head *next)
66{
67 next->prev = new;
68 new->next = next;
69 new->prev = prev;
70 prev->next = new;
71}
72
73/**
74 * list_add - add a new entry
75 * @new: new entry to be added
76 * @head: list head to add it after
77 *
78 * Insert a new entry after the specified head.
79 * This is good for implementing stacks.
80 */
81static inline void list_add(struct list_head *new, struct list_head *head)
82{
83 __list_add(new, head, head->next);
84}
85
86/**
87 * list_add_tail - add a new entry
88 * @new: new entry to be added
89 * @head: list head to add it before
90 *
91 * Insert a new entry before the specified head.
92 * This is useful for implementing queues.
93 */
94static inline void list_add_tail(struct list_head *new, struct list_head *head)
95{
96 __list_add(new, head->prev, head);
97}
98
99/*
100 * Delete a list entry by making the prev/next entries
101 * point to each other.
102 *
103 * This is only for internal list manipulation where we know
104 * the prev/next entries already!
105 */
106static inline void __list_del(struct list_head * prev, struct list_head * next)
107{
108 next->prev = prev;
109 prev->next = next;
110}
111
112/**
113 * list_del - deletes entry from list.
114 * @entry: the element to delete from the list.
115 * Note: list_empty on entry does not return true after this, the entry is
116 * in an undefined state.
117 */
118static inline void list_del(struct list_head *entry)
119{
120 __list_del(entry->prev, entry->next);
121 entry->next = LIST_POISON1;
122 entry->prev = LIST_POISON2;
123}
124
125/**
126 * list_del_range - deletes range of entries from list.
127 * @beging: first element in the range to delete from the list.
128 * @beging: first element in the range to delete from the list.
129 * Note: list_empty on the range of entries does not return true after this,
130 * the entries is in an undefined state.
131 */
132static inline void list_del_range(struct list_head *begin,
133 struct list_head *end)
134{
135 begin->prev->next = end->next;
136 end->next->prev = begin->prev;
137}
138
139/**
140 * list_replace - replace old entry by new one
141 * @old : the element to be replaced
142 * @new : the new element to insert
143 * Note: if 'old' was empty, it will be overwritten.
144 */
145static inline void list_replace(struct list_head *old,
146 struct list_head *new)
147{
148 new->next = old->next;
149 new->next->prev = new;
150 new->prev = old->prev;
151 new->prev->next = new;
152}
153
154static inline void list_replace_init(struct list_head *old,
155 struct list_head *new)
156{
157 list_replace(old, new);
158 INIT_LIST_HEAD(old);
159}
160
161/**
162 * list_del_init - deletes entry from list and reinitialize it.
163 * @entry: the element to delete from the list.
164 */
165static inline void list_del_init(struct list_head *entry)
166{
167 __list_del(entry->prev, entry->next);
168 INIT_LIST_HEAD(entry);
169}
170
171/**
172 * list_move - delete from one list and add as another's head
173 * @list: the entry to move
174 * @head: the head that will precede our entry
175 */
176static inline void list_move(struct list_head *list, struct list_head *head)
177{
178 __list_del(list->prev, list->next);
179 list_add(list, head);
180}
181
182/**
183 * list_move_tail - delete from one list and add as another's tail
184 * @list: the entry to move
185 * @head: the head that will follow our entry
186 */
187static inline void list_move_tail(struct list_head *list,
188 struct list_head *head)
189{
190 __list_del(list->prev, list->next);
191 list_add_tail(list, head);
192}
193
194/**
195 * list_is_last - tests whether @list is the last entry in list @head
196 * @list: the entry to test
197 * @head: the head of the list
198 */
199static inline int list_is_last(const struct list_head *list,
200 const struct list_head *head)
201{
202 return list->next == head;
203}
204
205/**
206 * list_empty - tests whether a list is empty
207 * @head: the list to test.
208 */
209static inline int list_empty(const struct list_head *head)
210{
211 return head->next == head;
212}
213
214/**
215 * list_empty_careful - tests whether a list is empty and not being modified
216 * @head: the list to test
217 *
218 * Description:
219 * tests whether a list is empty _and_ checks that no other CPU might be
220 * in the process of modifying either member (next or prev)
221 *
222 * NOTE: using list_empty_careful() without synchronization
223 * can only be safe if the only activity that can happen
224 * to the list entry is list_del_init(). Eg. it cannot be used
225 * if another CPU could re-list_add() it.
226 */
227static inline int list_empty_careful(const struct list_head *head)
228{
229 struct list_head *next = head->next;
230 return (next == head) && (next == head->prev);
231}
232
233static inline void __list_splice(struct list_head *list,
234 struct list_head *head)
235{
236 struct list_head *first = list->next;
237 struct list_head *last = list->prev;
238 struct list_head *at = head->next;
239
240 first->prev = head;
241 head->next = first;
242
243 last->next = at;
244 at->prev = last;
245}
246
247/**
248 * list_splice - join two lists
249 * @list: the new list to add.
250 * @head: the place to add it in the first list.
251 */
252static inline void list_splice(struct list_head *list, struct list_head *head)
253{
254 if (!list_empty(list))
255 __list_splice(list, head);
256}
257
258/**
259 * list_splice_init - join two lists and reinitialise the emptied list.
260 * @list: the new list to add.
261 * @head: the place to add it in the first list.
262 *
263 * The list at @list is reinitialised
264 */
265static inline void list_splice_init(struct list_head *list,
266 struct list_head *head)
267{
268 if (!list_empty(list)) {
269 __list_splice(list, head);
270 INIT_LIST_HEAD(list);
271 }
272}
273
274/**
275 * list_entry - get the struct for this entry
276 * @ptr: the &struct list_head pointer.
277 * @type: the type of the struct this is embedded in.
278 * @member: the name of the list_struct within the struct.
279 */
280#define list_entry(ptr, type, member) \
281 container_of(ptr, type, member)
282
283/**
284 * list_first_entry - get the first element from a list
285 * @ptr: the list head to take the element from.
286 * @type: the type of the struct this is embedded in.
287 * @member: the name of the list_struct within the struct.
288 *
289 * Note, that list is expected to be not empty.
290 */
291#define list_first_entry(ptr, type, member) \
292 list_entry((ptr)->next, type, member)
293
294/**
295 * list_for_each - iterate over a list
296 * @pos: the &struct list_head to use as a loop cursor.
297 * @head: the head for your list.
298 */
299#define list_for_each(pos, head) \
300 for (pos = (head)->next; pos != (head); \
301 pos = pos->next)
302
303/**
304 * __list_for_each - iterate over a list
305 * @pos: the &struct list_head to use as a loop cursor.
306 * @head: the head for your list.
307 *
308 * This variant differs from list_for_each() in that it's the
309 * simplest possible list iteration code, no prefetching is done.
310 * Use this for code that knows the list to be very short (empty
311 * or 1 entry) most of the time.
312 */
313#define __list_for_each(pos, head) \
314 for (pos = (head)->next; pos != (head); pos = pos->next)
315
316/**
317 * list_for_each_prev - iterate over a list backwards
318 * @pos: the &struct list_head to use as a loop cursor.
319 * @head: the head for your list.
320 */
321#define list_for_each_prev(pos, head) \
322 for (pos = (head)->prev; pos != (head); \
323 pos = pos->prev)
324
325/**
326 * list_for_each_safe - iterate over a list safe against removal of list entry
327 * @pos: the &struct list_head to use as a loop cursor.
328 * @n: another &struct list_head to use as temporary storage
329 * @head: the head for your list.
330 */
331#define list_for_each_safe(pos, n, head) \
332 for (pos = (head)->next, n = pos->next; pos != (head); \
333 pos = n, n = pos->next)
334
335/**
336 * list_for_each_entry - iterate over list of given type
337 * @pos: the type * to use as a loop cursor.
338 * @head: the head for your list.
339 * @member: the name of the list_struct within the struct.
340 */
341#define list_for_each_entry(pos, head, member) \
342 for (pos = list_entry((head)->next, typeof(*pos), member); \
343 &pos->member != (head); \
344 pos = list_entry(pos->member.next, typeof(*pos), member))
345
346/**
347 * list_for_each_entry_reverse - iterate backwards over list of given type.
348 * @pos: the type * to use as a loop cursor.
349 * @head: the head for your list.
350 * @member: the name of the list_struct within the struct.
351 */
352#define list_for_each_entry_reverse(pos, head, member) \
353 for (pos = list_entry((head)->prev, typeof(*pos), member); \
354 &pos->member != (head); \
355 pos = list_entry(pos->member.prev, typeof(*pos), member))
356
357/**
358 * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
359 * @pos: the type * to use as a start point
360 * @head: the head of the list
361 * @member: the name of the list_struct within the struct.
362 *
363 * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
364 */
365#define list_prepare_entry(pos, head, member) \
366 ((pos) ? : list_entry(head, typeof(*pos), member))
367
368/**
369 * list_for_each_entry_continue - continue iteration over list of given type
370 * @pos: the type * to use as a loop cursor.
371 * @head: the head for your list.
372 * @member: the name of the list_struct within the struct.
373 *
374 * Continue to iterate over list of given type, continuing after
375 * the current position.
376 */
377#define list_for_each_entry_continue(pos, head, member) \
378 for (pos = list_entry(pos->member.next, typeof(*pos), member); \
379 &pos->member != (head); \
380 pos = list_entry(pos->member.next, typeof(*pos), member))
381
382/**
383 * list_for_each_entry_from - iterate over list of given type from the current point
384 * @pos: the type * to use as a loop cursor.
385 * @head: the head for your list.
386 * @member: the name of the list_struct within the struct.
387 *
388 * Iterate over list of given type, continuing from current position.
389 */
390#define list_for_each_entry_from(pos, head, member) \
391 for (; &pos->member != (head); \
392 pos = list_entry(pos->member.next, typeof(*pos), member))
393
394/**
395 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
396 * @pos: the type * to use as a loop cursor.
397 * @n: another type * to use as temporary storage
398 * @head: the head for your list.
399 * @member: the name of the list_struct within the struct.
400 */
401#define list_for_each_entry_safe(pos, n, head, member) \
402 for (pos = list_entry((head)->next, typeof(*pos), member), \
403 n = list_entry(pos->member.next, typeof(*pos), member); \
404 &pos->member != (head); \
405 pos = n, n = list_entry(n->member.next, typeof(*n), member))
406
407/**
408 * list_for_each_entry_safe_continue
409 * @pos: the type * to use as a loop cursor.
410 * @n: another type * to use as temporary storage
411 * @head: the head for your list.
412 * @member: the name of the list_struct within the struct.
413 *
414 * Iterate over list of given type, continuing after current point,
415 * safe against removal of list entry.
416 */
417#define list_for_each_entry_safe_continue(pos, n, head, member) \
418 for (pos = list_entry(pos->member.next, typeof(*pos), member), \
419 n = list_entry(pos->member.next, typeof(*pos), member); \
420 &pos->member != (head); \
421 pos = n, n = list_entry(n->member.next, typeof(*n), member))
422
423/**
424 * list_for_each_entry_safe_from
425 * @pos: the type * to use as a loop cursor.
426 * @n: another type * to use as temporary storage
427 * @head: the head for your list.
428 * @member: the name of the list_struct within the struct.
429 *
430 * Iterate over list of given type from current point, safe against
431 * removal of list entry.
432 */
433#define list_for_each_entry_safe_from(pos, n, head, member) \
434 for (n = list_entry(pos->member.next, typeof(*pos), member); \
435 &pos->member != (head); \
436 pos = n, n = list_entry(n->member.next, typeof(*n), member))
437
438/**
439 * list_for_each_entry_safe_reverse
440 * @pos: the type * to use as a loop cursor.
441 * @n: another type * to use as temporary storage
442 * @head: the head for your list.
443 * @member: the name of the list_struct within the struct.
444 *
445 * Iterate backwards over list of given type, safe against removal
446 * of list entry.
447 */
448#define list_for_each_entry_safe_reverse(pos, n, head, member) \
449 for (pos = list_entry((head)->prev, typeof(*pos), member), \
450 n = list_entry(pos->member.prev, typeof(*pos), member); \
451 &pos->member != (head); \
452 pos = n, n = list_entry(n->member.prev, typeof(*n), member))
453
454/*
455 * Double linked lists with a single pointer list head.
456 * Mostly useful for hash tables where the two pointer list head is
457 * too wasteful.
458 * You lose the ability to access the tail in O(1).
459 */
460
461struct hlist_head {
462 struct hlist_node *first;
463};
464
465struct hlist_node {
466 struct hlist_node *next, **pprev;
467};
468
469#define HLIST_HEAD_INIT { .first = NULL }
470#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
471#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
472static inline void INIT_HLIST_NODE(struct hlist_node *h)
473{
474 h->next = NULL;
475 h->pprev = NULL;
476}
477
478static inline int hlist_unhashed(const struct hlist_node *h)
479{
480 return !h->pprev;
481}
482
483static inline int hlist_empty(const struct hlist_head *h)
484{
485 return !h->first;
486}
487
488static inline void __hlist_del(struct hlist_node *n)
489{
490 struct hlist_node *next = n->next;
491 struct hlist_node **pprev = n->pprev;
492 *pprev = next;
493 if (next)
494 next->pprev = pprev;
495}
496
497static inline void hlist_del(struct hlist_node *n)
498{
499 __hlist_del(n);
500 n->next = LIST_POISON1;
501 n->pprev = LIST_POISON2;
502}
503
504static inline void hlist_del_init(struct hlist_node *n)
505{
506 if (!hlist_unhashed(n)) {
507 __hlist_del(n);
508 INIT_HLIST_NODE(n);
509 }
510}
511
512static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
513{
514 struct hlist_node *first = h->first;
515 n->next = first;
516 if (first)
517 first->pprev = &n->next;
518 h->first = n;
519 n->pprev = &h->first;
520}
521
522/* next must be != NULL */
523static inline void hlist_add_before(struct hlist_node *n,
524 struct hlist_node *next)
525{
526 n->pprev = next->pprev;
527 n->next = next;
528 next->pprev = &n->next;
529 *(n->pprev) = n;
530}
531
532static inline void hlist_add_after(struct hlist_node *n,
533 struct hlist_node *next)
534{
535 next->next = n->next;
536 n->next = next;
537 next->pprev = &n->next;
538
539 if(next->next)
540 next->next->pprev = &next->next;
541}
542
543#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
544
545#define hlist_for_each(pos, head) \
546 for (pos = (head)->first; pos; \
547 pos = pos->next)
548
549#define hlist_for_each_safe(pos, n, head) \
550 for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
551 pos = n)
552
553/**
554 * hlist_for_each_entry - iterate over list of given type
555 * @tpos: the type * to use as a loop cursor.
556 * @pos: the &struct hlist_node to use as a loop cursor.
557 * @head: the head for your list.
558 * @member: the name of the hlist_node within the struct.
559 */
560#define hlist_for_each_entry(tpos, pos, head, member) \
561 for (pos = (head)->first; \
562 pos && \
563 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
564 pos = pos->next)
565
566/**
567 * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
568 * @tpos: the type * to use as a loop cursor.
569 * @pos: the &struct hlist_node to use as a loop cursor.
570 * @member: the name of the hlist_node within the struct.
571 */
572#define hlist_for_each_entry_continue(tpos, pos, member) \
573 for (pos = (pos)->next; \
574 pos && \
575 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
576 pos = pos->next)
577
578/**
579 * hlist_for_each_entry_from - iterate over a hlist continuing from current point
580 * @tpos: the type * to use as a loop cursor.
581 * @pos: the &struct hlist_node to use as a loop cursor.
582 * @member: the name of the hlist_node within the struct.
583 */
584#define hlist_for_each_entry_from(tpos, pos, member) \
585 for (; pos && \
586 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
587 pos = pos->next)
588
589/**
590 * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
591 * @tpos: the type * to use as a loop cursor.
592 * @pos: the &struct hlist_node to use as a loop cursor.
593 * @n: another &struct hlist_node to use as temporary storage
594 * @head: the head for your list.
595 * @member: the name of the hlist_node within the struct.
596 */
597#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
598 for (pos = (head)->first; \
599 pos && ({ n = pos->next; 1; }) && \
600 ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
601 pos = n)
602
603#endif
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
new file mode 100644
index 000000000000..a28bccae5458
--- /dev/null
+++ b/tools/perf/util/pager.c
@@ -0,0 +1,99 @@
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
12#ifndef __MINGW32__
13static void pager_preexec(void)
14{
15 /*
16 * Work around bug in "less" by not starting it until we
17 * have real input
18 */
19 fd_set in;
20
21 FD_ZERO(&in);
22 FD_SET(0, &in);
23 select(1, &in, NULL, &in, NULL);
24
25 setenv("LESS", "FRSX", 0);
26}
27#endif
28
29static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
30static struct child_process pager_process;
31
32static void wait_for_pager(void)
33{
34 fflush(stdout);
35 fflush(stderr);
36 /* signal EOF to pager */
37 close(1);
38 close(2);
39 finish_command(&pager_process);
40}
41
42static void wait_for_pager_signal(int signo)
43{
44 wait_for_pager();
45 sigchain_pop(signo);
46 raise(signo);
47}
48
49void setup_pager(void)
50{
51 const char *pager = getenv("PERF_PAGER");
52
53 if (!isatty(1))
54 return;
55 if (!pager) {
56 if (!pager_program)
57 perf_config(perf_default_config, NULL);
58 pager = pager_program;
59 }
60 if (!pager)
61 pager = getenv("PAGER");
62 if (!pager)
63 pager = "less";
64 else if (!*pager || !strcmp(pager, "cat"))
65 return;
66
67 spawned_pager = 1; /* means we are emitting to terminal */
68
69 /* spawn the pager */
70 pager_argv[2] = pager;
71 pager_process.argv = pager_argv;
72 pager_process.in = -1;
73#ifndef __MINGW32__
74 pager_process.preexec_cb = pager_preexec;
75#endif
76 if (start_command(&pager_process))
77 return;
78
79 /* original process continues, but writes to the pipe */
80 dup2(pager_process.in, 1);
81 if (isatty(2))
82 dup2(pager_process.in, 2);
83 close(pager_process.in);
84
85 /* this makes sure that the parent terminates after the pager */
86 sigchain_push_common(wait_for_pager_signal);
87 atexit(wait_for_pager);
88}
89
90int pager_in_use(void)
91{
92 const char *env;
93
94 if (spawned_pager)
95 return 1;
96
97 env = getenv("PERF_PAGER_IN_USE");
98 return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
99}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
new file mode 100644
index 000000000000..35d04da38d6a
--- /dev/null
+++ b/tools/perf/util/parse-events.c
@@ -0,0 +1,316 @@
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
9extern char *strcasestr(const char *haystack, const char *needle);
10
11int nr_counters;
12
13struct perf_counter_attr attrs[MAX_COUNTERS];
14
15struct event_symbol {
16 u8 type;
17 u64 config;
18 char *symbol;
19};
20
21#define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y
22#define CR(x, y) .type = PERF_TYPE_##x, .config = y
23
24static struct event_symbol event_symbols[] = {
25 { C(HARDWARE, HW_CPU_CYCLES), "cpu-cycles", },
26 { C(HARDWARE, HW_CPU_CYCLES), "cycles", },
27 { C(HARDWARE, HW_INSTRUCTIONS), "instructions", },
28 { C(HARDWARE, HW_CACHE_REFERENCES), "cache-references", },
29 { C(HARDWARE, HW_CACHE_MISSES), "cache-misses", },
30 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", },
31 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches", },
32 { C(HARDWARE, HW_BRANCH_MISSES), "branch-misses", },
33 { C(HARDWARE, HW_BUS_CYCLES), "bus-cycles", },
34
35 { C(SOFTWARE, SW_CPU_CLOCK), "cpu-clock", },
36 { C(SOFTWARE, SW_TASK_CLOCK), "task-clock", },
37 { C(SOFTWARE, SW_PAGE_FAULTS), "page-faults", },
38 { C(SOFTWARE, SW_PAGE_FAULTS), "faults", },
39 { C(SOFTWARE, SW_PAGE_FAULTS_MIN), "minor-faults", },
40 { C(SOFTWARE, SW_PAGE_FAULTS_MAJ), "major-faults", },
41 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "context-switches", },
42 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "cs", },
43 { C(SOFTWARE, SW_CPU_MIGRATIONS), "cpu-migrations", },
44 { C(SOFTWARE, SW_CPU_MIGRATIONS), "migrations", },
45};
46
47#define __PERF_COUNTER_FIELD(config, name) \
48 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
49
50#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW)
51#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG)
52#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
53#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
54
55static char *hw_event_names[] = {
56 "cycles",
57 "instructions",
58 "cache-references",
59 "cache-misses",
60 "branches",
61 "branch-misses",
62 "bus-cycles",
63};
64
65static char *sw_event_names[] = {
66 "cpu-clock-msecs",
67 "task-clock-msecs",
68 "page-faults",
69 "context-switches",
70 "CPU-migrations",
71 "minor-faults",
72 "major-faults",
73};
74
75#define MAX_ALIASES 8
76
77static char *hw_cache [][MAX_ALIASES] = {
78 { "L1-data" , "l1-d", "l1d" },
79 { "L1-instruction" , "l1-i", "l1i" },
80 { "L2" , "l2" },
81 { "Data-TLB" , "dtlb", "d-tlb" },
82 { "Instruction-TLB" , "itlb", "i-tlb" },
83 { "Branch" , "bpu" , "btb", "bpc" },
84};
85
86static char *hw_cache_op [][MAX_ALIASES] = {
87 { "Load" , "read" },
88 { "Store" , "write" },
89 { "Prefetch" , "speculative-read", "speculative-load" },
90};
91
92static char *hw_cache_result [][MAX_ALIASES] = {
93 { "Reference" , "ops", "access" },
94 { "Miss" },
95};
96
97char *event_name(int counter)
98{
99 u64 config = attrs[counter].config;
100 int type = attrs[counter].type;
101 static char buf[32];
102
103 if (attrs[counter].type == PERF_TYPE_RAW) {
104 sprintf(buf, "raw 0x%llx", config);
105 return buf;
106 }
107
108 switch (type) {
109 case PERF_TYPE_HARDWARE:
110 if (config < PERF_COUNT_HW_MAX)
111 return hw_event_names[config];
112 return "unknown-hardware";
113
114 case PERF_TYPE_HW_CACHE: {
115 u8 cache_type, cache_op, cache_result;
116 static char name[100];
117
118 cache_type = (config >> 0) & 0xff;
119 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
120 return "unknown-ext-hardware-cache-type";
121
122 cache_op = (config >> 8) & 0xff;
123 if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
124 return "unknown-ext-hardware-cache-op";
125
126 cache_result = (config >> 16) & 0xff;
127 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
128 return "unknown-ext-hardware-cache-result";
129
130 sprintf(name, "%s-Cache-%s-%ses",
131 hw_cache[cache_type][0],
132 hw_cache_op[cache_op][0],
133 hw_cache_result[cache_result][0]);
134
135 return name;
136 }
137
138 case PERF_TYPE_SOFTWARE:
139 if (config < PERF_COUNT_SW_MAX)
140 return sw_event_names[config];
141 return "unknown-software";
142
143 default:
144 break;
145 }
146
147 return "unknown";
148}
149
150static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
151{
152 int i, j;
153
154 for (i = 0; i < size; i++) {
155 for (j = 0; j < MAX_ALIASES; j++) {
156 if (!names[i][j])
157 break;
158 if (strcasestr(str, names[i][j]))
159 return i;
160 }
161 }
162
163 return -1;
164}
165
166static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
167{
168 int cache_type = -1, cache_op = 0, cache_result = 0;
169
170 cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX);
171 /*
172 * No fallback - if we cannot get a clear cache type
173 * then bail out:
174 */
175 if (cache_type == -1)
176 return -EINVAL;
177
178 cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
179 /*
180 * Fall back to reads:
181 */
182 if (cache_op == -1)
183 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
184
185 cache_result = parse_aliases(str, hw_cache_result,
186 PERF_COUNT_HW_CACHE_RESULT_MAX);
187 /*
188 * Fall back to accesses:
189 */
190 if (cache_result == -1)
191 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
192
193 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
194 attr->type = PERF_TYPE_HW_CACHE;
195
196 return 0;
197}
198
199/*
200 * Each event can have multiple symbolic names.
201 * Symbolic names are (almost) exactly matched.
202 */
203static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
204{
205 u64 config, id;
206 int type;
207 unsigned int i;
208 const char *sep, *pstr;
209
210 if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
211 attr->type = PERF_TYPE_RAW;
212 attr->config = config;
213
214 return 0;
215 }
216
217 pstr = str;
218 sep = strchr(pstr, ':');
219 if (sep) {
220 type = atoi(pstr);
221 pstr = sep + 1;
222 id = atoi(pstr);
223 sep = strchr(pstr, ':');
224 if (sep) {
225 pstr = sep + 1;
226 if (strchr(pstr, 'k'))
227 attr->exclude_user = 1;
228 if (strchr(pstr, 'u'))
229 attr->exclude_kernel = 1;
230 }
231 attr->type = type;
232 attr->config = id;
233
234 return 0;
235 }
236
237 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
238 if (!strncmp(str, event_symbols[i].symbol,
239 strlen(event_symbols[i].symbol))) {
240
241 attr->type = event_symbols[i].type;
242 attr->config = event_symbols[i].config;
243
244 return 0;
245 }
246 }
247
248 return parse_generic_hw_symbols(str, attr);
249}
250
251int parse_events(const struct option *opt, const char *str, int unset)
252{
253 struct perf_counter_attr attr;
254 int ret;
255
256 memset(&attr, 0, sizeof(attr));
257again:
258 if (nr_counters == MAX_COUNTERS)
259 return -1;
260
261 ret = parse_event_symbols(str, &attr);
262 if (ret < 0)
263 return ret;
264
265 attrs[nr_counters] = attr;
266 nr_counters++;
267
268 str = strstr(str, ",");
269 if (str) {
270 str++;
271 goto again;
272 }
273
274 return 0;
275}
276
277static const char * const event_type_descriptors[] = {
278 "",
279 "Hardware event",
280 "Software event",
281 "Tracepoint event",
282 "Hardware cache event",
283};
284
285/*
286 * Print the help text for the event symbols:
287 */
288void print_events(void)
289{
290 struct event_symbol *syms = event_symbols;
291 unsigned int i, type, prev_type = -1;
292
293 fprintf(stderr, "\n");
294 fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
295
296 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
297 type = syms->type + 1;
298 if (type > ARRAY_SIZE(event_type_descriptors))
299 type = 0;
300
301 if (type != prev_type)
302 fprintf(stderr, "\n");
303
304 fprintf(stderr, " %-30s [%s]\n", syms->symbol,
305 event_type_descriptors[type]);
306
307 prev_type = type;
308 }
309
310 fprintf(stderr, "\n");
311 fprintf(stderr, " %-30s [raw hardware event descriptor]\n",
312 "rNNN");
313 fprintf(stderr, "\n");
314
315 exit(129);
316}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
new file mode 100644
index 000000000000..e3d552908e60
--- /dev/null
+++ b/tools/perf/util/parse-events.h
@@ -0,0 +1,17 @@
1
2/*
3 * Parse symbolic events/counts passed in as options:
4 */
5
6extern int nr_counters;
7
8extern struct perf_counter_attr attrs[MAX_COUNTERS];
9
10extern char *event_name(int ctr);
11
12extern int parse_events(const struct option *opt, const char *str, int unset);
13
14#define EVENTS_HELP_MAX (128*1024)
15
16extern void print_events(void);
17
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
new file mode 100644
index 000000000000..b3affb1658d2
--- /dev/null
+++ b/tools/perf/util/parse-options.c
@@ -0,0 +1,508 @@
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 (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) {
24 *arg = (const char *)opt->defval;
25 } else if (p->argc > 1) {
26 p->argc--;
27 *arg = *++p->argv;
28 } else
29 return opterror(opt, "requires a value", flags);
30 return 0;
31}
32
33static int get_value(struct parse_opt_ctx_t *p,
34 const struct option *opt, int flags)
35{
36 const char *s, *arg = NULL;
37 const int unset = flags & OPT_UNSET;
38
39 if (unset && p->opt)
40 return opterror(opt, "takes no value", flags);
41 if (unset && (opt->flags & PARSE_OPT_NONEG))
42 return opterror(opt, "isn't available", flags);
43
44 if (!(flags & OPT_SHORT) && p->opt) {
45 switch (opt->type) {
46 case OPTION_CALLBACK:
47 if (!(opt->flags & PARSE_OPT_NOARG))
48 break;
49 /* FALLTHROUGH */
50 case OPTION_BOOLEAN:
51 case OPTION_BIT:
52 case OPTION_SET_INT:
53 case OPTION_SET_PTR:
54 return opterror(opt, "takes no value", flags);
55 default:
56 break;
57 }
58 }
59
60 switch (opt->type) {
61 case OPTION_BIT:
62 if (unset)
63 *(int *)opt->value &= ~opt->defval;
64 else
65 *(int *)opt->value |= opt->defval;
66 return 0;
67
68 case OPTION_BOOLEAN:
69 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
70 return 0;
71
72 case OPTION_SET_INT:
73 *(int *)opt->value = unset ? 0 : opt->defval;
74 return 0;
75
76 case OPTION_SET_PTR:
77 *(void **)opt->value = unset ? NULL : (void *)opt->defval;
78 return 0;
79
80 case OPTION_STRING:
81 if (unset)
82 *(const char **)opt->value = NULL;
83 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
84 *(const char **)opt->value = (const char *)opt->defval;
85 else
86 return get_arg(p, opt, flags, (const char **)opt->value);
87 return 0;
88
89 case OPTION_CALLBACK:
90 if (unset)
91 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
92 if (opt->flags & PARSE_OPT_NOARG)
93 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
94 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
95 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
96 if (get_arg(p, opt, flags, &arg))
97 return -1;
98 return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
99
100 case OPTION_INTEGER:
101 if (unset) {
102 *(int *)opt->value = 0;
103 return 0;
104 }
105 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
106 *(int *)opt->value = opt->defval;
107 return 0;
108 }
109 if (get_arg(p, opt, flags, &arg))
110 return -1;
111 *(int *)opt->value = strtol(arg, (char **)&s, 10);
112 if (*s)
113 return opterror(opt, "expects a numerical value", flags);
114 return 0;
115
116 case OPTION_LONG:
117 if (unset) {
118 *(long *)opt->value = 0;
119 return 0;
120 }
121 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
122 *(long *)opt->value = opt->defval;
123 return 0;
124 }
125 if (get_arg(p, opt, flags, &arg))
126 return -1;
127 *(long *)opt->value = strtol(arg, (char **)&s, 10);
128 if (*s)
129 return opterror(opt, "expects a numerical value", flags);
130 return 0;
131
132 default:
133 die("should not happen, someone must be hit on the forehead");
134 }
135}
136
137static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
138{
139 for (; options->type != OPTION_END; options++) {
140 if (options->short_name == *p->opt) {
141 p->opt = p->opt[1] ? p->opt + 1 : NULL;
142 return get_value(p, options, OPT_SHORT);
143 }
144 }
145 return -2;
146}
147
148static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
149 const struct option *options)
150{
151 const char *arg_end = strchr(arg, '=');
152 const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
153 int abbrev_flags = 0, ambiguous_flags = 0;
154
155 if (!arg_end)
156 arg_end = arg + strlen(arg);
157
158 for (; options->type != OPTION_END; options++) {
159 const char *rest;
160 int flags = 0;
161
162 if (!options->long_name)
163 continue;
164
165 rest = skip_prefix(arg, options->long_name);
166 if (options->type == OPTION_ARGUMENT) {
167 if (!rest)
168 continue;
169 if (*rest == '=')
170 return opterror(options, "takes no value", flags);
171 if (*rest)
172 continue;
173 p->out[p->cpidx++] = arg - 2;
174 return 0;
175 }
176 if (!rest) {
177 /* abbreviated? */
178 if (!strncmp(options->long_name, arg, arg_end - arg)) {
179is_abbreviated:
180 if (abbrev_option) {
181 /*
182 * If this is abbreviated, it is
183 * ambiguous. So when there is no
184 * exact match later, we need to
185 * error out.
186 */
187 ambiguous_option = abbrev_option;
188 ambiguous_flags = abbrev_flags;
189 }
190 if (!(flags & OPT_UNSET) && *arg_end)
191 p->opt = arg_end + 1;
192 abbrev_option = options;
193 abbrev_flags = flags;
194 continue;
195 }
196 /* negated and abbreviated very much? */
197 if (!prefixcmp("no-", arg)) {
198 flags |= OPT_UNSET;
199 goto is_abbreviated;
200 }
201 /* negated? */
202 if (strncmp(arg, "no-", 3))
203 continue;
204 flags |= OPT_UNSET;
205 rest = skip_prefix(arg + 3, options->long_name);
206 /* abbreviated and negated? */
207 if (!rest && !prefixcmp(options->long_name, arg + 3))
208 goto is_abbreviated;
209 if (!rest)
210 continue;
211 }
212 if (*rest) {
213 if (*rest != '=')
214 continue;
215 p->opt = rest + 1;
216 }
217 return get_value(p, options, flags);
218 }
219
220 if (ambiguous_option)
221 return error("Ambiguous option: %s "
222 "(could be --%s%s or --%s%s)",
223 arg,
224 (ambiguous_flags & OPT_UNSET) ? "no-" : "",
225 ambiguous_option->long_name,
226 (abbrev_flags & OPT_UNSET) ? "no-" : "",
227 abbrev_option->long_name);
228 if (abbrev_option)
229 return get_value(p, abbrev_option, abbrev_flags);
230 return -2;
231}
232
233static void check_typos(const char *arg, const struct option *options)
234{
235 if (strlen(arg) < 3)
236 return;
237
238 if (!prefixcmp(arg, "no-")) {
239 error ("did you mean `--%s` (with two dashes ?)", arg);
240 exit(129);
241 }
242
243 for (; options->type != OPTION_END; options++) {
244 if (!options->long_name)
245 continue;
246 if (!prefixcmp(options->long_name, arg)) {
247 error ("did you mean `--%s` (with two dashes ?)", arg);
248 exit(129);
249 }
250 }
251}
252
253void parse_options_start(struct parse_opt_ctx_t *ctx,
254 int argc, const char **argv, int flags)
255{
256 memset(ctx, 0, sizeof(*ctx));
257 ctx->argc = argc - 1;
258 ctx->argv = argv + 1;
259 ctx->out = argv;
260 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
261 ctx->flags = flags;
262 if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
263 (flags & PARSE_OPT_STOP_AT_NON_OPTION))
264 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
265}
266
267static int usage_with_options_internal(const char * const *,
268 const struct option *, int);
269
270int parse_options_step(struct parse_opt_ctx_t *ctx,
271 const struct option *options,
272 const char * const usagestr[])
273{
274 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
275
276 /* we must reset ->opt, unknown short option leave it dangling */
277 ctx->opt = NULL;
278
279 for (; ctx->argc; ctx->argc--, ctx->argv++) {
280 const char *arg = ctx->argv[0];
281
282 if (*arg != '-' || !arg[1]) {
283 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
284 break;
285 ctx->out[ctx->cpidx++] = ctx->argv[0];
286 continue;
287 }
288
289 if (arg[1] != '-') {
290 ctx->opt = arg + 1;
291 if (internal_help && *ctx->opt == 'h')
292 return parse_options_usage(usagestr, options);
293 switch (parse_short_opt(ctx, options)) {
294 case -1:
295 return parse_options_usage(usagestr, options);
296 case -2:
297 goto unknown;
298 }
299 if (ctx->opt)
300 check_typos(arg + 1, options);
301 while (ctx->opt) {
302 if (internal_help && *ctx->opt == 'h')
303 return parse_options_usage(usagestr, options);
304 switch (parse_short_opt(ctx, options)) {
305 case -1:
306 return parse_options_usage(usagestr, options);
307 case -2:
308 /* fake a short option thing to hide the fact that we may have
309 * started to parse aggregated stuff
310 *
311 * This is leaky, too bad.
312 */
313 ctx->argv[0] = strdup(ctx->opt - 1);
314 *(char *)ctx->argv[0] = '-';
315 goto unknown;
316 }
317 }
318 continue;
319 }
320
321 if (!arg[2]) { /* "--" */
322 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
323 ctx->argc--;
324 ctx->argv++;
325 }
326 break;
327 }
328
329 if (internal_help && !strcmp(arg + 2, "help-all"))
330 return usage_with_options_internal(usagestr, options, 1);
331 if (internal_help && !strcmp(arg + 2, "help"))
332 return parse_options_usage(usagestr, options);
333 switch (parse_long_opt(ctx, arg + 2, options)) {
334 case -1:
335 return parse_options_usage(usagestr, options);
336 case -2:
337 goto unknown;
338 }
339 continue;
340unknown:
341 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
342 return PARSE_OPT_UNKNOWN;
343 ctx->out[ctx->cpidx++] = ctx->argv[0];
344 ctx->opt = NULL;
345 }
346 return PARSE_OPT_DONE;
347}
348
349int parse_options_end(struct parse_opt_ctx_t *ctx)
350{
351 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
352 ctx->out[ctx->cpidx + ctx->argc] = NULL;
353 return ctx->cpidx + ctx->argc;
354}
355
356int parse_options(int argc, const char **argv, const struct option *options,
357 const char * const usagestr[], int flags)
358{
359 struct parse_opt_ctx_t ctx;
360
361 parse_options_start(&ctx, argc, argv, flags);
362 switch (parse_options_step(&ctx, options, usagestr)) {
363 case PARSE_OPT_HELP:
364 exit(129);
365 case PARSE_OPT_DONE:
366 break;
367 default: /* PARSE_OPT_UNKNOWN */
368 if (ctx.argv[0][1] == '-') {
369 error("unknown option `%s'", ctx.argv[0] + 2);
370 } else {
371 error("unknown switch `%c'", *ctx.opt);
372 }
373 usage_with_options(usagestr, options);
374 }
375
376 return parse_options_end(&ctx);
377}
378
379#define USAGE_OPTS_WIDTH 24
380#define USAGE_GAP 2
381
382int usage_with_options_internal(const char * const *usagestr,
383 const struct option *opts, int full)
384{
385 if (!usagestr)
386 return PARSE_OPT_HELP;
387
388 fprintf(stderr, "\n usage: %s\n", *usagestr++);
389 while (*usagestr && **usagestr)
390 fprintf(stderr, " or: %s\n", *usagestr++);
391 while (*usagestr) {
392 fprintf(stderr, "%s%s\n",
393 **usagestr ? " " : "",
394 *usagestr);
395 usagestr++;
396 }
397
398 if (opts->type != OPTION_GROUP)
399 fputc('\n', stderr);
400
401 for (; opts->type != OPTION_END; opts++) {
402 size_t pos;
403 int pad;
404
405 if (opts->type == OPTION_GROUP) {
406 fputc('\n', stderr);
407 if (*opts->help)
408 fprintf(stderr, "%s\n", opts->help);
409 continue;
410 }
411 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
412 continue;
413
414 pos = fprintf(stderr, " ");
415 if (opts->short_name)
416 pos += fprintf(stderr, "-%c", opts->short_name);
417 if (opts->long_name && opts->short_name)
418 pos += fprintf(stderr, ", ");
419 if (opts->long_name)
420 pos += fprintf(stderr, "--%s", opts->long_name);
421
422 switch (opts->type) {
423 case OPTION_ARGUMENT:
424 break;
425 case OPTION_INTEGER:
426 if (opts->flags & PARSE_OPT_OPTARG)
427 if (opts->long_name)
428 pos += fprintf(stderr, "[=<n>]");
429 else
430 pos += fprintf(stderr, "[<n>]");
431 else
432 pos += fprintf(stderr, " <n>");
433 break;
434 case OPTION_CALLBACK:
435 if (opts->flags & PARSE_OPT_NOARG)
436 break;
437 /* FALLTHROUGH */
438 case OPTION_STRING:
439 if (opts->argh) {
440 if (opts->flags & PARSE_OPT_OPTARG)
441 if (opts->long_name)
442 pos += fprintf(stderr, "[=<%s>]", opts->argh);
443 else
444 pos += fprintf(stderr, "[<%s>]", opts->argh);
445 else
446 pos += fprintf(stderr, " <%s>", opts->argh);
447 } else {
448 if (opts->flags & PARSE_OPT_OPTARG)
449 if (opts->long_name)
450 pos += fprintf(stderr, "[=...]");
451 else
452 pos += fprintf(stderr, "[...]");
453 else
454 pos += fprintf(stderr, " ...");
455 }
456 break;
457 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
458 break;
459 }
460
461 if (pos <= USAGE_OPTS_WIDTH)
462 pad = USAGE_OPTS_WIDTH - pos;
463 else {
464 fputc('\n', stderr);
465 pad = USAGE_OPTS_WIDTH;
466 }
467 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
468 }
469 fputc('\n', stderr);
470
471 return PARSE_OPT_HELP;
472}
473
474void usage_with_options(const char * const *usagestr,
475 const struct option *opts)
476{
477 usage_with_options_internal(usagestr, opts, 0);
478 exit(129);
479}
480
481int parse_options_usage(const char * const *usagestr,
482 const struct option *opts)
483{
484 return usage_with_options_internal(usagestr, opts, 0);
485}
486
487
488int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
489 int unset)
490{
491 int *target = opt->value;
492
493 if (unset)
494 /* --no-quiet, --no-verbose */
495 *target = 0;
496 else if (opt->short_name == 'v') {
497 if (*target >= 0)
498 (*target)++;
499 else
500 *target = 1;
501 } else {
502 if (*target <= 0)
503 (*target)--;
504 else
505 *target = -1;
506 }
507 return 0;
508}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
new file mode 100644
index 000000000000..a1039a6ce0eb
--- /dev/null
+++ b/tools/perf/util/parse-options.h
@@ -0,0 +1,174 @@
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() { OPTION_END }
94#define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) }
95#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
96#define OPT_BIT(s, l, v, h, b) { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
97#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
98#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) }
99#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) }
100#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
101#define OPT_LONG(s, l, v, h) { OPTION_LONG, (s), (l), (v), NULL, (h) }
102#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
103#define OPT_DATE(s, l, v, h) \
104 { OPTION_CALLBACK, (s), (l), (v), "time",(h), 0, \
105 parse_opt_approxidate_cb }
106#define OPT_CALLBACK(s, l, v, a, h, f) \
107 { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
108
109/* parse_options() will filter out the processed options and leave the
110 * non-option argments in argv[].
111 * Returns the number of arguments left in argv[].
112 */
113extern int parse_options(int argc, const char **argv,
114 const struct option *options,
115 const char * const usagestr[], int flags);
116
117extern NORETURN void usage_with_options(const char * const *usagestr,
118 const struct option *options);
119
120/*----- incremantal advanced APIs -----*/
121
122enum {
123 PARSE_OPT_HELP = -1,
124 PARSE_OPT_DONE,
125 PARSE_OPT_UNKNOWN,
126};
127
128/*
129 * It's okay for the caller to consume argv/argc in the usual way.
130 * Other fields of that structure are private to parse-options and should not
131 * be modified in any way.
132 */
133struct parse_opt_ctx_t {
134 const char **argv;
135 const char **out;
136 int argc, cpidx;
137 const char *opt;
138 int flags;
139};
140
141extern int parse_options_usage(const char * const *usagestr,
142 const struct option *opts);
143
144extern void parse_options_start(struct parse_opt_ctx_t *ctx,
145 int argc, const char **argv, int flags);
146
147extern int parse_options_step(struct parse_opt_ctx_t *ctx,
148 const struct option *options,
149 const char * const usagestr[]);
150
151extern int parse_options_end(struct parse_opt_ctx_t *ctx);
152
153
154/*----- some often used options -----*/
155extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
156extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
157extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
158
159#define OPT__VERBOSE(var) OPT_BOOLEAN('v', "verbose", (var), "be verbose")
160#define OPT__QUIET(var) OPT_BOOLEAN('q', "quiet", (var), "be quiet")
161#define OPT__VERBOSITY(var) \
162 { OPTION_CALLBACK, 'v', "verbose", (var), NULL, "be more verbose", \
163 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
164 { OPTION_CALLBACK, 'q', "quiet", (var), NULL, "be more quiet", \
165 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
166#define OPT__DRY_RUN(var) OPT_BOOLEAN('n', "dry-run", (var), "dry run")
167#define OPT__ABBREV(var) \
168 { OPTION_CALLBACK, 0, "abbrev", (var), "n", \
169 "use <n> digits to display SHA-1s", \
170 PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
171
172extern const char *parse_options_fix_filename(const char *prefix, const char *file);
173
174#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..f18c5212bc92
--- /dev/null
+++ b/tools/perf/util/quote.c
@@ -0,0 +1,481 @@
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/* returns the longest prefix not needing a quote up to maxlen if positive.
166 This stops at the first \0 because it's marked as a character needing an
167 escape */
168static size_t next_quote_pos(const char *s, ssize_t maxlen)
169{
170 size_t len;
171 if (maxlen < 0) {
172 for (len = 0; !sq_must_quote(s[len]); len++);
173 } else {
174 for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++);
175 }
176 return len;
177}
178
179/*
180 * C-style name quoting.
181 *
182 * (1) if sb and fp are both NULL, inspect the input name and counts the
183 * number of bytes that are needed to hold c_style quoted version of name,
184 * counting the double quotes around it but not terminating NUL, and
185 * returns it.
186 * However, if name does not need c_style quoting, it returns 0.
187 *
188 * (2) if sb or fp are not NULL, it emits the c_style quoted version
189 * of name, enclosed with double quotes if asked and needed only.
190 * Return value is the same as in (1).
191 */
192static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
193 struct strbuf *sb, FILE *fp, int no_dq)
194{
195#undef EMIT
196#define EMIT(c) \
197 do { \
198 if (sb) strbuf_addch(sb, (c)); \
199 if (fp) fputc((c), fp); \
200 count++; \
201 } while (0)
202#define EMITBUF(s, l) \
203 do { \
204 int __ret; \
205 if (sb) strbuf_add(sb, (s), (l)); \
206 if (fp) __ret = fwrite((s), (l), 1, fp); \
207 count += (l); \
208 } while (0)
209
210 size_t len, count = 0;
211 const char *p = name;
212
213 for (;;) {
214 int ch;
215
216 len = next_quote_pos(p, maxlen);
217 if (len == maxlen || !p[len])
218 break;
219
220 if (!no_dq && p == name)
221 EMIT('"');
222
223 EMITBUF(p, len);
224 EMIT('\\');
225 p += len;
226 ch = (unsigned char)*p++;
227 if (sq_lookup[ch] >= ' ') {
228 EMIT(sq_lookup[ch]);
229 } else {
230 EMIT(((ch >> 6) & 03) + '0');
231 EMIT(((ch >> 3) & 07) + '0');
232 EMIT(((ch >> 0) & 07) + '0');
233 }
234 }
235
236 EMITBUF(p, len);
237 if (p == name) /* no ending quote needed */
238 return 0;
239
240 if (!no_dq)
241 EMIT('"');
242 return count;
243}
244
245size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq)
246{
247 return quote_c_style_counted(name, -1, sb, fp, nodq);
248}
249
250void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, int nodq)
251{
252 if (quote_c_style(prefix, NULL, NULL, 0) ||
253 quote_c_style(path, NULL, NULL, 0)) {
254 if (!nodq)
255 strbuf_addch(sb, '"');
256 quote_c_style(prefix, sb, NULL, 1);
257 quote_c_style(path, sb, NULL, 1);
258 if (!nodq)
259 strbuf_addch(sb, '"');
260 } else {
261 strbuf_addstr(sb, prefix);
262 strbuf_addstr(sb, path);
263 }
264}
265
266void write_name_quoted(const char *name, FILE *fp, int terminator)
267{
268 if (terminator) {
269 quote_c_style(name, NULL, fp, 0);
270 } else {
271 fputs(name, fp);
272 }
273 fputc(terminator, fp);
274}
275
276extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
277 const char *name, FILE *fp, int terminator)
278{
279 int needquote = 0;
280
281 if (terminator) {
282 needquote = next_quote_pos(pfx, pfxlen) < pfxlen
283 || name[next_quote_pos(name, -1)];
284 }
285 if (needquote) {
286 fputc('"', fp);
287 quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
288 quote_c_style(name, NULL, fp, 1);
289 fputc('"', fp);
290 } else {
291 int ret;
292
293 ret = fwrite(pfx, pfxlen, 1, fp);
294 fputs(name, fp);
295 }
296 fputc(terminator, fp);
297}
298
299/* quote path as relative to the given prefix */
300char *quote_path_relative(const char *in, int len,
301 struct strbuf *out, const char *prefix)
302{
303 int needquote;
304
305 if (len < 0)
306 len = strlen(in);
307
308 /* "../" prefix itself does not need quoting, but "in" might. */
309 needquote = next_quote_pos(in, len) < len;
310 strbuf_setlen(out, 0);
311 strbuf_grow(out, len);
312
313 if (needquote)
314 strbuf_addch(out, '"');
315 if (prefix) {
316 int off = 0;
317 while (prefix[off] && off < len && prefix[off] == in[off])
318 if (prefix[off] == '/') {
319 prefix += off + 1;
320 in += off + 1;
321 len -= off + 1;
322 off = 0;
323 } else
324 off++;
325
326 for (; *prefix; prefix++)
327 if (*prefix == '/')
328 strbuf_addstr(out, "../");
329 }
330
331 quote_c_style_counted (in, len, out, NULL, 1);
332
333 if (needquote)
334 strbuf_addch(out, '"');
335 if (!out->len)
336 strbuf_addstr(out, "./");
337
338 return out->buf;
339}
340
341/*
342 * C-style name unquoting.
343 *
344 * Quoted should point at the opening double quote.
345 * + Returns 0 if it was able to unquote the string properly, and appends the
346 * result in the strbuf `sb'.
347 * + Returns -1 in case of error, and doesn't touch the strbuf. Though note
348 * that this function will allocate memory in the strbuf, so calling
349 * strbuf_release is mandatory whichever result unquote_c_style returns.
350 *
351 * Updates endp pointer to point at one past the ending double quote if given.
352 */
353int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
354{
355 size_t oldlen = sb->len, len;
356 int ch, ac;
357
358 if (*quoted++ != '"')
359 return -1;
360
361 for (;;) {
362 len = strcspn(quoted, "\"\\");
363 strbuf_add(sb, quoted, len);
364 quoted += len;
365
366 switch (*quoted++) {
367 case '"':
368 if (endp)
369 *endp = quoted;
370 return 0;
371 case '\\':
372 break;
373 default:
374 goto error;
375 }
376
377 switch ((ch = *quoted++)) {
378 case 'a': ch = '\a'; break;
379 case 'b': ch = '\b'; break;
380 case 'f': ch = '\f'; break;
381 case 'n': ch = '\n'; break;
382 case 'r': ch = '\r'; break;
383 case 't': ch = '\t'; break;
384 case 'v': ch = '\v'; break;
385
386 case '\\': case '"':
387 break; /* verbatim */
388
389 /* octal values with first digit over 4 overflow */
390 case '0': case '1': case '2': case '3':
391 ac = ((ch - '0') << 6);
392 if ((ch = *quoted++) < '0' || '7' < ch)
393 goto error;
394 ac |= ((ch - '0') << 3);
395 if ((ch = *quoted++) < '0' || '7' < ch)
396 goto error;
397 ac |= (ch - '0');
398 ch = ac;
399 break;
400 default:
401 goto error;
402 }
403 strbuf_addch(sb, ch);
404 }
405
406 error:
407 strbuf_setlen(sb, oldlen);
408 return -1;
409}
410
411/* quoting as a string literal for other languages */
412
413void perl_quote_print(FILE *stream, const char *src)
414{
415 const char sq = '\'';
416 const char bq = '\\';
417 char c;
418
419 fputc(sq, stream);
420 while ((c = *src++)) {
421 if (c == sq || c == bq)
422 fputc(bq, stream);
423 fputc(c, stream);
424 }
425 fputc(sq, stream);
426}
427
428void python_quote_print(FILE *stream, const char *src)
429{
430 const char sq = '\'';
431 const char bq = '\\';
432 const char nl = '\n';
433 char c;
434
435 fputc(sq, stream);
436 while ((c = *src++)) {
437 if (c == nl) {
438 fputc(bq, stream);
439 fputc('n', stream);
440 continue;
441 }
442 if (c == sq || c == bq)
443 fputc(bq, stream);
444 fputc(c, stream);
445 }
446 fputc(sq, stream);
447}
448
449void tcl_quote_print(FILE *stream, const char *src)
450{
451 char c;
452
453 fputc('"', stream);
454 while ((c = *src++)) {
455 switch (c) {
456 case '[': case ']':
457 case '{': case '}':
458 case '$': case '\\': case '"':
459 fputc('\\', stream);
460 default:
461 fputc(c, stream);
462 break;
463 case '\f':
464 fputs("\\f", stream);
465 break;
466 case '\r':
467 fputs("\\r", stream);
468 break;
469 case '\n':
470 fputs("\\n", stream);
471 break;
472 case '\t':
473 fputs("\\t", stream);
474 break;
475 case '\v':
476 fputs("\\v", stream);
477 break;
478 }
479 }
480 fputc('"', stream);
481}
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
new file mode 100644
index 000000000000..5dfad89816db
--- /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, size_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/rbtree.c b/tools/perf/util/rbtree.c
new file mode 100644
index 000000000000..b15ba9c7cb3f
--- /dev/null
+++ b/tools/perf/util/rbtree.c
@@ -0,0 +1,383 @@
1/*
2 Red Black Trees
3 (C) 1999 Andrea Arcangeli <andrea@suse.de>
4 (C) 2002 David Woodhouse <dwmw2@infradead.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 linux/lib/rbtree.c
21*/
22
23#include "rbtree.h"
24
25static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
26{
27 struct rb_node *right = node->rb_right;
28 struct rb_node *parent = rb_parent(node);
29
30 if ((node->rb_right = right->rb_left))
31 rb_set_parent(right->rb_left, node);
32 right->rb_left = node;
33
34 rb_set_parent(right, parent);
35
36 if (parent)
37 {
38 if (node == parent->rb_left)
39 parent->rb_left = right;
40 else
41 parent->rb_right = right;
42 }
43 else
44 root->rb_node = right;
45 rb_set_parent(node, right);
46}
47
48static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
49{
50 struct rb_node *left = node->rb_left;
51 struct rb_node *parent = rb_parent(node);
52
53 if ((node->rb_left = left->rb_right))
54 rb_set_parent(left->rb_right, node);
55 left->rb_right = node;
56
57 rb_set_parent(left, parent);
58
59 if (parent)
60 {
61 if (node == parent->rb_right)
62 parent->rb_right = left;
63 else
64 parent->rb_left = left;
65 }
66 else
67 root->rb_node = left;
68 rb_set_parent(node, left);
69}
70
71void rb_insert_color(struct rb_node *node, struct rb_root *root)
72{
73 struct rb_node *parent, *gparent;
74
75 while ((parent = rb_parent(node)) && rb_is_red(parent))
76 {
77 gparent = rb_parent(parent);
78
79 if (parent == gparent->rb_left)
80 {
81 {
82 register struct rb_node *uncle = gparent->rb_right;
83 if (uncle && rb_is_red(uncle))
84 {
85 rb_set_black(uncle);
86 rb_set_black(parent);
87 rb_set_red(gparent);
88 node = gparent;
89 continue;
90 }
91 }
92
93 if (parent->rb_right == node)
94 {
95 register struct rb_node *tmp;
96 __rb_rotate_left(parent, root);
97 tmp = parent;
98 parent = node;
99 node = tmp;
100 }
101
102 rb_set_black(parent);
103 rb_set_red(gparent);
104 __rb_rotate_right(gparent, root);
105 } else {
106 {
107 register struct rb_node *uncle = gparent->rb_left;
108 if (uncle && rb_is_red(uncle))
109 {
110 rb_set_black(uncle);
111 rb_set_black(parent);
112 rb_set_red(gparent);
113 node = gparent;
114 continue;
115 }
116 }
117
118 if (parent->rb_left == node)
119 {
120 register struct rb_node *tmp;
121 __rb_rotate_right(parent, root);
122 tmp = parent;
123 parent = node;
124 node = tmp;
125 }
126
127 rb_set_black(parent);
128 rb_set_red(gparent);
129 __rb_rotate_left(gparent, root);
130 }
131 }
132
133 rb_set_black(root->rb_node);
134}
135
136static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
137 struct rb_root *root)
138{
139 struct rb_node *other;
140
141 while ((!node || rb_is_black(node)) && node != root->rb_node)
142 {
143 if (parent->rb_left == node)
144 {
145 other = parent->rb_right;
146 if (rb_is_red(other))
147 {
148 rb_set_black(other);
149 rb_set_red(parent);
150 __rb_rotate_left(parent, root);
151 other = parent->rb_right;
152 }
153 if ((!other->rb_left || rb_is_black(other->rb_left)) &&
154 (!other->rb_right || rb_is_black(other->rb_right)))
155 {
156 rb_set_red(other);
157 node = parent;
158 parent = rb_parent(node);
159 }
160 else
161 {
162 if (!other->rb_right || rb_is_black(other->rb_right))
163 {
164 rb_set_black(other->rb_left);
165 rb_set_red(other);
166 __rb_rotate_right(other, root);
167 other = parent->rb_right;
168 }
169 rb_set_color(other, rb_color(parent));
170 rb_set_black(parent);
171 rb_set_black(other->rb_right);
172 __rb_rotate_left(parent, root);
173 node = root->rb_node;
174 break;
175 }
176 }
177 else
178 {
179 other = parent->rb_left;
180 if (rb_is_red(other))
181 {
182 rb_set_black(other);
183 rb_set_red(parent);
184 __rb_rotate_right(parent, root);
185 other = parent->rb_left;
186 }
187 if ((!other->rb_left || rb_is_black(other->rb_left)) &&
188 (!other->rb_right || rb_is_black(other->rb_right)))
189 {
190 rb_set_red(other);
191 node = parent;
192 parent = rb_parent(node);
193 }
194 else
195 {
196 if (!other->rb_left || rb_is_black(other->rb_left))
197 {
198 rb_set_black(other->rb_right);
199 rb_set_red(other);
200 __rb_rotate_left(other, root);
201 other = parent->rb_left;
202 }
203 rb_set_color(other, rb_color(parent));
204 rb_set_black(parent);
205 rb_set_black(other->rb_left);
206 __rb_rotate_right(parent, root);
207 node = root->rb_node;
208 break;
209 }
210 }
211 }
212 if (node)
213 rb_set_black(node);
214}
215
216void rb_erase(struct rb_node *node, struct rb_root *root)
217{
218 struct rb_node *child, *parent;
219 int color;
220
221 if (!node->rb_left)
222 child = node->rb_right;
223 else if (!node->rb_right)
224 child = node->rb_left;
225 else
226 {
227 struct rb_node *old = node, *left;
228
229 node = node->rb_right;
230 while ((left = node->rb_left) != NULL)
231 node = left;
232 child = node->rb_right;
233 parent = rb_parent(node);
234 color = rb_color(node);
235
236 if (child)
237 rb_set_parent(child, parent);
238 if (parent == old) {
239 parent->rb_right = child;
240 parent = node;
241 } else
242 parent->rb_left = child;
243
244 node->rb_parent_color = old->rb_parent_color;
245 node->rb_right = old->rb_right;
246 node->rb_left = old->rb_left;
247
248 if (rb_parent(old))
249 {
250 if (rb_parent(old)->rb_left == old)
251 rb_parent(old)->rb_left = node;
252 else
253 rb_parent(old)->rb_right = node;
254 } else
255 root->rb_node = node;
256
257 rb_set_parent(old->rb_left, node);
258 if (old->rb_right)
259 rb_set_parent(old->rb_right, node);
260 goto color;
261 }
262
263 parent = rb_parent(node);
264 color = rb_color(node);
265
266 if (child)
267 rb_set_parent(child, parent);
268 if (parent)
269 {
270 if (parent->rb_left == node)
271 parent->rb_left = child;
272 else
273 parent->rb_right = child;
274 }
275 else
276 root->rb_node = child;
277
278 color:
279 if (color == RB_BLACK)
280 __rb_erase_color(child, parent, root);
281}
282
283/*
284 * This function returns the first node (in sort order) of the tree.
285 */
286struct rb_node *rb_first(const struct rb_root *root)
287{
288 struct rb_node *n;
289
290 n = root->rb_node;
291 if (!n)
292 return NULL;
293 while (n->rb_left)
294 n = n->rb_left;
295 return n;
296}
297
298struct rb_node *rb_last(const struct rb_root *root)
299{
300 struct rb_node *n;
301
302 n = root->rb_node;
303 if (!n)
304 return NULL;
305 while (n->rb_right)
306 n = n->rb_right;
307 return n;
308}
309
310struct rb_node *rb_next(const struct rb_node *node)
311{
312 struct rb_node *parent;
313
314 if (rb_parent(node) == node)
315 return NULL;
316
317 /* If we have a right-hand child, go down and then left as far
318 as we can. */
319 if (node->rb_right) {
320 node = node->rb_right;
321 while (node->rb_left)
322 node=node->rb_left;
323 return (struct rb_node *)node;
324 }
325
326 /* No right-hand children. Everything down and left is
327 smaller than us, so any 'next' node must be in the general
328 direction of our parent. Go up the tree; any time the
329 ancestor is a right-hand child of its parent, keep going
330 up. First time it's a left-hand child of its parent, said
331 parent is our 'next' node. */
332 while ((parent = rb_parent(node)) && node == parent->rb_right)
333 node = parent;
334
335 return parent;
336}
337
338struct rb_node *rb_prev(const struct rb_node *node)
339{
340 struct rb_node *parent;
341
342 if (rb_parent(node) == node)
343 return NULL;
344
345 /* If we have a left-hand child, go down and then right as far
346 as we can. */
347 if (node->rb_left) {
348 node = node->rb_left;
349 while (node->rb_right)
350 node=node->rb_right;
351 return (struct rb_node *)node;
352 }
353
354 /* No left-hand children. Go up till we find an ancestor which
355 is a right-hand child of its parent */
356 while ((parent = rb_parent(node)) && node == parent->rb_left)
357 node = parent;
358
359 return parent;
360}
361
362void rb_replace_node(struct rb_node *victim, struct rb_node *new,
363 struct rb_root *root)
364{
365 struct rb_node *parent = rb_parent(victim);
366
367 /* Set the surrounding nodes to point to the replacement */
368 if (parent) {
369 if (victim == parent->rb_left)
370 parent->rb_left = new;
371 else
372 parent->rb_right = new;
373 } else {
374 root->rb_node = new;
375 }
376 if (victim->rb_left)
377 rb_set_parent(victim->rb_left, new);
378 if (victim->rb_right)
379 rb_set_parent(victim->rb_right, new);
380
381 /* Copy the pointers/colour from the victim to the replacement */
382 *new = *victim;
383}
diff --git a/tools/perf/util/rbtree.h b/tools/perf/util/rbtree.h
new file mode 100644
index 000000000000..6bdc488a47fb
--- /dev/null
+++ b/tools/perf/util/rbtree.h
@@ -0,0 +1,171 @@
1/*
2 Red Black Trees
3 (C) 1999 Andrea Arcangeli <andrea@suse.de>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 linux/include/linux/rbtree.h
20
21 To use rbtrees you'll have to implement your own insert and search cores.
22 This will avoid us to use callbacks and to drop drammatically performances.
23 I know it's not the cleaner way, but in C (not in C++) to get
24 performances and genericity...
25
26 Some example of insert and search follows here. The search is a plain
27 normal search over an ordered tree. The insert instead must be implemented
28 int two steps: as first thing the code must insert the element in
29 order as a red leaf in the tree, then the support library function
30 rb_insert_color() must be called. Such function will do the
31 not trivial work to rebalance the rbtree if necessary.
32
33-----------------------------------------------------------------------
34static inline struct page * rb_search_page_cache(struct inode * inode,
35 unsigned long offset)
36{
37 struct rb_node * n = inode->i_rb_page_cache.rb_node;
38 struct page * page;
39
40 while (n)
41 {
42 page = rb_entry(n, struct page, rb_page_cache);
43
44 if (offset < page->offset)
45 n = n->rb_left;
46 else if (offset > page->offset)
47 n = n->rb_right;
48 else
49 return page;
50 }
51 return NULL;
52}
53
54static inline struct page * __rb_insert_page_cache(struct inode * inode,
55 unsigned long offset,
56 struct rb_node * node)
57{
58 struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
59 struct rb_node * parent = NULL;
60 struct page * page;
61
62 while (*p)
63 {
64 parent = *p;
65 page = rb_entry(parent, struct page, rb_page_cache);
66
67 if (offset < page->offset)
68 p = &(*p)->rb_left;
69 else if (offset > page->offset)
70 p = &(*p)->rb_right;
71 else
72 return page;
73 }
74
75 rb_link_node(node, parent, p);
76
77 return NULL;
78}
79
80static inline struct page * rb_insert_page_cache(struct inode * inode,
81 unsigned long offset,
82 struct rb_node * node)
83{
84 struct page * ret;
85 if ((ret = __rb_insert_page_cache(inode, offset, node)))
86 goto out;
87 rb_insert_color(node, &inode->i_rb_page_cache);
88 out:
89 return ret;
90}
91-----------------------------------------------------------------------
92*/
93
94#ifndef _LINUX_RBTREE_H
95#define _LINUX_RBTREE_H
96
97#include <stddef.h>
98
99/**
100 * container_of - cast a member of a structure out to the containing structure
101 * @ptr: the pointer to the member.
102 * @type: the type of the container struct this is embedded in.
103 * @member: the name of the member within the struct.
104 *
105 */
106#define container_of(ptr, type, member) ({ \
107 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
108 (type *)( (char *)__mptr - offsetof(type,member) );})
109
110struct rb_node
111{
112 unsigned long rb_parent_color;
113#define RB_RED 0
114#define RB_BLACK 1
115 struct rb_node *rb_right;
116 struct rb_node *rb_left;
117} __attribute__((aligned(sizeof(long))));
118 /* The alignment might seem pointless, but allegedly CRIS needs it */
119
120struct rb_root
121{
122 struct rb_node *rb_node;
123};
124
125
126#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
127#define rb_color(r) ((r)->rb_parent_color & 1)
128#define rb_is_red(r) (!rb_color(r))
129#define rb_is_black(r) rb_color(r)
130#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
131#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
132
133static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
134{
135 rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
136}
137static inline void rb_set_color(struct rb_node *rb, int color)
138{
139 rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
140}
141
142#define RB_ROOT (struct rb_root) { NULL, }
143#define rb_entry(ptr, type, member) container_of(ptr, type, member)
144
145#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
146#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
147#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
148
149extern void rb_insert_color(struct rb_node *, struct rb_root *);
150extern void rb_erase(struct rb_node *, struct rb_root *);
151
152/* Find logical next and previous nodes in a tree */
153extern struct rb_node *rb_next(const struct rb_node *);
154extern struct rb_node *rb_prev(const struct rb_node *);
155extern struct rb_node *rb_first(const struct rb_root *);
156extern struct rb_node *rb_last(const struct rb_root *);
157
158/* Fast replacement of a single node without remove/rebalance/add/rebalance */
159extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
160 struct rb_root *root);
161
162static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
163 struct rb_node ** rb_link)
164{
165 node->rb_parent_color = (unsigned long )parent;
166 node->rb_left = node->rb_right = NULL;
167
168 *rb_link = node;
169}
170
171#endif /* _LINUX_RBTREE_H */
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
new file mode 100644
index 000000000000..b2f5e854f40a
--- /dev/null
+++ b/tools/perf/util/run-command.c
@@ -0,0 +1,395 @@
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#ifndef __MINGW32__
69 fflush(NULL);
70 cmd->pid = fork();
71 if (!cmd->pid) {
72 if (cmd->no_stdin)
73 dup_devnull(0);
74 else if (need_in) {
75 dup2(fdin[0], 0);
76 close_pair(fdin);
77 } else if (cmd->in) {
78 dup2(cmd->in, 0);
79 close(cmd->in);
80 }
81
82 if (cmd->no_stderr)
83 dup_devnull(2);
84 else if (need_err) {
85 dup2(fderr[1], 2);
86 close_pair(fderr);
87 }
88
89 if (cmd->no_stdout)
90 dup_devnull(1);
91 else if (cmd->stdout_to_stderr)
92 dup2(2, 1);
93 else if (need_out) {
94 dup2(fdout[1], 1);
95 close_pair(fdout);
96 } else if (cmd->out > 1) {
97 dup2(cmd->out, 1);
98 close(cmd->out);
99 }
100
101 if (cmd->dir && chdir(cmd->dir))
102 die("exec %s: cd to %s failed (%s)", cmd->argv[0],
103 cmd->dir, strerror(errno));
104 if (cmd->env) {
105 for (; *cmd->env; cmd->env++) {
106 if (strchr(*cmd->env, '='))
107 putenv((char*)*cmd->env);
108 else
109 unsetenv(*cmd->env);
110 }
111 }
112 if (cmd->preexec_cb)
113 cmd->preexec_cb();
114 if (cmd->perf_cmd) {
115 execv_perf_cmd(cmd->argv);
116 } else {
117 execvp(cmd->argv[0], (char *const*) cmd->argv);
118 }
119 exit(127);
120 }
121#else
122 int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
123 const char **sargv = cmd->argv;
124 char **env = environ;
125
126 if (cmd->no_stdin) {
127 s0 = dup(0);
128 dup_devnull(0);
129 } else if (need_in) {
130 s0 = dup(0);
131 dup2(fdin[0], 0);
132 } else if (cmd->in) {
133 s0 = dup(0);
134 dup2(cmd->in, 0);
135 }
136
137 if (cmd->no_stderr) {
138 s2 = dup(2);
139 dup_devnull(2);
140 } else if (need_err) {
141 s2 = dup(2);
142 dup2(fderr[1], 2);
143 }
144
145 if (cmd->no_stdout) {
146 s1 = dup(1);
147 dup_devnull(1);
148 } else if (cmd->stdout_to_stderr) {
149 s1 = dup(1);
150 dup2(2, 1);
151 } else if (need_out) {
152 s1 = dup(1);
153 dup2(fdout[1], 1);
154 } else if (cmd->out > 1) {
155 s1 = dup(1);
156 dup2(cmd->out, 1);
157 }
158
159 if (cmd->dir)
160 die("chdir in start_command() not implemented");
161 if (cmd->env) {
162 env = copy_environ();
163 for (; *cmd->env; cmd->env++)
164 env = env_setenv(env, *cmd->env);
165 }
166
167 if (cmd->perf_cmd) {
168 cmd->argv = prepare_perf_cmd(cmd->argv);
169 }
170
171 cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
172
173 if (cmd->env)
174 free_environ(env);
175 if (cmd->perf_cmd)
176 free(cmd->argv);
177
178 cmd->argv = sargv;
179 if (s0 >= 0)
180 dup2(s0, 0), close(s0);
181 if (s1 >= 0)
182 dup2(s1, 1), close(s1);
183 if (s2 >= 0)
184 dup2(s2, 2), close(s2);
185#endif
186
187 if (cmd->pid < 0) {
188 int err = errno;
189 if (need_in)
190 close_pair(fdin);
191 else if (cmd->in)
192 close(cmd->in);
193 if (need_out)
194 close_pair(fdout);
195 else if (cmd->out)
196 close(cmd->out);
197 if (need_err)
198 close_pair(fderr);
199 return err == ENOENT ?
200 -ERR_RUN_COMMAND_EXEC :
201 -ERR_RUN_COMMAND_FORK;
202 }
203
204 if (need_in)
205 close(fdin[0]);
206 else if (cmd->in)
207 close(cmd->in);
208
209 if (need_out)
210 close(fdout[1]);
211 else if (cmd->out)
212 close(cmd->out);
213
214 if (need_err)
215 close(fderr[1]);
216
217 return 0;
218}
219
220static int wait_or_whine(pid_t pid)
221{
222 for (;;) {
223 int status, code;
224 pid_t waiting = waitpid(pid, &status, 0);
225
226 if (waiting < 0) {
227 if (errno == EINTR)
228 continue;
229 error("waitpid failed (%s)", strerror(errno));
230 return -ERR_RUN_COMMAND_WAITPID;
231 }
232 if (waiting != pid)
233 return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
234 if (WIFSIGNALED(status))
235 return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
236
237 if (!WIFEXITED(status))
238 return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
239 code = WEXITSTATUS(status);
240 switch (code) {
241 case 127:
242 return -ERR_RUN_COMMAND_EXEC;
243 case 0:
244 return 0;
245 default:
246 return -code;
247 }
248 }
249}
250
251int finish_command(struct child_process *cmd)
252{
253 return wait_or_whine(cmd->pid);
254}
255
256int run_command(struct child_process *cmd)
257{
258 int code = start_command(cmd);
259 if (code)
260 return code;
261 return finish_command(cmd);
262}
263
264static void prepare_run_command_v_opt(struct child_process *cmd,
265 const char **argv,
266 int opt)
267{
268 memset(cmd, 0, sizeof(*cmd));
269 cmd->argv = argv;
270 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
271 cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
272 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
273}
274
275int run_command_v_opt(const char **argv, int opt)
276{
277 struct child_process cmd;
278 prepare_run_command_v_opt(&cmd, argv, opt);
279 return run_command(&cmd);
280}
281
282int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
283{
284 struct child_process cmd;
285 prepare_run_command_v_opt(&cmd, argv, opt);
286 cmd.dir = dir;
287 cmd.env = env;
288 return run_command(&cmd);
289}
290
291#ifdef __MINGW32__
292static __stdcall unsigned run_thread(void *data)
293{
294 struct async *async = data;
295 return async->proc(async->fd_for_proc, async->data);
296}
297#endif
298
299int start_async(struct async *async)
300{
301 int pipe_out[2];
302
303 if (pipe(pipe_out) < 0)
304 return error("cannot create pipe: %s", strerror(errno));
305 async->out = pipe_out[0];
306
307#ifndef __MINGW32__
308 /* Flush stdio before fork() to avoid cloning buffers */
309 fflush(NULL);
310
311 async->pid = fork();
312 if (async->pid < 0) {
313 error("fork (async) failed: %s", strerror(errno));
314 close_pair(pipe_out);
315 return -1;
316 }
317 if (!async->pid) {
318 close(pipe_out[0]);
319 exit(!!async->proc(pipe_out[1], async->data));
320 }
321 close(pipe_out[1]);
322#else
323 async->fd_for_proc = pipe_out[1];
324 async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
325 if (!async->tid) {
326 error("cannot create thread: %s", strerror(errno));
327 close_pair(pipe_out);
328 return -1;
329 }
330#endif
331 return 0;
332}
333
334int finish_async(struct async *async)
335{
336#ifndef __MINGW32__
337 int ret = 0;
338
339 if (wait_or_whine(async->pid))
340 ret = error("waitpid (async) failed");
341#else
342 DWORD ret = 0;
343 if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0)
344 ret = error("waiting for thread failed: %lu", GetLastError());
345 else if (!GetExitCodeThread(async->tid, &ret))
346 ret = error("cannot get thread exit code: %lu", GetLastError());
347 CloseHandle(async->tid);
348#endif
349 return ret;
350}
351
352int run_hook(const char *index_file, const char *name, ...)
353{
354 struct child_process hook;
355 const char **argv = NULL, *env[2];
356 char index[PATH_MAX];
357 va_list args;
358 int ret;
359 size_t i = 0, alloc = 0;
360
361 if (access(perf_path("hooks/%s", name), X_OK) < 0)
362 return 0;
363
364 va_start(args, name);
365 ALLOC_GROW(argv, i + 1, alloc);
366 argv[i++] = perf_path("hooks/%s", name);
367 while (argv[i-1]) {
368 ALLOC_GROW(argv, i + 1, alloc);
369 argv[i++] = va_arg(args, const char *);
370 }
371 va_end(args);
372
373 memset(&hook, 0, sizeof(hook));
374 hook.argv = argv;
375 hook.no_stdin = 1;
376 hook.stdout_to_stderr = 1;
377 if (index_file) {
378 snprintf(index, sizeof(index), "PERF_INDEX_FILE=%s", index_file);
379 env[0] = index;
380 env[1] = NULL;
381 hook.env = env;
382 }
383
384 ret = start_command(&hook);
385 free(argv);
386 if (ret) {
387 warning("Could not spawn %s", argv[0]);
388 return ret;
389 }
390 ret = finish_command(&hook);
391 if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
392 warning("%s exited due to uncaught signal", argv[0]);
393
394 return ret;
395}
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
new file mode 100644
index 000000000000..328289f23669
--- /dev/null
+++ b/tools/perf/util/run-command.h
@@ -0,0 +1,93 @@
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#ifndef __MINGW32__
83 pid_t pid;
84#else
85 HANDLE tid;
86 int fd_for_proc;
87#endif
88};
89
90int start_async(struct async *async);
91int finish_async(struct async *async);
92
93#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..eaba09306802
--- /dev/null
+++ b/tools/perf/util/strbuf.c
@@ -0,0 +1,359 @@
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, size_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 int i;
96 for (i = 0; i < sb->len; i++)
97 sb->buf[i] = tolower(sb->buf[i]);
98}
99
100struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
101{
102 int alloc = 2, pos = 0;
103 char *n, *p;
104 struct strbuf **ret;
105 struct strbuf *t;
106
107 ret = calloc(alloc, sizeof(struct strbuf *));
108 p = n = sb->buf;
109 while (n < sb->buf + sb->len) {
110 int len;
111 n = memchr(n, delim, sb->len - (n - sb->buf));
112 if (pos + 1 >= alloc) {
113 alloc = alloc * 2;
114 ret = realloc(ret, sizeof(struct strbuf *) * alloc);
115 }
116 if (!n)
117 n = sb->buf + sb->len - 1;
118 len = n - p + 1;
119 t = malloc(sizeof(struct strbuf));
120 strbuf_init(t, len);
121 strbuf_add(t, p, len);
122 ret[pos] = t;
123 ret[++pos] = NULL;
124 p = ++n;
125 }
126 return ret;
127}
128
129void strbuf_list_free(struct strbuf **sbs)
130{
131 struct strbuf **s = sbs;
132
133 while (*s) {
134 strbuf_release(*s);
135 free(*s++);
136 }
137 free(sbs);
138}
139
140int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
141{
142 int len = a->len < b->len ? a->len: b->len;
143 int cmp = memcmp(a->buf, b->buf, len);
144 if (cmp)
145 return cmp;
146 return a->len < b->len ? -1: a->len != b->len;
147}
148
149void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
150 const void *data, size_t dlen)
151{
152 if (pos + len < pos)
153 die("you want to use way too much memory");
154 if (pos > sb->len)
155 die("`pos' is too far after the end of the buffer");
156 if (pos + len > sb->len)
157 die("`pos + len' is too far after the end of the buffer");
158
159 if (dlen >= len)
160 strbuf_grow(sb, dlen - len);
161 memmove(sb->buf + pos + dlen,
162 sb->buf + pos + len,
163 sb->len - pos - len);
164 memcpy(sb->buf + pos, data, dlen);
165 strbuf_setlen(sb, sb->len + dlen - len);
166}
167
168void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
169{
170 strbuf_splice(sb, pos, 0, data, len);
171}
172
173void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
174{
175 strbuf_splice(sb, pos, len, NULL, 0);
176}
177
178void strbuf_add(struct strbuf *sb, const void *data, size_t len)
179{
180 strbuf_grow(sb, len);
181 memcpy(sb->buf + sb->len, data, len);
182 strbuf_setlen(sb, sb->len + len);
183}
184
185void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
186{
187 strbuf_grow(sb, len);
188 memcpy(sb->buf + sb->len, sb->buf + pos, len);
189 strbuf_setlen(sb, sb->len + len);
190}
191
192void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
193{
194 int len;
195 va_list ap;
196
197 if (!strbuf_avail(sb))
198 strbuf_grow(sb, 64);
199 va_start(ap, fmt);
200 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
201 va_end(ap);
202 if (len < 0)
203 die("your vsnprintf is broken");
204 if (len > strbuf_avail(sb)) {
205 strbuf_grow(sb, len);
206 va_start(ap, fmt);
207 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
208 va_end(ap);
209 if (len > strbuf_avail(sb)) {
210 die("this should not happen, your snprintf is broken");
211 }
212 }
213 strbuf_setlen(sb, sb->len + len);
214}
215
216void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
217 void *context)
218{
219 for (;;) {
220 const char *percent;
221 size_t consumed;
222
223 percent = strchrnul(format, '%');
224 strbuf_add(sb, format, percent - format);
225 if (!*percent)
226 break;
227 format = percent + 1;
228
229 consumed = fn(sb, format, context);
230 if (consumed)
231 format += consumed;
232 else
233 strbuf_addch(sb, '%');
234 }
235}
236
237size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
238 void *context)
239{
240 struct strbuf_expand_dict_entry *e = context;
241 size_t len;
242
243 for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
244 if (!strncmp(placeholder, e->placeholder, len)) {
245 if (e->value)
246 strbuf_addstr(sb, e->value);
247 return len;
248 }
249 }
250 return 0;
251}
252
253size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
254{
255 size_t res;
256 size_t oldalloc = sb->alloc;
257
258 strbuf_grow(sb, size);
259 res = fread(sb->buf + sb->len, 1, size, f);
260 if (res > 0)
261 strbuf_setlen(sb, sb->len + res);
262 else if (res < 0 && oldalloc == 0)
263 strbuf_release(sb);
264 return res;
265}
266
267ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
268{
269 size_t oldlen = sb->len;
270 size_t oldalloc = sb->alloc;
271
272 strbuf_grow(sb, hint ? hint : 8192);
273 for (;;) {
274 ssize_t cnt;
275
276 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
277 if (cnt < 0) {
278 if (oldalloc == 0)
279 strbuf_release(sb);
280 else
281 strbuf_setlen(sb, oldlen);
282 return -1;
283 }
284 if (!cnt)
285 break;
286 sb->len += cnt;
287 strbuf_grow(sb, 8192);
288 }
289
290 sb->buf[sb->len] = '\0';
291 return sb->len - oldlen;
292}
293
294#define STRBUF_MAXLINK (2*PATH_MAX)
295
296int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
297{
298 size_t oldalloc = sb->alloc;
299
300 if (hint < 32)
301 hint = 32;
302
303 while (hint < STRBUF_MAXLINK) {
304 int len;
305
306 strbuf_grow(sb, hint);
307 len = readlink(path, sb->buf, hint);
308 if (len < 0) {
309 if (errno != ERANGE)
310 break;
311 } else if (len < hint) {
312 strbuf_setlen(sb, len);
313 return 0;
314 }
315
316 /* .. the buffer was too small - try again */
317 hint *= 2;
318 }
319 if (oldalloc == 0)
320 strbuf_release(sb);
321 return -1;
322}
323
324int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
325{
326 int ch;
327
328 strbuf_grow(sb, 0);
329 if (feof(fp))
330 return EOF;
331
332 strbuf_reset(sb);
333 while ((ch = fgetc(fp)) != EOF) {
334 if (ch == term)
335 break;
336 strbuf_grow(sb, 1);
337 sb->buf[sb->len++] = ch;
338 }
339 if (ch == EOF && sb->len == 0)
340 return EOF;
341
342 sb->buf[sb->len] = '\0';
343 return 0;
344}
345
346int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
347{
348 int fd, len;
349
350 fd = open(path, O_RDONLY);
351 if (fd < 0)
352 return -1;
353 len = strbuf_read(sb, fd, hint);
354 close(fd);
355 if (len < 0)
356 return -1;
357
358 return len;
359}
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
new file mode 100644
index 000000000000..9ee908a3ec5d
--- /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 *, size_t);
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 size_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, size_t hint);
126extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
127extern int strbuf_readlink(struct strbuf *sb, const char *path, size_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..37b03255b425
--- /dev/null
+++ b/tools/perf/util/string.h
@@ -0,0 +1,8 @@
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#endif
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
new file mode 100644
index 000000000000..86e14375e74e
--- /dev/null
+++ b/tools/perf/util/symbol.c
@@ -0,0 +1,641 @@
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
12static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size,
14 u64 obj_start, int verbose)
15{
16 size_t namelen = strlen(name) + 1;
17 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
18
19 if (!self)
20 return NULL;
21
22 if (verbose >= 2)
23 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
24 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
25
26 self->obj_start= obj_start;
27 self->hist = NULL;
28 self->hist_sum = 0;
29
30 if (sym_hist_filter && !strcmp(name, sym_hist_filter))
31 self->hist = calloc(sizeof(u64), len);
32
33 if (priv_size) {
34 memset(self, 0, priv_size);
35 self = ((void *)self) + priv_size;
36 }
37 self->start = start;
38 self->end = start + len - 1;
39 memcpy(self->name, name, namelen);
40
41 return self;
42}
43
44static void symbol__delete(struct symbol *self, unsigned int priv_size)
45{
46 free(((void *)self) - priv_size);
47}
48
49static size_t symbol__fprintf(struct symbol *self, FILE *fp)
50{
51 return fprintf(fp, " %llx-%llx %s\n",
52 self->start, self->end, self->name);
53}
54
55struct dso *dso__new(const char *name, unsigned int sym_priv_size)
56{
57 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
58
59 if (self != NULL) {
60 strcpy(self->name, name);
61 self->syms = RB_ROOT;
62 self->sym_priv_size = sym_priv_size;
63 self->find_symbol = dso__find_symbol;
64 }
65
66 return self;
67}
68
69static void dso__delete_symbols(struct dso *self)
70{
71 struct symbol *pos;
72 struct rb_node *next = rb_first(&self->syms);
73
74 while (next) {
75 pos = rb_entry(next, struct symbol, rb_node);
76 next = rb_next(&pos->rb_node);
77 rb_erase(&pos->rb_node, &self->syms);
78 symbol__delete(pos, self->sym_priv_size);
79 }
80}
81
82void dso__delete(struct dso *self)
83{
84 dso__delete_symbols(self);
85 free(self);
86}
87
88static void dso__insert_symbol(struct dso *self, struct symbol *sym)
89{
90 struct rb_node **p = &self->syms.rb_node;
91 struct rb_node *parent = NULL;
92 const u64 ip = sym->start;
93 struct symbol *s;
94
95 while (*p != NULL) {
96 parent = *p;
97 s = rb_entry(parent, struct symbol, rb_node);
98 if (ip < s->start)
99 p = &(*p)->rb_left;
100 else
101 p = &(*p)->rb_right;
102 }
103 rb_link_node(&sym->rb_node, parent, p);
104 rb_insert_color(&sym->rb_node, &self->syms);
105}
106
107struct symbol *dso__find_symbol(struct dso *self, u64 ip)
108{
109 struct rb_node *n;
110
111 if (self == NULL)
112 return NULL;
113
114 n = self->syms.rb_node;
115
116 while (n) {
117 struct symbol *s = rb_entry(n, struct symbol, rb_node);
118
119 if (ip < s->start)
120 n = n->rb_left;
121 else if (ip > s->end)
122 n = n->rb_right;
123 else
124 return s;
125 }
126
127 return NULL;
128}
129
130size_t dso__fprintf(struct dso *self, FILE *fp)
131{
132 size_t ret = fprintf(fp, "dso: %s\n", self->name);
133
134 struct rb_node *nd;
135 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
136 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
137 ret += symbol__fprintf(pos, fp);
138 }
139
140 return ret;
141}
142
143static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
144{
145 struct rb_node *nd, *prevnd;
146 char *line = NULL;
147 size_t n;
148 FILE *file = fopen("/proc/kallsyms", "r");
149
150 if (file == NULL)
151 goto out_failure;
152
153 while (!feof(file)) {
154 u64 start;
155 struct symbol *sym;
156 int line_len, len;
157 char symbol_type;
158
159 line_len = getline(&line, &n, file);
160 if (line_len < 0)
161 break;
162
163 if (!line)
164 goto out_failure;
165
166 line[--line_len] = '\0'; /* \n */
167
168 len = hex2u64(line, &start);
169
170 len++;
171 if (len + 2 >= line_len)
172 continue;
173
174 symbol_type = toupper(line[len]);
175 /*
176 * We're interested only in code ('T'ext)
177 */
178 if (symbol_type != 'T' && symbol_type != 'W')
179 continue;
180 /*
181 * Well fix up the end later, when we have all sorted.
182 */
183 sym = symbol__new(start, 0xdead, line + len + 2,
184 self->sym_priv_size, 0, verbose);
185
186 if (sym == NULL)
187 goto out_delete_line;
188
189 if (filter && filter(self, sym))
190 symbol__delete(sym, self->sym_priv_size);
191 else
192 dso__insert_symbol(self, sym);
193 }
194
195 /*
196 * Now that we have all sorted out, just set the ->end of all
197 * symbols
198 */
199 prevnd = rb_first(&self->syms);
200
201 if (prevnd == NULL)
202 goto out_delete_line;
203
204 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
205 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
206 *curr = rb_entry(nd, struct symbol, rb_node);
207
208 prev->end = curr->start - 1;
209 prevnd = nd;
210 }
211
212 free(line);
213 fclose(file);
214
215 return 0;
216
217out_delete_line:
218 free(line);
219out_failure:
220 return -1;
221}
222
223static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose)
224{
225 char *line = NULL;
226 size_t n;
227 FILE *file;
228 int nr_syms = 0;
229
230 file = fopen(self->name, "r");
231 if (file == NULL)
232 goto out_failure;
233
234 while (!feof(file)) {
235 u64 start, size;
236 struct symbol *sym;
237 int line_len, len;
238
239 line_len = getline(&line, &n, file);
240 if (line_len < 0)
241 break;
242
243 if (!line)
244 goto out_failure;
245
246 line[--line_len] = '\0'; /* \n */
247
248 len = hex2u64(line, &start);
249
250 len++;
251 if (len + 2 >= line_len)
252 continue;
253
254 len += hex2u64(line + len, &size);
255
256 len++;
257 if (len + 2 >= line_len)
258 continue;
259
260 sym = symbol__new(start, size, line + len,
261 self->sym_priv_size, start, verbose);
262
263 if (sym == NULL)
264 goto out_delete_line;
265
266 if (filter && filter(self, sym))
267 symbol__delete(sym, self->sym_priv_size);
268 else {
269 dso__insert_symbol(self, sym);
270 nr_syms++;
271 }
272 }
273
274 free(line);
275 fclose(file);
276
277 return nr_syms;
278
279out_delete_line:
280 free(line);
281out_failure:
282 return -1;
283}
284
285/**
286 * elf_symtab__for_each_symbol - iterate thru all the symbols
287 *
288 * @self: struct elf_symtab instance to iterate
289 * @index: uint32_t index
290 * @sym: GElf_Sym iterator
291 */
292#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
293 for (index = 0, gelf_getsym(syms, index, &sym);\
294 index < nr_syms; \
295 index++, gelf_getsym(syms, index, &sym))
296
297static inline uint8_t elf_sym__type(const GElf_Sym *sym)
298{
299 return GELF_ST_TYPE(sym->st_info);
300}
301
302static inline int elf_sym__is_function(const GElf_Sym *sym)
303{
304 return elf_sym__type(sym) == STT_FUNC &&
305 sym->st_name != 0 &&
306 sym->st_shndx != SHN_UNDEF &&
307 sym->st_size != 0;
308}
309
310static inline const char *elf_sym__name(const GElf_Sym *sym,
311 const Elf_Data *symstrs)
312{
313 return symstrs->d_buf + sym->st_name;
314}
315
316static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
317 GElf_Shdr *shp, const char *name,
318 size_t *index)
319{
320 Elf_Scn *sec = NULL;
321 size_t cnt = 1;
322
323 while ((sec = elf_nextscn(elf, sec)) != NULL) {
324 char *str;
325
326 gelf_getshdr(sec, shp);
327 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
328 if (!strcmp(name, str)) {
329 if (index)
330 *index = cnt;
331 break;
332 }
333 ++cnt;
334 }
335
336 return sec;
337}
338
339#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
340 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
341 idx < nr_entries; \
342 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
343
344#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
345 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
346 idx < nr_entries; \
347 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
348
349static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
350 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym,
351 GElf_Shdr *shdr_dynsym,
352 size_t dynsym_idx, int verbose)
353{
354 uint32_t nr_rel_entries, idx;
355 GElf_Sym sym;
356 u64 plt_offset;
357 GElf_Shdr shdr_plt;
358 struct symbol *f;
359 GElf_Shdr shdr_rel_plt;
360 Elf_Data *reldata, *syms, *symstrs;
361 Elf_Scn *scn_plt_rel, *scn_symstrs;
362 char sympltname[1024];
363 int nr = 0, symidx;
364
365 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
366 ".rela.plt", NULL);
367 if (scn_plt_rel == NULL) {
368 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
369 ".rel.plt", NULL);
370 if (scn_plt_rel == NULL)
371 return 0;
372 }
373
374 if (shdr_rel_plt.sh_link != dynsym_idx)
375 return 0;
376
377 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL)
378 return 0;
379
380 /*
381 * Fetch the relocation section to find the indexes to the GOT
382 * and the symbols in the .dynsym they refer to.
383 */
384 reldata = elf_getdata(scn_plt_rel, NULL);
385 if (reldata == NULL)
386 return -1;
387
388 syms = elf_getdata(scn_dynsym, NULL);
389 if (syms == NULL)
390 return -1;
391
392 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link);
393 if (scn_symstrs == NULL)
394 return -1;
395
396 symstrs = elf_getdata(scn_symstrs, NULL);
397 if (symstrs == NULL)
398 return -1;
399
400 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
401 plt_offset = shdr_plt.sh_offset;
402
403 if (shdr_rel_plt.sh_type == SHT_RELA) {
404 GElf_Rela pos_mem, *pos;
405
406 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
407 nr_rel_entries) {
408 symidx = GELF_R_SYM(pos->r_info);
409 plt_offset += shdr_plt.sh_entsize;
410 gelf_getsym(syms, symidx, &sym);
411 snprintf(sympltname, sizeof(sympltname),
412 "%s@plt", elf_sym__name(&sym, symstrs));
413
414 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
415 sympltname, self->sym_priv_size, 0, verbose);
416 if (!f)
417 return -1;
418
419 dso__insert_symbol(self, f);
420 ++nr;
421 }
422 } else if (shdr_rel_plt.sh_type == SHT_REL) {
423 GElf_Rel pos_mem, *pos;
424 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
425 nr_rel_entries) {
426 symidx = GELF_R_SYM(pos->r_info);
427 plt_offset += shdr_plt.sh_entsize;
428 gelf_getsym(syms, symidx, &sym);
429 snprintf(sympltname, sizeof(sympltname),
430 "%s@plt", elf_sym__name(&sym, symstrs));
431
432 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
433 sympltname, self->sym_priv_size, 0, verbose);
434 if (!f)
435 return -1;
436
437 dso__insert_symbol(self, f);
438 ++nr;
439 }
440 } else {
441 /*
442 * TODO: There are still one more shdr_rel_plt.sh_type
443 * I have to investigate, but probably should be ignored.
444 */
445 }
446
447 return nr;
448}
449
450static int dso__load_sym(struct dso *self, int fd, const char *name,
451 symbol_filter_t filter, int verbose)
452{
453 Elf_Data *symstrs;
454 uint32_t nr_syms;
455 int err = -1;
456 uint32_t index;
457 GElf_Ehdr ehdr;
458 GElf_Shdr shdr;
459 Elf_Data *syms;
460 GElf_Sym sym;
461 Elf_Scn *sec, *sec_dynsym;
462 Elf *elf;
463 size_t dynsym_idx;
464 int nr = 0;
465
466 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
467 if (elf == NULL) {
468 if (verbose)
469 fprintf(stderr, "%s: cannot read %s ELF file.\n",
470 __func__, name);
471 goto out_close;
472 }
473
474 if (gelf_getehdr(elf, &ehdr) == NULL) {
475 if (verbose)
476 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
477 goto out_elf_end;
478 }
479
480 /*
481 * We need to check if we have a .dynsym, so that we can handle the
482 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
483 * .dynsym or .symtab)
484 */
485 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
486 ".dynsym", &dynsym_idx);
487 if (sec_dynsym != NULL) {
488 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
489 sec_dynsym, &shdr,
490 dynsym_idx, verbose);
491 if (nr < 0)
492 goto out_elf_end;
493 }
494
495 /*
496 * But if we have a full .symtab (that is a superset of .dynsym) we
497 * should add the symbols not in the .dynsyn
498 */
499 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
500 if (sec == NULL) {
501 if (sec_dynsym == NULL)
502 goto out_elf_end;
503
504 sec = sec_dynsym;
505 gelf_getshdr(sec, &shdr);
506 }
507
508 syms = elf_getdata(sec, NULL);
509 if (syms == NULL)
510 goto out_elf_end;
511
512 sec = elf_getscn(elf, shdr.sh_link);
513 if (sec == NULL)
514 goto out_elf_end;
515
516 symstrs = elf_getdata(sec, NULL);
517 if (symstrs == NULL)
518 goto out_elf_end;
519
520 nr_syms = shdr.sh_size / shdr.sh_entsize;
521
522 memset(&sym, 0, sizeof(sym));
523
524 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
525 struct symbol *f;
526 u64 obj_start;
527
528 if (!elf_sym__is_function(&sym))
529 continue;
530
531 sec = elf_getscn(elf, sym.st_shndx);
532 if (!sec)
533 goto out_elf_end;
534
535 gelf_getshdr(sec, &shdr);
536 obj_start = sym.st_value;
537
538 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
539
540 f = symbol__new(sym.st_value, sym.st_size,
541 elf_sym__name(&sym, symstrs),
542 self->sym_priv_size, obj_start, verbose);
543 if (!f)
544 goto out_elf_end;
545
546 if (filter && filter(self, f))
547 symbol__delete(f, self->sym_priv_size);
548 else {
549 dso__insert_symbol(self, f);
550 nr++;
551 }
552 }
553
554 err = nr;
555out_elf_end:
556 elf_end(elf);
557out_close:
558 return err;
559}
560
561int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
562{
563 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
564 char *name = malloc(size);
565 int variant = 0;
566 int ret = -1;
567 int fd;
568
569 if (!name)
570 return -1;
571
572 if (strncmp(self->name, "/tmp/perf-", 10) == 0)
573 return dso__load_perf_map(self, filter, verbose);
574
575more:
576 do {
577 switch (variant) {
578 case 0: /* Fedora */
579 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
580 break;
581 case 1: /* Ubuntu */
582 snprintf(name, size, "/usr/lib/debug%s", self->name);
583 break;
584 case 2: /* Sane people */
585 snprintf(name, size, "%s", self->name);
586 break;
587
588 default:
589 goto out;
590 }
591 variant++;
592
593 fd = open(name, O_RDONLY);
594 } while (fd < 0);
595
596 ret = dso__load_sym(self, fd, name, filter, verbose);
597 close(fd);
598
599 /*
600 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
601 */
602 if (!ret)
603 goto more;
604
605out:
606 free(name);
607 return ret;
608}
609
610static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
611 symbol_filter_t filter, int verbose)
612{
613 int err, fd = open(vmlinux, O_RDONLY);
614
615 if (fd < 0)
616 return -1;
617
618 err = dso__load_sym(self, fd, vmlinux, filter, verbose);
619 close(fd);
620
621 return err;
622}
623
624int dso__load_kernel(struct dso *self, const char *vmlinux,
625 symbol_filter_t filter, int verbose)
626{
627 int err = -1;
628
629 if (vmlinux)
630 err = dso__load_vmlinux(self, vmlinux, filter, verbose);
631
632 if (err)
633 err = dso__load_kallsyms(self, filter, verbose);
634
635 return err;
636}
637
638void symbol__init(void)
639{
640 elf_version(EV_CURRENT);
641}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
new file mode 100644
index 000000000000..ea332e56e458
--- /dev/null
+++ b/tools/perf/util/symbol.h
@@ -0,0 +1,49 @@
1#ifndef _PERF_SYMBOL_
2#define _PERF_SYMBOL_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include "list.h"
7#include "rbtree.h"
8
9struct symbol {
10 struct rb_node rb_node;
11 u64 start;
12 u64 end;
13 u64 obj_start;
14 u64 hist_sum;
15 u64 *hist;
16 void *priv;
17 char name[0];
18};
19
20struct dso {
21 struct list_head node;
22 struct rb_root syms;
23 unsigned int sym_priv_size;
24 struct symbol *(*find_symbol)(struct dso *, u64 ip);
25 char name[0];
26};
27
28const char *sym_hist_filter;
29
30typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
31
32struct dso *dso__new(const char *name, unsigned int sym_priv_size);
33void dso__delete(struct dso *self);
34
35static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
36{
37 return ((void *)sym) - self->sym_priv_size;
38}
39
40struct symbol *dso__find_symbol(struct dso *self, u64 ip);
41
42int dso__load_kernel(struct dso *self, const char *vmlinux,
43 symbol_filter_t filter, int verbose);
44int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
45
46size_t dso__fprintf(struct dso *self, FILE *fp);
47
48void symbol__init(void);
49#endif /* _PERF_SYMBOL_ */
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..b8cfed776d81
--- /dev/null
+++ b/tools/perf/util/util.h
@@ -0,0 +1,408 @@
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 <fcntl.h>
54#include <stddef.h>
55#include <stdlib.h>
56#include <stdarg.h>
57#include <string.h>
58#include <errno.h>
59#include <limits.h>
60#include <sys/param.h>
61#include <sys/types.h>
62#include <dirent.h>
63#include <sys/time.h>
64#include <time.h>
65#include <signal.h>
66#include <fnmatch.h>
67#include <assert.h>
68#include <regex.h>
69#include <utime.h>
70#ifndef __MINGW32__
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#if defined(__CYGWIN__)
85#undef _XOPEN_SOURCE
86#include <grp.h>
87#define _XOPEN_SOURCE 600
88#include "compat/cygwin.h"
89#else
90#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
91#include <grp.h>
92#define _ALL_SOURCE 1
93#endif
94#else /* __MINGW32__ */
95/* pull in Windows compatibility stuff */
96#include "compat/mingw.h"
97#endif /* __MINGW32__ */
98
99#ifndef NO_ICONV
100#include <iconv.h>
101#endif
102
103/* On most systems <limits.h> would have given us this, but
104 * not on some systems (e.g. GNU/Hurd).
105 */
106#ifndef PATH_MAX
107#define PATH_MAX 4096
108#endif
109
110#ifndef PRIuMAX
111#define PRIuMAX "llu"
112#endif
113
114#ifndef PRIu32
115#define PRIu32 "u"
116#endif
117
118#ifndef PRIx32
119#define PRIx32 "x"
120#endif
121
122#ifndef PATH_SEP
123#define PATH_SEP ':'
124#endif
125
126#ifndef STRIP_EXTENSION
127#define STRIP_EXTENSION ""
128#endif
129
130#ifndef has_dos_drive_prefix
131#define has_dos_drive_prefix(path) 0
132#endif
133
134#ifndef is_dir_sep
135#define is_dir_sep(c) ((c) == '/')
136#endif
137
138#ifdef __GNUC__
139#define NORETURN __attribute__((__noreturn__))
140#else
141#define NORETURN
142#ifndef __attribute__
143#define __attribute__(x)
144#endif
145#endif
146
147/* General helper functions */
148extern void usage(const char *err) NORETURN;
149extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
150extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
151extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
152
153extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
154
155extern int prefixcmp(const char *str, const char *prefix);
156extern time_t tm_to_time_t(const struct tm *tm);
157
158static inline const char *skip_prefix(const char *str, const char *prefix)
159{
160 size_t len = strlen(prefix);
161 return strncmp(str, prefix, len) ? NULL : str + len;
162}
163
164#if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
165
166#ifndef PROT_READ
167#define PROT_READ 1
168#define PROT_WRITE 2
169#define MAP_PRIVATE 1
170#define MAP_FAILED ((void*)-1)
171#endif
172
173#define mmap git_mmap
174#define munmap git_munmap
175extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
176extern int git_munmap(void *start, size_t length);
177
178#else /* NO_MMAP || USE_WIN32_MMAP */
179
180#include <sys/mman.h>
181
182#endif /* NO_MMAP || USE_WIN32_MMAP */
183
184#ifdef NO_MMAP
185
186/* This value must be multiple of (pagesize * 2) */
187#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024)
188
189#else /* NO_MMAP */
190
191/* This value must be multiple of (pagesize * 2) */
192#define DEFAULT_PACKED_GIT_WINDOW_SIZE \
193 (sizeof(void*) >= 8 \
194 ? 1 * 1024 * 1024 * 1024 \
195 : 32 * 1024 * 1024)
196
197#endif /* NO_MMAP */
198
199#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
200#define on_disk_bytes(st) ((st).st_size)
201#else
202#define on_disk_bytes(st) ((st).st_blocks * 512)
203#endif
204
205#define DEFAULT_PACKED_GIT_LIMIT \
206 ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
207
208#ifdef NO_PREAD
209#define pread git_pread
210extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
211#endif
212/*
213 * Forward decl that will remind us if its twin in cache.h changes.
214 * This function is used in compat/pread.c. But we can't include
215 * cache.h there.
216 */
217extern ssize_t read_in_full(int fd, void *buf, size_t count);
218
219#ifdef NO_SETENV
220#define setenv gitsetenv
221extern int gitsetenv(const char *, const char *, int);
222#endif
223
224#ifdef NO_MKDTEMP
225#define mkdtemp gitmkdtemp
226extern char *gitmkdtemp(char *);
227#endif
228
229#ifdef NO_UNSETENV
230#define unsetenv gitunsetenv
231extern void gitunsetenv(const char *);
232#endif
233
234#ifdef NO_STRCASESTR
235#define strcasestr gitstrcasestr
236extern char *gitstrcasestr(const char *haystack, const char *needle);
237#endif
238
239#ifdef NO_STRLCPY
240#define strlcpy gitstrlcpy
241extern size_t gitstrlcpy(char *, const char *, size_t);
242#endif
243
244#ifdef NO_STRTOUMAX
245#define strtoumax gitstrtoumax
246extern uintmax_t gitstrtoumax(const char *, char **, int);
247#endif
248
249#ifdef NO_HSTRERROR
250#define hstrerror githstrerror
251extern const char *githstrerror(int herror);
252#endif
253
254#ifdef NO_MEMMEM
255#define memmem gitmemmem
256void *gitmemmem(const void *haystack, size_t haystacklen,
257 const void *needle, size_t needlelen);
258#endif
259
260#ifdef FREAD_READS_DIRECTORIES
261#ifdef fopen
262#undef fopen
263#endif
264#define fopen(a,b) git_fopen(a,b)
265extern FILE *git_fopen(const char*, const char*);
266#endif
267
268#ifdef SNPRINTF_RETURNS_BOGUS
269#define snprintf git_snprintf
270extern int git_snprintf(char *str, size_t maxsize,
271 const char *format, ...);
272#define vsnprintf git_vsnprintf
273extern int git_vsnprintf(char *str, size_t maxsize,
274 const char *format, va_list ap);
275#endif
276
277#ifdef __GLIBC_PREREQ
278#if __GLIBC_PREREQ(2, 1)
279#define HAVE_STRCHRNUL
280#endif
281#endif
282
283#ifndef HAVE_STRCHRNUL
284#define strchrnul gitstrchrnul
285static inline char *gitstrchrnul(const char *s, int c)
286{
287 while (*s && *s != c)
288 s++;
289 return (char *)s;
290}
291#endif
292
293/*
294 * Wrappers:
295 */
296extern char *xstrdup(const char *str);
297extern void *xmalloc(size_t size);
298extern void *xmemdupz(const void *data, size_t len);
299extern char *xstrndup(const char *str, size_t len);
300extern void *xrealloc(void *ptr, size_t size);
301extern void *xcalloc(size_t nmemb, size_t size);
302extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
303extern ssize_t xread(int fd, void *buf, size_t len);
304extern ssize_t xwrite(int fd, const void *buf, size_t len);
305extern int xdup(int fd);
306extern FILE *xfdopen(int fd, const char *mode);
307extern int xmkstemp(char *template);
308
309static inline size_t xsize_t(off_t len)
310{
311 return (size_t)len;
312}
313
314static inline int has_extension(const char *filename, const char *ext)
315{
316 size_t len = strlen(filename);
317 size_t extlen = strlen(ext);
318 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
319}
320
321/* Sane ctype - no locale, and works with signed chars */
322#undef isascii
323#undef isspace
324#undef isdigit
325#undef isalpha
326#undef isalnum
327#undef tolower
328#undef toupper
329extern unsigned char sane_ctype[256];
330#define GIT_SPACE 0x01
331#define GIT_DIGIT 0x02
332#define GIT_ALPHA 0x04
333#define GIT_GLOB_SPECIAL 0x08
334#define GIT_REGEX_SPECIAL 0x10
335#define GIT_PRINT_EXTRA 0x20
336#define GIT_PRINT 0x3E
337#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
338#define isascii(x) (((x) & ~0x7f) == 0)
339#define isspace(x) sane_istest(x,GIT_SPACE)
340#define isdigit(x) sane_istest(x,GIT_DIGIT)
341#define isalpha(x) sane_istest(x,GIT_ALPHA)
342#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
343#define isprint(x) sane_istest(x,GIT_PRINT)
344#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
345#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
346#define tolower(x) sane_case((unsigned char)(x), 0x20)
347#define toupper(x) sane_case((unsigned char)(x), 0)
348
349static inline int sane_case(int x, int high)
350{
351 if (sane_istest(x, GIT_ALPHA))
352 x = (x & ~0x20) | high;
353 return x;
354}
355
356static inline int strtoul_ui(char const *s, int base, unsigned int *result)
357{
358 unsigned long ul;
359 char *p;
360
361 errno = 0;
362 ul = strtoul(s, &p, base);
363 if (errno || *p || p == s || (unsigned int) ul != ul)
364 return -1;
365 *result = ul;
366 return 0;
367}
368
369static inline int strtol_i(char const *s, int base, int *result)
370{
371 long ul;
372 char *p;
373
374 errno = 0;
375 ul = strtol(s, &p, base);
376 if (errno || *p || p == s || (int) ul != ul)
377 return -1;
378 *result = ul;
379 return 0;
380}
381
382#ifdef INTERNAL_QSORT
383void git_qsort(void *base, size_t nmemb, size_t size,
384 int(*compar)(const void *, const void *));
385#define qsort git_qsort
386#endif
387
388#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
389# define FORCE_DIR_SET_GID S_ISGID
390#else
391# define FORCE_DIR_SET_GID 0
392#endif
393
394#ifdef NO_NSEC
395#undef USE_NSEC
396#define ST_CTIME_NSEC(st) 0
397#define ST_MTIME_NSEC(st) 0
398#else
399#ifdef USE_ST_TIMESPEC
400#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
401#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
402#else
403#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
404#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
405#endif
406#endif
407
408#endif
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
new file mode 100644
index 000000000000..6350d65f6d9e
--- /dev/null
+++ b/tools/perf/util/wrapper.c
@@ -0,0 +1,206 @@
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, int flag)
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 return xmemdupz(str, p ? p - str : len);
63}
64
65void *xrealloc(void *ptr, size_t size)
66{
67 void *ret = realloc(ptr, size);
68 if (!ret && !size)
69 ret = realloc(ptr, 1);
70 if (!ret) {
71 release_pack_memory(size, -1);
72 ret = realloc(ptr, size);
73 if (!ret && !size)
74 ret = realloc(ptr, 1);
75 if (!ret)
76 die("Out of memory, realloc failed");
77 }
78 return ret;
79}
80
81void *xcalloc(size_t nmemb, size_t size)
82{
83 void *ret = calloc(nmemb, size);
84 if (!ret && (!nmemb || !size))
85 ret = calloc(1, 1);
86 if (!ret) {
87 release_pack_memory(nmemb * size, -1);
88 ret = calloc(nmemb, size);
89 if (!ret && (!nmemb || !size))
90 ret = calloc(1, 1);
91 if (!ret)
92 die("Out of memory, calloc failed");
93 }
94 return ret;
95}
96
97void *xmmap(void *start, size_t length,
98 int prot, int flags, int fd, off_t offset)
99{
100 void *ret = mmap(start, length, prot, flags, fd, offset);
101 if (ret == MAP_FAILED) {
102 if (!length)
103 return NULL;
104 release_pack_memory(length, fd);
105 ret = mmap(start, length, prot, flags, fd, offset);
106 if (ret == MAP_FAILED)
107 die("Out of memory? mmap failed: %s", strerror(errno));
108 }
109 return ret;
110}
111
112/*
113 * xread() is the same a read(), but it automatically restarts read()
114 * operations with a recoverable error (EAGAIN and EINTR). xread()
115 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
116 */
117ssize_t xread(int fd, void *buf, size_t len)
118{
119 ssize_t nr;
120 while (1) {
121 nr = read(fd, buf, len);
122 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
123 continue;
124 return nr;
125 }
126}
127
128/*
129 * xwrite() is the same a write(), but it automatically restarts write()
130 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
131 * GUARANTEE that "len" bytes is written even if the operation is successful.
132 */
133ssize_t xwrite(int fd, const void *buf, size_t len)
134{
135 ssize_t nr;
136 while (1) {
137 nr = write(fd, buf, len);
138 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
139 continue;
140 return nr;
141 }
142}
143
144ssize_t read_in_full(int fd, void *buf, size_t count)
145{
146 char *p = buf;
147 ssize_t total = 0;
148
149 while (count > 0) {
150 ssize_t loaded = xread(fd, p, count);
151 if (loaded <= 0)
152 return total ? total : loaded;
153 count -= loaded;
154 p += loaded;
155 total += loaded;
156 }
157
158 return total;
159}
160
161ssize_t write_in_full(int fd, const void *buf, size_t count)
162{
163 const char *p = buf;
164 ssize_t total = 0;
165
166 while (count > 0) {
167 ssize_t written = xwrite(fd, p, count);
168 if (written < 0)
169 return -1;
170 if (!written) {
171 errno = ENOSPC;
172 return -1;
173 }
174 count -= written;
175 p += written;
176 total += written;
177 }
178
179 return total;
180}
181
182int xdup(int fd)
183{
184 int ret = dup(fd);
185 if (ret < 0)
186 die("dup failed: %s", strerror(errno));
187 return ret;
188}
189
190FILE *xfdopen(int fd, const char *mode)
191{
192 FILE *stream = fdopen(fd, mode);
193 if (stream == NULL)
194 die("Out of memory? fdopen failed: %s", strerror(errno));
195 return stream;
196}
197
198int xmkstemp(char *template)
199{
200 int fd;
201
202 fd = mkstemp(template);
203 if (fd < 0)
204 die("Unable to create temporary file: %s", strerror(errno));
205 return fd;
206}