aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-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/Makefile929
-rw-r--r--tools/perf/builtin-annotate.c1355
-rw-r--r--tools/perf/builtin-help.c461
-rw-r--r--tools/perf/builtin-list.c20
-rw-r--r--tools/perf/builtin-record.c544
-rw-r--r--tools/perf/builtin-report.c1291
-rw-r--r--tools/perf/builtin-stat.c339
-rw-r--r--tools/perf/builtin-top.c692
-rw-r--r--tools/perf/builtin.h26
-rw-r--r--tools/perf/command-list.txt10
-rw-r--r--tools/perf/design.txt442
-rw-r--r--tools/perf/perf.c428
-rw-r--r--tools/perf/perf.h67
-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.c26
-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.c574
-rw-r--r--tools/perf/util/symbol.h47
-rw-r--r--tools/perf/util/usage.c80
-rw-r--r--tools/perf/util/util.h410
-rw-r--r--tools/perf/util/wrapper.c206
69 files changed, 15209 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..0cbd5d6874ec
--- /dev/null
+++ b/tools/perf/Makefile
@@ -0,0 +1,929 @@
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# CFLAGS and LDFLAGS are for the users to override from the command line.
161
162CFLAGS = -ggdb3 -Wall -Werror -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -O6
163LDFLAGS = -lpthread -lrt -lelf
164ALL_CFLAGS = $(CFLAGS)
165ALL_LDFLAGS = $(LDFLAGS)
166STRIP ?= strip
167
168# Among the variables below, these:
169# perfexecdir
170# template_dir
171# mandir
172# infodir
173# htmldir
174# ETC_PERFCONFIG (but not sysconfdir)
175# can be specified as a relative path some/where/else;
176# this is interpreted as relative to $(prefix) and "perf" at
177# runtime figures out where they are based on the path to the executable.
178# This can help installing the suite in a relocatable way.
179
180prefix = $(HOME)
181bindir_relative = bin
182bindir = $(prefix)/$(bindir_relative)
183mandir = share/man
184infodir = share/info
185perfexecdir = libexec/perf-core
186sharedir = $(prefix)/share
187template_dir = share/perf-core/templates
188htmldir = share/doc/perf-doc
189ifeq ($(prefix),/usr)
190sysconfdir = /etc
191ETC_PERFCONFIG = $(sysconfdir)/perfconfig
192else
193sysconfdir = $(prefix)/etc
194ETC_PERFCONFIG = etc/perfconfig
195endif
196lib = lib
197# DESTDIR=
198
199export prefix bindir sharedir sysconfdir
200
201CC = gcc
202AR = ar
203RM = rm -f
204TAR = tar
205FIND = find
206INSTALL = install
207RPMBUILD = rpmbuild
208PTHREAD_LIBS = -lpthread
209
210# sparse is architecture-neutral, which means that we need to tell it
211# explicitly what architecture to check for. Fix this up for yours..
212SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
213
214
215
216### --- END CONFIGURATION SECTION ---
217
218# Those must not be GNU-specific; they are shared with perl/ which may
219# be built by a different compiler. (Note that this is an artifact now
220# but it still might be nice to keep that distinction.)
221BASIC_CFLAGS =
222BASIC_LDFLAGS =
223
224# Guard against environment variables
225BUILTIN_OBJS =
226BUILT_INS =
227COMPAT_CFLAGS =
228COMPAT_OBJS =
229LIB_H =
230LIB_OBJS =
231SCRIPT_PERL =
232SCRIPT_SH =
233TEST_PROGRAMS =
234
235#
236# No scripts right now:
237#
238
239# SCRIPT_SH += perf-am.sh
240
241#
242# No Perl scripts right now:
243#
244
245# SCRIPT_PERL += perf-add--interactive.perl
246
247SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
248 $(patsubst %.perl,%,$(SCRIPT_PERL))
249
250# Empty...
251EXTRA_PROGRAMS =
252
253# ... and all the rest that could be moved out of bindir to perfexecdir
254PROGRAMS += $(EXTRA_PROGRAMS)
255
256#
257# Single 'perf' binary right now:
258#
259PROGRAMS += perf
260
261# List built-in command $C whose implementation cmd_$C() is not in
262# builtin-$C.o but is linked in as part of some other command.
263#
264# None right now:
265#
266# BUILT_INS += perf-init $X
267
268# what 'all' will build and 'install' will install, in perfexecdir
269ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
270
271# what 'all' will build but not install in perfexecdir
272OTHER_PROGRAMS = perf$X
273
274# Set paths to tools early so that they can be used for version tests.
275ifndef SHELL_PATH
276 SHELL_PATH = /bin/sh
277endif
278ifndef PERL_PATH
279 PERL_PATH = /usr/bin/perl
280endif
281
282export PERL_PATH
283
284LIB_FILE=libperf.a
285
286LIB_H += ../../include/linux/perf_counter.h
287LIB_H += perf.h
288LIB_H += util/list.h
289LIB_H += util/rbtree.h
290LIB_H += util/levenshtein.h
291LIB_H += util/parse-options.h
292LIB_H += util/parse-events.h
293LIB_H += util/quote.h
294LIB_H += util/util.h
295LIB_H += util/help.h
296LIB_H += util/strbuf.h
297LIB_H += util/string.h
298LIB_H += util/run-command.h
299LIB_H += util/sigchain.h
300LIB_H += util/symbol.h
301LIB_H += util/color.h
302
303LIB_OBJS += util/abspath.o
304LIB_OBJS += util/alias.o
305LIB_OBJS += util/config.o
306LIB_OBJS += util/ctype.o
307LIB_OBJS += util/environment.o
308LIB_OBJS += util/exec_cmd.o
309LIB_OBJS += util/help.o
310LIB_OBJS += util/levenshtein.o
311LIB_OBJS += util/parse-options.o
312LIB_OBJS += util/parse-events.o
313LIB_OBJS += util/path.o
314LIB_OBJS += util/rbtree.o
315LIB_OBJS += util/run-command.o
316LIB_OBJS += util/quote.o
317LIB_OBJS += util/strbuf.o
318LIB_OBJS += util/string.o
319LIB_OBJS += util/usage.o
320LIB_OBJS += util/wrapper.o
321LIB_OBJS += util/sigchain.o
322LIB_OBJS += util/symbol.o
323LIB_OBJS += util/color.o
324LIB_OBJS += util/pager.o
325
326BUILTIN_OBJS += builtin-annotate.o
327BUILTIN_OBJS += builtin-help.o
328BUILTIN_OBJS += builtin-list.o
329BUILTIN_OBJS += builtin-record.o
330BUILTIN_OBJS += builtin-report.o
331BUILTIN_OBJS += builtin-stat.o
332BUILTIN_OBJS += builtin-top.o
333
334PERFLIBS = $(LIB_FILE)
335EXTLIBS =
336
337#
338# Platform specific tweaks
339#
340
341# We choose to avoid "if .. else if .. else .. endif endif"
342# because maintaining the nesting to match is a pain. If
343# we had "elif" things would have been much nicer...
344
345-include config.mak.autogen
346-include config.mak
347
348ifeq ($(uname_S),Darwin)
349 ifndef NO_FINK
350 ifeq ($(shell test -d /sw/lib && echo y),y)
351 BASIC_CFLAGS += -I/sw/include
352 BASIC_LDFLAGS += -L/sw/lib
353 endif
354 endif
355 ifndef NO_DARWIN_PORTS
356 ifeq ($(shell test -d /opt/local/lib && echo y),y)
357 BASIC_CFLAGS += -I/opt/local/include
358 BASIC_LDFLAGS += -L/opt/local/lib
359 endif
360 endif
361 PTHREAD_LIBS =
362endif
363
364ifndef CC_LD_DYNPATH
365 ifdef NO_R_TO_GCC_LINKER
366 # Some gcc does not accept and pass -R to the linker to specify
367 # the runtime dynamic library path.
368 CC_LD_DYNPATH = -Wl,-rpath,
369 else
370 CC_LD_DYNPATH = -R
371 endif
372endif
373
374ifdef ZLIB_PATH
375 BASIC_CFLAGS += -I$(ZLIB_PATH)/include
376 EXTLIBS += -L$(ZLIB_PATH)/$(lib) $(CC_LD_DYNPATH)$(ZLIB_PATH)/$(lib)
377endif
378EXTLIBS += -lz
379
380ifdef NEEDS_SOCKET
381 EXTLIBS += -lsocket
382endif
383ifdef NEEDS_NSL
384 EXTLIBS += -lnsl
385endif
386ifdef NO_D_TYPE_IN_DIRENT
387 BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
388endif
389ifdef NO_D_INO_IN_DIRENT
390 BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
391endif
392ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
393 BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
394endif
395ifdef USE_NSEC
396 BASIC_CFLAGS += -DUSE_NSEC
397endif
398ifdef USE_ST_TIMESPEC
399 BASIC_CFLAGS += -DUSE_ST_TIMESPEC
400endif
401ifdef NO_NSEC
402 BASIC_CFLAGS += -DNO_NSEC
403endif
404ifdef NO_C99_FORMAT
405 BASIC_CFLAGS += -DNO_C99_FORMAT
406endif
407ifdef SNPRINTF_RETURNS_BOGUS
408 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
409 COMPAT_OBJS += compat/snprintf.o
410endif
411ifdef FREAD_READS_DIRECTORIES
412 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
413 COMPAT_OBJS += compat/fopen.o
414endif
415ifdef NO_SYMLINK_HEAD
416 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
417endif
418ifdef NO_STRCASESTR
419 COMPAT_CFLAGS += -DNO_STRCASESTR
420 COMPAT_OBJS += compat/strcasestr.o
421endif
422ifdef NO_STRTOUMAX
423 COMPAT_CFLAGS += -DNO_STRTOUMAX
424 COMPAT_OBJS += compat/strtoumax.o
425endif
426ifdef NO_STRTOULL
427 COMPAT_CFLAGS += -DNO_STRTOULL
428endif
429ifdef NO_SETENV
430 COMPAT_CFLAGS += -DNO_SETENV
431 COMPAT_OBJS += compat/setenv.o
432endif
433ifdef NO_MKDTEMP
434 COMPAT_CFLAGS += -DNO_MKDTEMP
435 COMPAT_OBJS += compat/mkdtemp.o
436endif
437ifdef NO_UNSETENV
438 COMPAT_CFLAGS += -DNO_UNSETENV
439 COMPAT_OBJS += compat/unsetenv.o
440endif
441ifdef NO_SYS_SELECT_H
442 BASIC_CFLAGS += -DNO_SYS_SELECT_H
443endif
444ifdef NO_MMAP
445 COMPAT_CFLAGS += -DNO_MMAP
446 COMPAT_OBJS += compat/mmap.o
447else
448 ifdef USE_WIN32_MMAP
449 COMPAT_CFLAGS += -DUSE_WIN32_MMAP
450 COMPAT_OBJS += compat/win32mmap.o
451 endif
452endif
453ifdef NO_PREAD
454 COMPAT_CFLAGS += -DNO_PREAD
455 COMPAT_OBJS += compat/pread.o
456endif
457ifdef NO_FAST_WORKING_DIRECTORY
458 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
459endif
460ifdef NO_TRUSTABLE_FILEMODE
461 BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
462endif
463ifdef NO_IPV6
464 BASIC_CFLAGS += -DNO_IPV6
465endif
466ifdef NO_UINTMAX_T
467 BASIC_CFLAGS += -Duintmax_t=uint32_t
468endif
469ifdef NO_SOCKADDR_STORAGE
470ifdef NO_IPV6
471 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
472else
473 BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
474endif
475endif
476ifdef NO_INET_NTOP
477 LIB_OBJS += compat/inet_ntop.o
478endif
479ifdef NO_INET_PTON
480 LIB_OBJS += compat/inet_pton.o
481endif
482
483ifdef NO_ICONV
484 BASIC_CFLAGS += -DNO_ICONV
485endif
486
487ifdef OLD_ICONV
488 BASIC_CFLAGS += -DOLD_ICONV
489endif
490
491ifdef NO_DEFLATE_BOUND
492 BASIC_CFLAGS += -DNO_DEFLATE_BOUND
493endif
494
495ifdef PPC_SHA1
496 SHA1_HEADER = "ppc/sha1.h"
497 LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
498else
499ifdef ARM_SHA1
500 SHA1_HEADER = "arm/sha1.h"
501 LIB_OBJS += arm/sha1.o arm/sha1_arm.o
502else
503ifdef MOZILLA_SHA1
504 SHA1_HEADER = "mozilla-sha1/sha1.h"
505 LIB_OBJS += mozilla-sha1/sha1.o
506else
507 SHA1_HEADER = <openssl/sha.h>
508 EXTLIBS += $(LIB_4_CRYPTO)
509endif
510endif
511endif
512ifdef NO_PERL_MAKEMAKER
513 export NO_PERL_MAKEMAKER
514endif
515ifdef NO_HSTRERROR
516 COMPAT_CFLAGS += -DNO_HSTRERROR
517 COMPAT_OBJS += compat/hstrerror.o
518endif
519ifdef NO_MEMMEM
520 COMPAT_CFLAGS += -DNO_MEMMEM
521 COMPAT_OBJS += compat/memmem.o
522endif
523ifdef INTERNAL_QSORT
524 COMPAT_CFLAGS += -DINTERNAL_QSORT
525 COMPAT_OBJS += compat/qsort.o
526endif
527ifdef RUNTIME_PREFIX
528 COMPAT_CFLAGS += -DRUNTIME_PREFIX
529endif
530
531ifdef DIR_HAS_BSD_GROUP_SEMANTICS
532 COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
533endif
534ifdef NO_EXTERNAL_GREP
535 BASIC_CFLAGS += -DNO_EXTERNAL_GREP
536endif
537
538ifeq ($(PERL_PATH),)
539NO_PERL=NoThanks
540endif
541
542QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
543QUIET_SUBDIR1 =
544
545ifneq ($(findstring $(MAKEFLAGS),w),w)
546PRINT_DIR = --no-print-directory
547else # "make -w"
548NO_SUBDIR = :
549endif
550
551ifneq ($(findstring $(MAKEFLAGS),s),s)
552ifndef V
553 QUIET_CC = @echo ' ' CC $@;
554 QUIET_AR = @echo ' ' AR $@;
555 QUIET_LINK = @echo ' ' LINK $@;
556 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
557 QUIET_GEN = @echo ' ' GEN $@;
558 QUIET_SUBDIR0 = +@subdir=
559 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
560 $(MAKE) $(PRINT_DIR) -C $$subdir
561 export V
562 export QUIET_GEN
563 export QUIET_BUILT_IN
564endif
565endif
566
567ifdef ASCIIDOC8
568 export ASCIIDOC8
569endif
570
571# Shell quote (do not use $(call) to accommodate ancient setups);
572
573SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
574ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
575
576DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
577bindir_SQ = $(subst ','\'',$(bindir))
578bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
579mandir_SQ = $(subst ','\'',$(mandir))
580infodir_SQ = $(subst ','\'',$(infodir))
581perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
582template_dir_SQ = $(subst ','\'',$(template_dir))
583htmldir_SQ = $(subst ','\'',$(htmldir))
584prefix_SQ = $(subst ','\'',$(prefix))
585
586SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
587PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
588
589LIBS = $(PERFLIBS) $(EXTLIBS)
590
591BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
592 $(COMPAT_CFLAGS)
593LIB_OBJS += $(COMPAT_OBJS)
594
595ALL_CFLAGS += $(BASIC_CFLAGS)
596ALL_LDFLAGS += $(BASIC_LDFLAGS)
597
598export TAR INSTALL DESTDIR SHELL_PATH
599
600
601### Build rules
602
603SHELL = $(SHELL_PATH)
604
605all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS
606ifneq (,$X)
607 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
608endif
609
610all::
611
612please_set_SHELL_PATH_to_a_more_modern_shell:
613 @$$(:)
614
615shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
616
617strip: $(PROGRAMS) perf$X
618 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) perf$X
619
620perf.o: perf.c common-cmds.h PERF-CFLAGS
621 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
622 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
623 $(ALL_CFLAGS) -c $(filter %.c,$^)
624
625perf$X: perf.o $(BUILTIN_OBJS) $(PERFLIBS)
626 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ perf.o \
627 $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
628
629builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS
630 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
631 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
632 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
633 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
634
635$(BUILT_INS): perf$X
636 $(QUIET_BUILT_IN)$(RM) $@ && \
637 ln perf$X $@ 2>/dev/null || \
638 ln -s perf$X $@ 2>/dev/null || \
639 cp perf$X $@
640
641common-cmds.h: util/generate-cmdlist.sh command-list.txt
642
643common-cmds.h: $(wildcard Documentation/perf-*.txt)
644 $(QUIET_GEN)util/generate-cmdlist.sh > $@+ && mv $@+ $@
645
646$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
647 $(QUIET_GEN)$(RM) $@ $@+ && \
648 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
649 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
650 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
651 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
652 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
653 $@.sh >$@+ && \
654 chmod +x $@+ && \
655 mv $@+ $@
656
657configure: configure.ac
658 $(QUIET_GEN)$(RM) $@ $<+ && \
659 sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
660 $< > $<+ && \
661 autoconf -o $@ $<+ && \
662 $(RM) $<+
663
664# These can record PERF_VERSION
665perf.o perf.spec \
666 $(patsubst %.sh,%,$(SCRIPT_SH)) \
667 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
668 : PERF-VERSION-FILE
669
670%.o: %.c PERF-CFLAGS
671 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
672%.s: %.c PERF-CFLAGS
673 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
674%.o: %.S
675 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
676
677util/exec_cmd.o: util/exec_cmd.c PERF-CFLAGS
678 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
679 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
680 '-DBINDIR="$(bindir_relative_SQ)"' \
681 '-DPREFIX="$(prefix_SQ)"' \
682 $<
683
684builtin-init-db.o: builtin-init-db.c PERF-CFLAGS
685 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
686
687util/config.o: util/config.c PERF-CFLAGS
688 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
689
690perf-%$X: %.o $(PERFLIBS)
691 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
692
693$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
694$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
695builtin-revert.o wt-status.o: wt-status.h
696
697$(LIB_FILE): $(LIB_OBJS)
698 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
699
700doc:
701 $(MAKE) -C Documentation all
702
703man:
704 $(MAKE) -C Documentation man
705
706html:
707 $(MAKE) -C Documentation html
708
709info:
710 $(MAKE) -C Documentation info
711
712pdf:
713 $(MAKE) -C Documentation pdf
714
715TAGS:
716 $(RM) TAGS
717 $(FIND) . -name '*.[hcS]' -print | xargs etags -a
718
719tags:
720 $(RM) tags
721 $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
722
723cscope:
724 $(RM) cscope*
725 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
726
727### Detect prefix changes
728TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
729 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
730
731PERF-CFLAGS: .FORCE-PERF-CFLAGS
732 @FLAGS='$(TRACK_CFLAGS)'; \
733 if test x"$$FLAGS" != x"`cat PERF-CFLAGS 2>/dev/null`" ; then \
734 echo 1>&2 " * new build flags or prefix"; \
735 echo "$$FLAGS" >PERF-CFLAGS; \
736 fi
737
738# We need to apply sq twice, once to protect from the shell
739# that runs PERF-BUILD-OPTIONS, and then again to protect it
740# and the first level quoting from the shell that runs "echo".
741PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
742 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
743 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
744 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
745 @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
746
747### Testing rules
748
749#
750# None right now:
751#
752# TEST_PROGRAMS += test-something$X
753
754all:: $(TEST_PROGRAMS)
755
756# GNU make supports exporting all variables by "export" without parameters.
757# However, the environment gets quite big, and some programs have problems
758# with that.
759
760export NO_SVN_TESTS
761
762check: common-cmds.h
763 if sparse; \
764 then \
765 for i in *.c */*.c; \
766 do \
767 sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
768 done; \
769 else \
770 echo 2>&1 "Did you mean 'make test'?"; \
771 exit 1; \
772 fi
773
774remove-dashes:
775 ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
776
777### Installation rules
778
779ifneq ($(filter /%,$(firstword $(template_dir))),)
780template_instdir = $(template_dir)
781else
782template_instdir = $(prefix)/$(template_dir)
783endif
784export template_instdir
785
786ifneq ($(filter /%,$(firstword $(perfexecdir))),)
787perfexec_instdir = $(perfexecdir)
788else
789perfexec_instdir = $(prefix)/$(perfexecdir)
790endif
791perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
792export perfexec_instdir
793
794install: all
795 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
796 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
797ifdef BUILT_INS
798 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
799 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
800ifneq (,$X)
801 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
802endif
803endif
804
805install-doc:
806 $(MAKE) -C Documentation install
807
808install-man:
809 $(MAKE) -C Documentation install-man
810
811install-html:
812 $(MAKE) -C Documentation install-html
813
814install-info:
815 $(MAKE) -C Documentation install-info
816
817install-pdf:
818 $(MAKE) -C Documentation install-pdf
819
820quick-install-doc:
821 $(MAKE) -C Documentation quick-install
822
823quick-install-man:
824 $(MAKE) -C Documentation quick-install-man
825
826quick-install-html:
827 $(MAKE) -C Documentation quick-install-html
828
829
830### Maintainer's dist rules
831#
832# None right now
833#
834#
835# perf.spec: perf.spec.in
836# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+
837# mv $@+ $@
838#
839# PERF_TARNAME=perf-$(PERF_VERSION)
840# dist: perf.spec perf-archive$(X) configure
841# ./perf-archive --format=tar \
842# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar
843# @mkdir -p $(PERF_TARNAME)
844# @cp perf.spec configure $(PERF_TARNAME)
845# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version
846# $(TAR) rf $(PERF_TARNAME).tar \
847# $(PERF_TARNAME)/perf.spec \
848# $(PERF_TARNAME)/configure \
849# $(PERF_TARNAME)/version
850# @$(RM) -r $(PERF_TARNAME)
851# gzip -f -9 $(PERF_TARNAME).tar
852#
853# htmldocs = perf-htmldocs-$(PERF_VERSION)
854# manpages = perf-manpages-$(PERF_VERSION)
855# dist-doc:
856# $(RM) -r .doc-tmp-dir
857# mkdir .doc-tmp-dir
858# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
859# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
860# gzip -n -9 -f $(htmldocs).tar
861# :
862# $(RM) -r .doc-tmp-dir
863# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
864# $(MAKE) -C Documentation DESTDIR=./ \
865# man1dir=../.doc-tmp-dir/man1 \
866# man5dir=../.doc-tmp-dir/man5 \
867# man7dir=../.doc-tmp-dir/man7 \
868# install
869# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
870# gzip -n -9 -f $(manpages).tar
871# $(RM) -r .doc-tmp-dir
872#
873# rpm: dist
874# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz
875
876### Cleaning rules
877
878distclean: clean
879# $(RM) configure
880
881clean:
882 $(RM) *.o */*.o $(LIB_FILE)
883 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
884 $(RM) $(TEST_PROGRAMS)
885 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
886 $(RM) -r autom4te.cache
887 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
888 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
889 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
890 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
891 $(MAKE) -C Documentation/ clean
892 $(RM) PERF-VERSION-FILE PERF-CFLAGS PERF-BUILD-OPTIONS
893
894.PHONY: all install clean strip
895.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
896.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
897.PHONY: .FORCE-PERF-BUILD-OPTIONS
898
899### Make sure built-ins do not have dups and listed in perf.c
900#
901check-builtins::
902 ./check-builtins.sh
903
904### Test suite coverage testing
905#
906# None right now
907#
908# .PHONY: coverage coverage-clean coverage-build coverage-report
909#
910# coverage:
911# $(MAKE) coverage-build
912# $(MAKE) coverage-report
913#
914# coverage-clean:
915# rm -f *.gcda *.gcno
916#
917# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
918# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
919#
920# coverage-build: coverage-clean
921# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
922# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
923# -j1 test
924#
925# coverage-report:
926# gcov -b *.c */*.c
927# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \
928# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
929# | tee coverage-untested-functions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
new file mode 100644
index 000000000000..116a3978b44c
--- /dev/null
+++ b/tools/perf/builtin-annotate.c
@@ -0,0 +1,1355 @@
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
28static char const *input_name = "perf.data";
29static char *vmlinux = NULL;
30
31static char default_sort_order[] = "comm,symbol";
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
40static int verbose;
41
42static unsigned long page_size;
43static unsigned long mmap_window = 32;
44
45struct ip_event {
46 struct perf_event_header header;
47 __u64 ip;
48 __u32 pid, tid;
49};
50
51struct mmap_event {
52 struct perf_event_header header;
53 __u32 pid, tid;
54 __u64 start;
55 __u64 len;
56 __u64 pgoff;
57 char filename[PATH_MAX];
58};
59
60struct comm_event {
61 struct perf_event_header header;
62 __u32 pid, tid;
63 char comm[16];
64};
65
66struct fork_event {
67 struct perf_event_header header;
68 __u32 pid, ppid;
69};
70
71struct period_event {
72 struct perf_event_header header;
73 __u64 time;
74 __u64 id;
75 __u64 sample_period;
76};
77
78typedef union event_union {
79 struct perf_event_header header;
80 struct ip_event ip;
81 struct mmap_event mmap;
82 struct comm_event comm;
83 struct fork_event fork;
84 struct period_event period;
85} event_t;
86
87static LIST_HEAD(dsos);
88static struct dso *kernel_dso;
89static struct dso *vdso;
90
91
92static void dsos__add(struct dso *dso)
93{
94 list_add_tail(&dso->node, &dsos);
95}
96
97static struct dso *dsos__find(const char *name)
98{
99 struct dso *pos;
100
101 list_for_each_entry(pos, &dsos, node)
102 if (strcmp(pos->name, name) == 0)
103 return pos;
104 return NULL;
105}
106
107static struct dso *dsos__findnew(const char *name)
108{
109 struct dso *dso = dsos__find(name);
110 int nr;
111
112 if (dso)
113 return dso;
114
115 dso = dso__new(name, 0);
116 if (!dso)
117 goto out_delete_dso;
118
119 nr = dso__load(dso, NULL, verbose);
120 if (nr < 0) {
121 if (verbose)
122 fprintf(stderr, "Failed to open: %s\n", name);
123 goto out_delete_dso;
124 }
125 if (!nr && verbose) {
126 fprintf(stderr,
127 "No symbols found in: %s, maybe install a debug package?\n",
128 name);
129 }
130
131 dsos__add(dso);
132
133 return dso;
134
135out_delete_dso:
136 dso__delete(dso);
137 return NULL;
138}
139
140static void dsos__fprintf(FILE *fp)
141{
142 struct dso *pos;
143
144 list_for_each_entry(pos, &dsos, node)
145 dso__fprintf(pos, fp);
146}
147
148static struct symbol *vdso__find_symbol(struct dso *dso, uint64_t ip)
149{
150 return dso__find_symbol(kernel_dso, ip);
151}
152
153static int load_kernel(void)
154{
155 int err;
156
157 kernel_dso = dso__new("[kernel]", 0);
158 if (!kernel_dso)
159 return -1;
160
161 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
162 if (err) {
163 dso__delete(kernel_dso);
164 kernel_dso = NULL;
165 } else
166 dsos__add(kernel_dso);
167
168 vdso = dso__new("[vdso]", 0);
169 if (!vdso)
170 return -1;
171
172 vdso->find_symbol = vdso__find_symbol;
173
174 dsos__add(vdso);
175
176 return err;
177}
178
179struct map {
180 struct list_head node;
181 uint64_t start;
182 uint64_t end;
183 uint64_t pgoff;
184 uint64_t (*map_ip)(struct map *, uint64_t);
185 struct dso *dso;
186};
187
188static uint64_t map__map_ip(struct map *map, uint64_t ip)
189{
190 return ip - map->start + map->pgoff;
191}
192
193static uint64_t vdso__map_ip(struct map *map, uint64_t ip)
194{
195 return ip;
196}
197
198static struct map *map__new(struct mmap_event *event)
199{
200 struct map *self = malloc(sizeof(*self));
201
202 if (self != NULL) {
203 const char *filename = event->filename;
204
205 self->start = event->start;
206 self->end = event->start + event->len;
207 self->pgoff = event->pgoff;
208
209 self->dso = dsos__findnew(filename);
210 if (self->dso == NULL)
211 goto out_delete;
212
213 if (self->dso == vdso)
214 self->map_ip = vdso__map_ip;
215 else
216 self->map_ip = map__map_ip;
217 }
218 return self;
219out_delete:
220 free(self);
221 return NULL;
222}
223
224static struct map *map__clone(struct map *self)
225{
226 struct map *map = malloc(sizeof(*self));
227
228 if (!map)
229 return NULL;
230
231 memcpy(map, self, sizeof(*self));
232
233 return map;
234}
235
236static int map__overlap(struct map *l, struct map *r)
237{
238 if (l->start > r->start) {
239 struct map *t = l;
240 l = r;
241 r = t;
242 }
243
244 if (l->end > r->start)
245 return 1;
246
247 return 0;
248}
249
250static size_t map__fprintf(struct map *self, FILE *fp)
251{
252 return fprintf(fp, " %"PRIx64"-%"PRIx64" %"PRIx64" %s\n",
253 self->start, self->end, self->pgoff, self->dso->name);
254}
255
256
257struct thread {
258 struct rb_node rb_node;
259 struct list_head maps;
260 pid_t pid;
261 char *comm;
262};
263
264static struct thread *thread__new(pid_t pid)
265{
266 struct thread *self = malloc(sizeof(*self));
267
268 if (self != NULL) {
269 self->pid = pid;
270 self->comm = malloc(32);
271 if (self->comm)
272 snprintf(self->comm, 32, ":%d", self->pid);
273 INIT_LIST_HEAD(&self->maps);
274 }
275
276 return self;
277}
278
279static int thread__set_comm(struct thread *self, const char *comm)
280{
281 if (self->comm)
282 free(self->comm);
283 self->comm = strdup(comm);
284 return self->comm ? 0 : -ENOMEM;
285}
286
287static size_t thread__fprintf(struct thread *self, FILE *fp)
288{
289 struct map *pos;
290 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
291
292 list_for_each_entry(pos, &self->maps, node)
293 ret += map__fprintf(pos, fp);
294
295 return ret;
296}
297
298
299static struct rb_root threads;
300static struct thread *last_match;
301
302static struct thread *threads__findnew(pid_t pid)
303{
304 struct rb_node **p = &threads.rb_node;
305 struct rb_node *parent = NULL;
306 struct thread *th;
307
308 /*
309 * Font-end cache - PID lookups come in blocks,
310 * so most of the time we dont have to look up
311 * the full rbtree:
312 */
313 if (last_match && last_match->pid == pid)
314 return last_match;
315
316 while (*p != NULL) {
317 parent = *p;
318 th = rb_entry(parent, struct thread, rb_node);
319
320 if (th->pid == pid) {
321 last_match = th;
322 return th;
323 }
324
325 if (pid < th->pid)
326 p = &(*p)->rb_left;
327 else
328 p = &(*p)->rb_right;
329 }
330
331 th = thread__new(pid);
332 if (th != NULL) {
333 rb_link_node(&th->rb_node, parent, p);
334 rb_insert_color(&th->rb_node, &threads);
335 last_match = th;
336 }
337
338 return th;
339}
340
341static void thread__insert_map(struct thread *self, struct map *map)
342{
343 struct map *pos, *tmp;
344
345 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
346 if (map__overlap(pos, map)) {
347 list_del_init(&pos->node);
348 /* XXX leaks dsos */
349 free(pos);
350 }
351 }
352
353 list_add_tail(&map->node, &self->maps);
354}
355
356static int thread__fork(struct thread *self, struct thread *parent)
357{
358 struct map *map;
359
360 if (self->comm)
361 free(self->comm);
362 self->comm = strdup(parent->comm);
363 if (!self->comm)
364 return -ENOMEM;
365
366 list_for_each_entry(map, &parent->maps, node) {
367 struct map *new = map__clone(map);
368 if (!new)
369 return -ENOMEM;
370 thread__insert_map(self, new);
371 }
372
373 return 0;
374}
375
376static struct map *thread__find_map(struct thread *self, uint64_t ip)
377{
378 struct map *pos;
379
380 if (self == NULL)
381 return NULL;
382
383 list_for_each_entry(pos, &self->maps, node)
384 if (ip >= pos->start && ip <= pos->end)
385 return pos;
386
387 return NULL;
388}
389
390static size_t threads__fprintf(FILE *fp)
391{
392 size_t ret = 0;
393 struct rb_node *nd;
394
395 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
396 struct thread *pos = rb_entry(nd, struct thread, rb_node);
397
398 ret += thread__fprintf(pos, fp);
399 }
400
401 return ret;
402}
403
404/*
405 * histogram, sorted on item, collects counts
406 */
407
408static struct rb_root hist;
409
410struct hist_entry {
411 struct rb_node rb_node;
412
413 struct thread *thread;
414 struct map *map;
415 struct dso *dso;
416 struct symbol *sym;
417 uint64_t ip;
418 char level;
419
420 uint32_t count;
421};
422
423/*
424 * configurable sorting bits
425 */
426
427struct sort_entry {
428 struct list_head list;
429
430 char *header;
431
432 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
433 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
434 size_t (*print)(FILE *fp, struct hist_entry *);
435};
436
437/* --sort pid */
438
439static int64_t
440sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
441{
442 return right->thread->pid - left->thread->pid;
443}
444
445static size_t
446sort__thread_print(FILE *fp, struct hist_entry *self)
447{
448 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
449}
450
451static struct sort_entry sort_thread = {
452 .header = " Command: Pid",
453 .cmp = sort__thread_cmp,
454 .print = sort__thread_print,
455};
456
457/* --sort comm */
458
459static int64_t
460sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
461{
462 return right->thread->pid - left->thread->pid;
463}
464
465static int64_t
466sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
467{
468 char *comm_l = left->thread->comm;
469 char *comm_r = right->thread->comm;
470
471 if (!comm_l || !comm_r) {
472 if (!comm_l && !comm_r)
473 return 0;
474 else if (!comm_l)
475 return -1;
476 else
477 return 1;
478 }
479
480 return strcmp(comm_l, comm_r);
481}
482
483static size_t
484sort__comm_print(FILE *fp, struct hist_entry *self)
485{
486 return fprintf(fp, "%16s", self->thread->comm);
487}
488
489static struct sort_entry sort_comm = {
490 .header = " Command",
491 .cmp = sort__comm_cmp,
492 .collapse = sort__comm_collapse,
493 .print = sort__comm_print,
494};
495
496/* --sort dso */
497
498static int64_t
499sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
500{
501 struct dso *dso_l = left->dso;
502 struct dso *dso_r = right->dso;
503
504 if (!dso_l || !dso_r) {
505 if (!dso_l && !dso_r)
506 return 0;
507 else if (!dso_l)
508 return -1;
509 else
510 return 1;
511 }
512
513 return strcmp(dso_l->name, dso_r->name);
514}
515
516static size_t
517sort__dso_print(FILE *fp, struct hist_entry *self)
518{
519 if (self->dso)
520 return fprintf(fp, "%-25s", self->dso->name);
521
522 return fprintf(fp, "%016llx ", (__u64)self->ip);
523}
524
525static struct sort_entry sort_dso = {
526 .header = "Shared Object ",
527 .cmp = sort__dso_cmp,
528 .print = sort__dso_print,
529};
530
531/* --sort symbol */
532
533static int64_t
534sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
535{
536 uint64_t ip_l, ip_r;
537
538 if (left->sym == right->sym)
539 return 0;
540
541 ip_l = left->sym ? left->sym->start : left->ip;
542 ip_r = right->sym ? right->sym->start : right->ip;
543
544 return (int64_t)(ip_r - ip_l);
545}
546
547static size_t
548sort__sym_print(FILE *fp, struct hist_entry *self)
549{
550 size_t ret = 0;
551
552 if (verbose)
553 ret += fprintf(fp, "%#018llx ", (__u64)self->ip);
554
555 if (self->sym) {
556 ret += fprintf(fp, "[%c] %s",
557 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
558 } else {
559 ret += fprintf(fp, "%#016llx", (__u64)self->ip);
560 }
561
562 return ret;
563}
564
565static struct sort_entry sort_sym = {
566 .header = "Symbol",
567 .cmp = sort__sym_cmp,
568 .print = sort__sym_print,
569};
570
571static int sort__need_collapse = 0;
572
573struct sort_dimension {
574 char *name;
575 struct sort_entry *entry;
576 int taken;
577};
578
579static struct sort_dimension sort_dimensions[] = {
580 { .name = "pid", .entry = &sort_thread, },
581 { .name = "comm", .entry = &sort_comm, },
582 { .name = "dso", .entry = &sort_dso, },
583 { .name = "symbol", .entry = &sort_sym, },
584};
585
586static LIST_HEAD(hist_entry__sort_list);
587
588static int sort_dimension__add(char *tok)
589{
590 int i;
591
592 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
593 struct sort_dimension *sd = &sort_dimensions[i];
594
595 if (sd->taken)
596 continue;
597
598 if (strncasecmp(tok, sd->name, strlen(tok)))
599 continue;
600
601 if (sd->entry->collapse)
602 sort__need_collapse = 1;
603
604 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
605 sd->taken = 1;
606
607 return 0;
608 }
609
610 return -ESRCH;
611}
612
613static int64_t
614hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
615{
616 struct sort_entry *se;
617 int64_t cmp = 0;
618
619 list_for_each_entry(se, &hist_entry__sort_list, list) {
620 cmp = se->cmp(left, right);
621 if (cmp)
622 break;
623 }
624
625 return cmp;
626}
627
628static int64_t
629hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
630{
631 struct sort_entry *se;
632 int64_t cmp = 0;
633
634 list_for_each_entry(se, &hist_entry__sort_list, list) {
635 int64_t (*f)(struct hist_entry *, struct hist_entry *);
636
637 f = se->collapse ?: se->cmp;
638
639 cmp = f(left, right);
640 if (cmp)
641 break;
642 }
643
644 return cmp;
645}
646
647/*
648 * collect histogram counts
649 */
650static void hist_hit(struct hist_entry *he, uint64_t ip)
651{
652 unsigned int sym_size, offset;
653 struct symbol *sym = he->sym;
654
655 he->count++;
656
657 if (!sym || !sym->hist)
658 return;
659
660 sym_size = sym->end - sym->start;
661 offset = ip - sym->start;
662
663 if (offset >= sym_size)
664 return;
665
666 sym->hist_sum++;
667 sym->hist[offset]++;
668
669 if (verbose >= 3)
670 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
671 (void *)he->sym->start,
672 he->sym->name,
673 (void *)ip, ip - he->sym->start,
674 sym->hist[offset]);
675}
676
677static int
678hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
679 struct symbol *sym, uint64_t ip, char level)
680{
681 struct rb_node **p = &hist.rb_node;
682 struct rb_node *parent = NULL;
683 struct hist_entry *he;
684 struct hist_entry entry = {
685 .thread = thread,
686 .map = map,
687 .dso = dso,
688 .sym = sym,
689 .ip = ip,
690 .level = level,
691 .count = 1,
692 };
693 int cmp;
694
695 while (*p != NULL) {
696 parent = *p;
697 he = rb_entry(parent, struct hist_entry, rb_node);
698
699 cmp = hist_entry__cmp(&entry, he);
700
701 if (!cmp) {
702 hist_hit(he, ip);
703
704 return 0;
705 }
706
707 if (cmp < 0)
708 p = &(*p)->rb_left;
709 else
710 p = &(*p)->rb_right;
711 }
712
713 he = malloc(sizeof(*he));
714 if (!he)
715 return -ENOMEM;
716 *he = entry;
717 rb_link_node(&he->rb_node, parent, p);
718 rb_insert_color(&he->rb_node, &hist);
719
720 return 0;
721}
722
723static void hist_entry__free(struct hist_entry *he)
724{
725 free(he);
726}
727
728/*
729 * collapse the histogram
730 */
731
732static struct rb_root collapse_hists;
733
734static void collapse__insert_entry(struct hist_entry *he)
735{
736 struct rb_node **p = &collapse_hists.rb_node;
737 struct rb_node *parent = NULL;
738 struct hist_entry *iter;
739 int64_t cmp;
740
741 while (*p != NULL) {
742 parent = *p;
743 iter = rb_entry(parent, struct hist_entry, rb_node);
744
745 cmp = hist_entry__collapse(iter, he);
746
747 if (!cmp) {
748 iter->count += he->count;
749 hist_entry__free(he);
750 return;
751 }
752
753 if (cmp < 0)
754 p = &(*p)->rb_left;
755 else
756 p = &(*p)->rb_right;
757 }
758
759 rb_link_node(&he->rb_node, parent, p);
760 rb_insert_color(&he->rb_node, &collapse_hists);
761}
762
763static void collapse__resort(void)
764{
765 struct rb_node *next;
766 struct hist_entry *n;
767
768 if (!sort__need_collapse)
769 return;
770
771 next = rb_first(&hist);
772 while (next) {
773 n = rb_entry(next, struct hist_entry, rb_node);
774 next = rb_next(&n->rb_node);
775
776 rb_erase(&n->rb_node, &hist);
777 collapse__insert_entry(n);
778 }
779}
780
781/*
782 * reverse the map, sort on count.
783 */
784
785static struct rb_root output_hists;
786
787static void output__insert_entry(struct hist_entry *he)
788{
789 struct rb_node **p = &output_hists.rb_node;
790 struct rb_node *parent = NULL;
791 struct hist_entry *iter;
792
793 while (*p != NULL) {
794 parent = *p;
795 iter = rb_entry(parent, struct hist_entry, rb_node);
796
797 if (he->count > iter->count)
798 p = &(*p)->rb_left;
799 else
800 p = &(*p)->rb_right;
801 }
802
803 rb_link_node(&he->rb_node, parent, p);
804 rb_insert_color(&he->rb_node, &output_hists);
805}
806
807static void output__resort(void)
808{
809 struct rb_node *next;
810 struct hist_entry *n;
811 struct rb_root *tree = &hist;
812
813 if (sort__need_collapse)
814 tree = &collapse_hists;
815
816 next = rb_first(tree);
817
818 while (next) {
819 n = rb_entry(next, struct hist_entry, rb_node);
820 next = rb_next(&n->rb_node);
821
822 rb_erase(&n->rb_node, tree);
823 output__insert_entry(n);
824 }
825}
826
827static void register_idle_thread(void)
828{
829 struct thread *thread = threads__findnew(0);
830
831 if (thread == NULL ||
832 thread__set_comm(thread, "[idle]")) {
833 fprintf(stderr, "problem inserting idle task.\n");
834 exit(-1);
835 }
836}
837
838static unsigned long total = 0,
839 total_mmap = 0,
840 total_comm = 0,
841 total_fork = 0,
842 total_unknown = 0;
843
844static int
845process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
846{
847 char level;
848 int show = 0;
849 struct dso *dso = NULL;
850 struct thread *thread = threads__findnew(event->ip.pid);
851 uint64_t ip = event->ip.ip;
852 struct map *map = NULL;
853
854 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
855 (void *)(offset + head),
856 (void *)(long)(event->header.size),
857 event->header.misc,
858 event->ip.pid,
859 (void *)(long)ip);
860
861 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
862
863 if (thread == NULL) {
864 fprintf(stderr, "problem processing %d event, skipping it.\n",
865 event->header.type);
866 return -1;
867 }
868
869 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
870 show = SHOW_KERNEL;
871 level = 'k';
872
873 dso = kernel_dso;
874
875 dprintf(" ...... dso: %s\n", dso->name);
876
877 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
878
879 show = SHOW_USER;
880 level = '.';
881
882 map = thread__find_map(thread, ip);
883 if (map != NULL) {
884 ip = map->map_ip(map, ip);
885 dso = map->dso;
886 } else {
887 /*
888 * If this is outside of all known maps,
889 * and is a negative address, try to look it
890 * up in the kernel dso, as it might be a
891 * vsyscall (which executes in user-mode):
892 */
893 if ((long long)ip < 0)
894 dso = kernel_dso;
895 }
896 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
897
898 } else {
899 show = SHOW_HV;
900 level = 'H';
901 dprintf(" ...... dso: [hypervisor]\n");
902 }
903
904 if (show & show_mask) {
905 struct symbol *sym = NULL;
906
907 if (dso)
908 sym = dso->find_symbol(dso, ip);
909
910 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
911 fprintf(stderr,
912 "problem incrementing symbol count, skipping event\n");
913 return -1;
914 }
915 }
916 total++;
917
918 return 0;
919}
920
921static int
922process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
923{
924 struct thread *thread = threads__findnew(event->mmap.pid);
925 struct map *map = map__new(&event->mmap);
926
927 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
928 (void *)(offset + head),
929 (void *)(long)(event->header.size),
930 event->mmap.pid,
931 (void *)(long)event->mmap.start,
932 (void *)(long)event->mmap.len,
933 (void *)(long)event->mmap.pgoff,
934 event->mmap.filename);
935
936 if (thread == NULL || map == NULL) {
937 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
938 return 0;
939 }
940
941 thread__insert_map(thread, map);
942 total_mmap++;
943
944 return 0;
945}
946
947static int
948process_comm_event(event_t *event, unsigned long offset, unsigned long head)
949{
950 struct thread *thread = threads__findnew(event->comm.pid);
951
952 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
953 (void *)(offset + head),
954 (void *)(long)(event->header.size),
955 event->comm.comm, event->comm.pid);
956
957 if (thread == NULL ||
958 thread__set_comm(thread, event->comm.comm)) {
959 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
960 return -1;
961 }
962 total_comm++;
963
964 return 0;
965}
966
967static int
968process_fork_event(event_t *event, unsigned long offset, unsigned long head)
969{
970 struct thread *thread = threads__findnew(event->fork.pid);
971 struct thread *parent = threads__findnew(event->fork.ppid);
972
973 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n",
974 (void *)(offset + head),
975 (void *)(long)(event->header.size),
976 event->fork.pid, event->fork.ppid);
977
978 if (!thread || !parent || thread__fork(thread, parent)) {
979 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
980 return -1;
981 }
982 total_fork++;
983
984 return 0;
985}
986
987static int
988process_period_event(event_t *event, unsigned long offset, unsigned long head)
989{
990 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
991 (void *)(offset + head),
992 (void *)(long)(event->header.size),
993 event->period.time,
994 event->period.id,
995 event->period.sample_period);
996
997 return 0;
998}
999
1000static int
1001process_event(event_t *event, unsigned long offset, unsigned long head)
1002{
1003 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1004 return process_overflow_event(event, offset, head);
1005
1006 switch (event->header.type) {
1007 case PERF_EVENT_MMAP:
1008 return process_mmap_event(event, offset, head);
1009
1010 case PERF_EVENT_COMM:
1011 return process_comm_event(event, offset, head);
1012
1013 case PERF_EVENT_FORK:
1014 return process_fork_event(event, offset, head);
1015
1016 case PERF_EVENT_PERIOD:
1017 return process_period_event(event, offset, head);
1018 /*
1019 * We dont process them right now but they are fine:
1020 */
1021
1022 case PERF_EVENT_THROTTLE:
1023 case PERF_EVENT_UNTHROTTLE:
1024 return 0;
1025
1026 default:
1027 return -1;
1028 }
1029
1030 return 0;
1031}
1032
1033static int
1034parse_line(FILE *file, struct symbol *sym, uint64_t start, uint64_t len)
1035{
1036 char *line = NULL, *tmp, *tmp2;
1037 unsigned int offset;
1038 size_t line_len;
1039 __u64 line_ip;
1040 int ret;
1041 char *c;
1042
1043 if (getline(&line, &line_len, file) < 0)
1044 return -1;
1045 if (!line)
1046 return -1;
1047
1048 c = strchr(line, '\n');
1049 if (c)
1050 *c = 0;
1051
1052 line_ip = -1;
1053 offset = 0;
1054 ret = -2;
1055
1056 /*
1057 * Strip leading spaces:
1058 */
1059 tmp = line;
1060 while (*tmp) {
1061 if (*tmp != ' ')
1062 break;
1063 tmp++;
1064 }
1065
1066 if (*tmp) {
1067 /*
1068 * Parse hexa addresses followed by ':'
1069 */
1070 line_ip = strtoull(tmp, &tmp2, 16);
1071 if (*tmp2 != ':')
1072 line_ip = -1;
1073 }
1074
1075 if (line_ip != -1) {
1076 unsigned int hits = 0;
1077 double percent = 0.0;
1078 char *color = PERF_COLOR_NORMAL;
1079
1080 offset = line_ip - start;
1081 if (offset < len)
1082 hits = sym->hist[offset];
1083
1084 if (sym->hist_sum)
1085 percent = 100.0 * hits / sym->hist_sum;
1086
1087 /*
1088 * We color high-overhead entries in red, low-overhead
1089 * entries in green - and keep the middle ground normal:
1090 */
1091 if (percent >= 5.0)
1092 color = PERF_COLOR_RED;
1093 else {
1094 if (percent > 0.5)
1095 color = PERF_COLOR_GREEN;
1096 }
1097
1098 color_fprintf(stdout, color, " %7.2f", percent);
1099 printf(" : ");
1100 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line);
1101 } else {
1102 if (!*line)
1103 printf(" :\n");
1104 else
1105 printf(" : %s\n", line);
1106 }
1107
1108 return 0;
1109}
1110
1111static void annotate_sym(struct dso *dso, struct symbol *sym)
1112{
1113 char *filename = dso->name;
1114 uint64_t start, end, len;
1115 char command[PATH_MAX*2];
1116 FILE *file;
1117
1118 if (!filename)
1119 return;
1120 if (dso == kernel_dso)
1121 filename = vmlinux;
1122
1123 printf("\n------------------------------------------------\n");
1124 printf(" Percent | Source code & Disassembly of %s\n", filename);
1125 printf("------------------------------------------------\n");
1126
1127 if (verbose >= 2)
1128 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
1129
1130 start = sym->obj_start;
1131 if (!start)
1132 start = sym->start;
1133
1134 end = start + sym->end - sym->start + 1;
1135 len = sym->end - sym->start;
1136
1137 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename);
1138
1139 if (verbose >= 3)
1140 printf("doing: %s\n", command);
1141
1142 file = popen(command, "r");
1143 if (!file)
1144 return;
1145
1146 while (!feof(file)) {
1147 if (parse_line(file, sym, start, len) < 0)
1148 break;
1149 }
1150
1151 pclose(file);
1152}
1153
1154static void find_annotations(void)
1155{
1156 struct rb_node *nd;
1157 struct dso *dso;
1158 int count = 0;
1159
1160 list_for_each_entry(dso, &dsos, node) {
1161
1162 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
1163 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
1164
1165 if (sym->hist) {
1166 annotate_sym(dso, sym);
1167 count++;
1168 }
1169 }
1170 }
1171
1172 if (!count)
1173 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
1174}
1175
1176static int __cmd_annotate(void)
1177{
1178 int ret, rc = EXIT_FAILURE;
1179 unsigned long offset = 0;
1180 unsigned long head = 0;
1181 struct stat stat;
1182 event_t *event;
1183 uint32_t size;
1184 char *buf;
1185
1186 register_idle_thread();
1187
1188 input = open(input_name, O_RDONLY);
1189 if (input < 0) {
1190 perror("failed to open file");
1191 exit(-1);
1192 }
1193
1194 ret = fstat(input, &stat);
1195 if (ret < 0) {
1196 perror("failed to stat file");
1197 exit(-1);
1198 }
1199
1200 if (!stat.st_size) {
1201 fprintf(stderr, "zero-sized file, nothing to do!\n");
1202 exit(0);
1203 }
1204
1205 if (load_kernel() < 0) {
1206 perror("failed to load kernel symbols");
1207 return EXIT_FAILURE;
1208 }
1209
1210remap:
1211 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1212 MAP_SHARED, input, offset);
1213 if (buf == MAP_FAILED) {
1214 perror("failed to mmap file");
1215 exit(-1);
1216 }
1217
1218more:
1219 event = (event_t *)(buf + head);
1220
1221 size = event->header.size;
1222 if (!size)
1223 size = 8;
1224
1225 if (head + event->header.size >= page_size * mmap_window) {
1226 unsigned long shift = page_size * (head / page_size);
1227 int ret;
1228
1229 ret = munmap(buf, page_size * mmap_window);
1230 assert(ret == 0);
1231
1232 offset += shift;
1233 head -= shift;
1234 goto remap;
1235 }
1236
1237 size = event->header.size;
1238
1239 dprintf("%p [%p]: event: %d\n",
1240 (void *)(offset + head),
1241 (void *)(long)event->header.size,
1242 event->header.type);
1243
1244 if (!size || process_event(event, offset, head) < 0) {
1245
1246 dprintf("%p [%p]: skipping unknown header type: %d\n",
1247 (void *)(offset + head),
1248 (void *)(long)(event->header.size),
1249 event->header.type);
1250
1251 total_unknown++;
1252
1253 /*
1254 * assume we lost track of the stream, check alignment, and
1255 * increment a single u64 in the hope to catch on again 'soon'.
1256 */
1257
1258 if (unlikely(head & 7))
1259 head &= ~7ULL;
1260
1261 size = 8;
1262 }
1263
1264 head += size;
1265
1266 if (offset + head < stat.st_size)
1267 goto more;
1268
1269 rc = EXIT_SUCCESS;
1270 close(input);
1271
1272 dprintf(" IP events: %10ld\n", total);
1273 dprintf(" mmap events: %10ld\n", total_mmap);
1274 dprintf(" comm events: %10ld\n", total_comm);
1275 dprintf(" fork events: %10ld\n", total_fork);
1276 dprintf(" unknown events: %10ld\n", total_unknown);
1277
1278 if (dump_trace)
1279 return 0;
1280
1281 if (verbose >= 3)
1282 threads__fprintf(stdout);
1283
1284 if (verbose >= 2)
1285 dsos__fprintf(stdout);
1286
1287 collapse__resort();
1288 output__resort();
1289
1290 find_annotations();
1291
1292 return rc;
1293}
1294
1295static const char * const annotate_usage[] = {
1296 "perf annotate [<options>] <command>",
1297 NULL
1298};
1299
1300static const struct option options[] = {
1301 OPT_STRING('i', "input", &input_name, "file",
1302 "input file name"),
1303 OPT_STRING('s', "symbol", &sym_hist_filter, "file",
1304 "symbol to annotate"),
1305 OPT_BOOLEAN('v', "verbose", &verbose,
1306 "be more verbose (show symbol address, etc)"),
1307 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1308 "dump raw trace in ASCII"),
1309 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1310 OPT_END()
1311};
1312
1313static void setup_sorting(void)
1314{
1315 char *tmp, *tok, *str = strdup(sort_order);
1316
1317 for (tok = strtok_r(str, ", ", &tmp);
1318 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1319 if (sort_dimension__add(tok) < 0) {
1320 error("Unknown --sort key: `%s'", tok);
1321 usage_with_options(annotate_usage, options);
1322 }
1323 }
1324
1325 free(str);
1326}
1327
1328int cmd_annotate(int argc, const char **argv, const char *prefix)
1329{
1330 symbol__init();
1331
1332 page_size = getpagesize();
1333
1334 argc = parse_options(argc, argv, options, annotate_usage, 0);
1335
1336 setup_sorting();
1337
1338 if (argc) {
1339 /*
1340 * Special case: if there's an argument left then assume tha
1341 * it's a symbol filter:
1342 */
1343 if (argc > 1)
1344 usage_with_options(annotate_usage, options);
1345
1346 sym_hist_filter = argv[0];
1347 }
1348
1349 if (!sym_hist_filter)
1350 usage_with_options(annotate_usage, options);
1351
1352 setup_pager();
1353
1354 return __cmd_annotate();
1355}
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..aeab9c4b15e4
--- /dev/null
+++ b/tools/perf/builtin-record.c
@@ -0,0 +1,544 @@
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;
40
41static long samples;
42static struct timeval last_read;
43static struct timeval this_read;
44
45static __u64 bytes_written;
46
47static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
48
49static int nr_poll;
50static int nr_cpu;
51
52struct mmap_event {
53 struct perf_event_header header;
54 __u32 pid;
55 __u32 tid;
56 __u64 start;
57 __u64 len;
58 __u64 pgoff;
59 char filename[PATH_MAX];
60};
61
62struct comm_event {
63 struct perf_event_header header;
64 __u32 pid;
65 __u32 tid;
66 char comm[16];
67};
68
69
70struct mmap_data {
71 int counter;
72 void *base;
73 unsigned int mask;
74 unsigned int prev;
75};
76
77static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
78
79static unsigned int mmap_read_head(struct mmap_data *md)
80{
81 struct perf_counter_mmap_page *pc = md->base;
82 int head;
83
84 head = pc->data_head;
85 rmb();
86
87 return head;
88}
89
90static void mmap_read(struct mmap_data *md)
91{
92 unsigned int head = mmap_read_head(md);
93 unsigned int old = md->prev;
94 unsigned char *data = md->base + page_size;
95 unsigned long size;
96 void *buf;
97 int diff;
98
99 gettimeofday(&this_read, NULL);
100
101 /*
102 * If we're further behind than half the buffer, there's a chance
103 * the writer will bite our tail and mess up the samples under us.
104 *
105 * If we somehow ended up ahead of the head, we got messed up.
106 *
107 * In either case, truncate and restart at head.
108 */
109 diff = head - old;
110 if (diff > md->mask / 2 || diff < 0) {
111 struct timeval iv;
112 unsigned long msecs;
113
114 timersub(&this_read, &last_read, &iv);
115 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
116
117 fprintf(stderr, "WARNING: failed to keep up with mmap data."
118 " Last read %lu msecs ago.\n", msecs);
119
120 /*
121 * head points to a known good entry, start there.
122 */
123 old = head;
124 }
125
126 last_read = this_read;
127
128 if (old != head)
129 samples++;
130
131 size = head - old;
132
133 if ((old & md->mask) + size != (head & md->mask)) {
134 buf = &data[old & md->mask];
135 size = md->mask + 1 - (old & md->mask);
136 old += size;
137
138 while (size) {
139 int ret = write(output, buf, size);
140
141 if (ret < 0)
142 die("failed to write");
143
144 size -= ret;
145 buf += ret;
146
147 bytes_written += ret;
148 }
149 }
150
151 buf = &data[old & md->mask];
152 size = head - old;
153 old += size;
154
155 while (size) {
156 int ret = write(output, buf, size);
157
158 if (ret < 0)
159 die("failed to write");
160
161 size -= ret;
162 buf += ret;
163
164 bytes_written += ret;
165 }
166
167 md->prev = old;
168}
169
170static volatile int done = 0;
171
172static void sig_handler(int sig)
173{
174 done = 1;
175}
176
177static void pid_synthesize_comm_event(pid_t pid, int full)
178{
179 struct comm_event comm_ev;
180 char filename[PATH_MAX];
181 char bf[BUFSIZ];
182 int fd, ret;
183 size_t size;
184 char *field, *sep;
185 DIR *tasks;
186 struct dirent dirent, *next;
187
188 snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
189
190 fd = open(filename, O_RDONLY);
191 if (fd < 0) {
192 fprintf(stderr, "couldn't open %s\n", filename);
193 exit(EXIT_FAILURE);
194 }
195 if (read(fd, bf, sizeof(bf)) < 0) {
196 fprintf(stderr, "couldn't read %s\n", filename);
197 exit(EXIT_FAILURE);
198 }
199 close(fd);
200
201 /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */
202 memset(&comm_ev, 0, sizeof(comm_ev));
203 field = strchr(bf, '(');
204 if (field == NULL)
205 goto out_failure;
206 sep = strchr(++field, ')');
207 if (sep == NULL)
208 goto out_failure;
209 size = sep - field;
210 memcpy(comm_ev.comm, field, size++);
211
212 comm_ev.pid = pid;
213 comm_ev.header.type = PERF_EVENT_COMM;
214 size = ALIGN(size, sizeof(uint64_t));
215 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
216
217 if (!full) {
218 comm_ev.tid = pid;
219
220 ret = write(output, &comm_ev, comm_ev.header.size);
221 if (ret < 0) {
222 perror("failed to write");
223 exit(-1);
224 }
225 return;
226 }
227
228 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
229
230 tasks = opendir(filename);
231 while (!readdir_r(tasks, &dirent, &next) && next) {
232 char *end;
233 pid = strtol(dirent.d_name, &end, 10);
234 if (*end)
235 continue;
236
237 comm_ev.tid = pid;
238
239 ret = write(output, &comm_ev, comm_ev.header.size);
240 if (ret < 0) {
241 perror("failed to write");
242 exit(-1);
243 }
244 }
245 closedir(tasks);
246 return;
247
248out_failure:
249 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
250 filename);
251 exit(EXIT_FAILURE);
252}
253
254static void pid_synthesize_mmap_samples(pid_t pid)
255{
256 char filename[PATH_MAX];
257 FILE *fp;
258
259 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
260
261 fp = fopen(filename, "r");
262 if (fp == NULL) {
263 fprintf(stderr, "couldn't open %s\n", filename);
264 exit(EXIT_FAILURE);
265 }
266 while (1) {
267 char bf[BUFSIZ], *pbf = bf;
268 struct mmap_event mmap_ev = {
269 .header.type = PERF_EVENT_MMAP,
270 };
271 int n;
272 size_t size;
273 if (fgets(bf, sizeof(bf), fp) == NULL)
274 break;
275
276 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
277 n = hex2u64(pbf, &mmap_ev.start);
278 if (n < 0)
279 continue;
280 pbf += n + 1;
281 n = hex2u64(pbf, &mmap_ev.len);
282 if (n < 0)
283 continue;
284 pbf += n + 3;
285 if (*pbf == 'x') { /* vm_exec */
286 char *execname = strrchr(bf, ' ');
287
288 if (execname == NULL || execname[1] != '/')
289 continue;
290
291 execname += 1;
292 size = strlen(execname);
293 execname[size - 1] = '\0'; /* Remove \n */
294 memcpy(mmap_ev.filename, execname, size);
295 size = ALIGN(size, sizeof(uint64_t));
296 mmap_ev.len -= mmap_ev.start;
297 mmap_ev.header.size = (sizeof(mmap_ev) -
298 (sizeof(mmap_ev.filename) - size));
299 mmap_ev.pid = pid;
300 mmap_ev.tid = pid;
301
302 if (write(output, &mmap_ev, mmap_ev.header.size) < 0) {
303 perror("failed to write");
304 exit(-1);
305 }
306 }
307 }
308
309 fclose(fp);
310}
311
312static void synthesize_samples(void)
313{
314 DIR *proc;
315 struct dirent dirent, *next;
316
317 proc = opendir("/proc");
318
319 while (!readdir_r(proc, &dirent, &next) && next) {
320 char *end;
321 pid_t pid;
322
323 pid = strtol(dirent.d_name, &end, 10);
324 if (*end) /* only interested in proper numerical dirents */
325 continue;
326
327 pid_synthesize_comm_event(pid, 1);
328 pid_synthesize_mmap_samples(pid);
329 }
330
331 closedir(proc);
332}
333
334static int group_fd;
335
336static void create_counter(int counter, int cpu, pid_t pid)
337{
338 struct perf_counter_attr *attr = attrs + counter;
339 int track = 1;
340
341 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD;
342 if (freq) {
343 attr->freq = 1;
344 attr->sample_freq = freq;
345 }
346 attr->mmap = track;
347 attr->comm = track;
348 attr->inherit = (cpu < 0) && inherit;
349
350 track = 0; /* only the first counter needs these */
351
352 fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
353
354 if (fd[nr_cpu][counter] < 0) {
355 int err = errno;
356
357 error("syscall returned with %d (%s)\n",
358 fd[nr_cpu][counter], strerror(err));
359 if (err == EPERM)
360 printf("Are you root?\n");
361 exit(-1);
362 }
363 assert(fd[nr_cpu][counter] >= 0);
364 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
365
366 /*
367 * First counter acts as the group leader:
368 */
369 if (group && group_fd == -1)
370 group_fd = fd[nr_cpu][counter];
371
372 event_array[nr_poll].fd = fd[nr_cpu][counter];
373 event_array[nr_poll].events = POLLIN;
374 nr_poll++;
375
376 mmap_array[nr_cpu][counter].counter = counter;
377 mmap_array[nr_cpu][counter].prev = 0;
378 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1;
379 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
380 PROT_READ, MAP_SHARED, fd[nr_cpu][counter], 0);
381 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) {
382 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
383 exit(-1);
384 }
385}
386
387static void open_counters(int cpu, pid_t pid)
388{
389 int counter;
390
391 if (pid > 0) {
392 pid_synthesize_comm_event(pid, 0);
393 pid_synthesize_mmap_samples(pid);
394 }
395
396 group_fd = -1;
397 for (counter = 0; counter < nr_counters; counter++)
398 create_counter(counter, cpu, pid);
399
400 nr_cpu++;
401}
402
403static int __cmd_record(int argc, const char **argv)
404{
405 int i, counter;
406 struct stat st;
407 pid_t pid;
408 int flags;
409 int ret;
410
411 page_size = sysconf(_SC_PAGE_SIZE);
412 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
413 assert(nr_cpus <= MAX_NR_CPUS);
414 assert(nr_cpus >= 0);
415
416 if (!stat(output_name, &st) && !force && !append_file) {
417 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
418 output_name);
419 exit(-1);
420 }
421
422 flags = O_CREAT|O_RDWR;
423 if (append_file)
424 flags |= O_APPEND;
425 else
426 flags |= O_TRUNC;
427
428 output = open(output_name, flags, S_IRUSR|S_IWUSR);
429 if (output < 0) {
430 perror("failed to create output file");
431 exit(-1);
432 }
433
434 if (!system_wide) {
435 open_counters(-1, target_pid != -1 ? target_pid : getpid());
436 } else for (i = 0; i < nr_cpus; i++)
437 open_counters(i, target_pid);
438
439 signal(SIGCHLD, sig_handler);
440 signal(SIGINT, sig_handler);
441
442 if (target_pid == -1 && argc) {
443 pid = fork();
444 if (pid < 0)
445 perror("failed to fork");
446
447 if (!pid) {
448 if (execvp(argv[0], (char **)argv)) {
449 perror(argv[0]);
450 exit(-1);
451 }
452 }
453 }
454
455 if (realtime_prio) {
456 struct sched_param param;
457
458 param.sched_priority = realtime_prio;
459 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
460 printf("Could not set realtime priority.\n");
461 exit(-1);
462 }
463 }
464
465 if (system_wide)
466 synthesize_samples();
467
468 while (!done) {
469 int hits = samples;
470
471 for (i = 0; i < nr_cpu; i++) {
472 for (counter = 0; counter < nr_counters; counter++)
473 mmap_read(&mmap_array[i][counter]);
474 }
475
476 if (hits == samples)
477 ret = poll(event_array, nr_poll, 100);
478 }
479
480 /*
481 * Approximate RIP event size: 24 bytes.
482 */
483 fprintf(stderr,
484 "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n",
485 (double)bytes_written / 1024.0 / 1024.0,
486 output_name,
487 bytes_written / 24);
488
489 return 0;
490}
491
492static const char * const record_usage[] = {
493 "perf record [<options>] [<command>]",
494 "perf record [<options>] -- <command> [<options>]",
495 NULL
496};
497
498static const struct option options[] = {
499 OPT_CALLBACK('e', "event", NULL, "event",
500 "event selector. use 'perf list' to list available events",
501 parse_events),
502 OPT_INTEGER('p', "pid", &target_pid,
503 "record events on existing pid"),
504 OPT_INTEGER('r', "realtime", &realtime_prio,
505 "collect data with this RT SCHED_FIFO priority"),
506 OPT_BOOLEAN('a', "all-cpus", &system_wide,
507 "system-wide collection from all CPUs"),
508 OPT_BOOLEAN('A', "append", &append_file,
509 "append to the output file to do incremental profiling"),
510 OPT_BOOLEAN('f', "force", &force,
511 "overwrite existing data file"),
512 OPT_LONG('c', "count", &default_interval,
513 "event period to sample"),
514 OPT_STRING('o', "output", &output_name, "file",
515 "output file name"),
516 OPT_BOOLEAN('i', "inherit", &inherit,
517 "child tasks inherit counters"),
518 OPT_INTEGER('F', "freq", &freq,
519 "profile at this frequency"),
520 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
521 "number of mmap data pages"),
522 OPT_END()
523};
524
525int cmd_record(int argc, const char **argv, const char *prefix)
526{
527 int counter;
528
529 argc = parse_options(argc, argv, options, record_usage, 0);
530 if (!argc && target_pid == -1 && !system_wide)
531 usage_with_options(record_usage, options);
532
533 if (!nr_counters)
534 nr_counters = 1;
535
536 for (counter = 0; counter < nr_counters; counter++) {
537 if (attrs[counter].sample_period)
538 continue;
539
540 attrs[counter].sample_period = default_interval;
541 }
542
543 return __cmd_record(argc, argv);
544}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
new file mode 100644
index 000000000000..242e09ff3658
--- /dev/null
+++ b/tools/perf/builtin-report.c
@@ -0,0 +1,1291 @@
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
40static int verbose;
41static int full_paths;
42
43static unsigned long page_size;
44static unsigned long mmap_window = 32;
45
46struct ip_event {
47 struct perf_event_header header;
48 __u64 ip;
49 __u32 pid, tid;
50};
51
52struct mmap_event {
53 struct perf_event_header header;
54 __u32 pid, tid;
55 __u64 start;
56 __u64 len;
57 __u64 pgoff;
58 char filename[PATH_MAX];
59};
60
61struct comm_event {
62 struct perf_event_header header;
63 __u32 pid, tid;
64 char comm[16];
65};
66
67struct fork_event {
68 struct perf_event_header header;
69 __u32 pid, ppid;
70};
71
72struct period_event {
73 struct perf_event_header header;
74 __u64 time;
75 __u64 id;
76 __u64 sample_period;
77};
78
79typedef union event_union {
80 struct perf_event_header header;
81 struct ip_event ip;
82 struct mmap_event mmap;
83 struct comm_event comm;
84 struct fork_event fork;
85 struct period_event period;
86} event_t;
87
88static LIST_HEAD(dsos);
89static struct dso *kernel_dso;
90static struct dso *vdso;
91
92static void dsos__add(struct dso *dso)
93{
94 list_add_tail(&dso->node, &dsos);
95}
96
97static struct dso *dsos__find(const char *name)
98{
99 struct dso *pos;
100
101 list_for_each_entry(pos, &dsos, node)
102 if (strcmp(pos->name, name) == 0)
103 return pos;
104 return NULL;
105}
106
107static struct dso *dsos__findnew(const char *name)
108{
109 struct dso *dso = dsos__find(name);
110 int nr;
111
112 if (dso)
113 return dso;
114
115 dso = dso__new(name, 0);
116 if (!dso)
117 goto out_delete_dso;
118
119 nr = dso__load(dso, NULL, verbose);
120 if (nr < 0) {
121 if (verbose)
122 fprintf(stderr, "Failed to open: %s\n", name);
123 goto out_delete_dso;
124 }
125 if (!nr && verbose) {
126 fprintf(stderr,
127 "No symbols found in: %s, maybe install a debug package?\n",
128 name);
129 }
130
131 dsos__add(dso);
132
133 return dso;
134
135out_delete_dso:
136 dso__delete(dso);
137 return NULL;
138}
139
140static void dsos__fprintf(FILE *fp)
141{
142 struct dso *pos;
143
144 list_for_each_entry(pos, &dsos, node)
145 dso__fprintf(pos, fp);
146}
147
148static struct symbol *vdso__find_symbol(struct dso *dso, uint64_t ip)
149{
150 return dso__find_symbol(kernel_dso, ip);
151}
152
153static int load_kernel(void)
154{
155 int err;
156
157 kernel_dso = dso__new("[kernel]", 0);
158 if (!kernel_dso)
159 return -1;
160
161 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
162 if (err) {
163 dso__delete(kernel_dso);
164 kernel_dso = NULL;
165 } else
166 dsos__add(kernel_dso);
167
168 vdso = dso__new("[vdso]", 0);
169 if (!vdso)
170 return -1;
171
172 vdso->find_symbol = vdso__find_symbol;
173
174 dsos__add(vdso);
175
176 return err;
177}
178
179static char __cwd[PATH_MAX];
180static char *cwd = __cwd;
181static int cwdlen;
182
183static int strcommon(const char *pathname)
184{
185 int n = 0;
186
187 while (pathname[n] == cwd[n] && n < cwdlen)
188 ++n;
189
190 return n;
191}
192
193struct map {
194 struct list_head node;
195 uint64_t start;
196 uint64_t end;
197 uint64_t pgoff;
198 uint64_t (*map_ip)(struct map *, uint64_t);
199 struct dso *dso;
200};
201
202static uint64_t map__map_ip(struct map *map, uint64_t ip)
203{
204 return ip - map->start + map->pgoff;
205}
206
207static uint64_t vdso__map_ip(struct map *map, uint64_t ip)
208{
209 return ip;
210}
211
212static struct map *map__new(struct mmap_event *event)
213{
214 struct map *self = malloc(sizeof(*self));
215
216 if (self != NULL) {
217 const char *filename = event->filename;
218 char newfilename[PATH_MAX];
219
220 if (cwd) {
221 int n = strcommon(filename);
222
223 if (n == cwdlen) {
224 snprintf(newfilename, sizeof(newfilename),
225 ".%s", filename + n);
226 filename = newfilename;
227 }
228 }
229
230 self->start = event->start;
231 self->end = event->start + event->len;
232 self->pgoff = event->pgoff;
233
234 self->dso = dsos__findnew(filename);
235 if (self->dso == NULL)
236 goto out_delete;
237
238 if (self->dso == vdso)
239 self->map_ip = vdso__map_ip;
240 else
241 self->map_ip = map__map_ip;
242 }
243 return self;
244out_delete:
245 free(self);
246 return NULL;
247}
248
249static struct map *map__clone(struct map *self)
250{
251 struct map *map = malloc(sizeof(*self));
252
253 if (!map)
254 return NULL;
255
256 memcpy(map, self, sizeof(*self));
257
258 return map;
259}
260
261static int map__overlap(struct map *l, struct map *r)
262{
263 if (l->start > r->start) {
264 struct map *t = l;
265 l = r;
266 r = t;
267 }
268
269 if (l->end > r->start)
270 return 1;
271
272 return 0;
273}
274
275static size_t map__fprintf(struct map *self, FILE *fp)
276{
277 return fprintf(fp, " %"PRIx64"-%"PRIx64" %"PRIx64" %s\n",
278 self->start, self->end, self->pgoff, self->dso->name);
279}
280
281
282struct thread {
283 struct rb_node rb_node;
284 struct list_head maps;
285 pid_t pid;
286 char *comm;
287};
288
289static struct thread *thread__new(pid_t pid)
290{
291 struct thread *self = malloc(sizeof(*self));
292
293 if (self != NULL) {
294 self->pid = pid;
295 self->comm = malloc(32);
296 if (self->comm)
297 snprintf(self->comm, 32, ":%d", self->pid);
298 INIT_LIST_HEAD(&self->maps);
299 }
300
301 return self;
302}
303
304static int thread__set_comm(struct thread *self, const char *comm)
305{
306 if (self->comm)
307 free(self->comm);
308 self->comm = strdup(comm);
309 return self->comm ? 0 : -ENOMEM;
310}
311
312static size_t thread__fprintf(struct thread *self, FILE *fp)
313{
314 struct map *pos;
315 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
316
317 list_for_each_entry(pos, &self->maps, node)
318 ret += map__fprintf(pos, fp);
319
320 return ret;
321}
322
323
324static struct rb_root threads;
325static struct thread *last_match;
326
327static struct thread *threads__findnew(pid_t pid)
328{
329 struct rb_node **p = &threads.rb_node;
330 struct rb_node *parent = NULL;
331 struct thread *th;
332
333 /*
334 * Font-end cache - PID lookups come in blocks,
335 * so most of the time we dont have to look up
336 * the full rbtree:
337 */
338 if (last_match && last_match->pid == pid)
339 return last_match;
340
341 while (*p != NULL) {
342 parent = *p;
343 th = rb_entry(parent, struct thread, rb_node);
344
345 if (th->pid == pid) {
346 last_match = th;
347 return th;
348 }
349
350 if (pid < th->pid)
351 p = &(*p)->rb_left;
352 else
353 p = &(*p)->rb_right;
354 }
355
356 th = thread__new(pid);
357 if (th != NULL) {
358 rb_link_node(&th->rb_node, parent, p);
359 rb_insert_color(&th->rb_node, &threads);
360 last_match = th;
361 }
362
363 return th;
364}
365
366static void thread__insert_map(struct thread *self, struct map *map)
367{
368 struct map *pos, *tmp;
369
370 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
371 if (map__overlap(pos, map)) {
372 list_del_init(&pos->node);
373 /* XXX leaks dsos */
374 free(pos);
375 }
376 }
377
378 list_add_tail(&map->node, &self->maps);
379}
380
381static int thread__fork(struct thread *self, struct thread *parent)
382{
383 struct map *map;
384
385 if (self->comm)
386 free(self->comm);
387 self->comm = strdup(parent->comm);
388 if (!self->comm)
389 return -ENOMEM;
390
391 list_for_each_entry(map, &parent->maps, node) {
392 struct map *new = map__clone(map);
393 if (!new)
394 return -ENOMEM;
395 thread__insert_map(self, new);
396 }
397
398 return 0;
399}
400
401static struct map *thread__find_map(struct thread *self, uint64_t ip)
402{
403 struct map *pos;
404
405 if (self == NULL)
406 return NULL;
407
408 list_for_each_entry(pos, &self->maps, node)
409 if (ip >= pos->start && ip <= pos->end)
410 return pos;
411
412 return NULL;
413}
414
415static size_t threads__fprintf(FILE *fp)
416{
417 size_t ret = 0;
418 struct rb_node *nd;
419
420 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
421 struct thread *pos = rb_entry(nd, struct thread, rb_node);
422
423 ret += thread__fprintf(pos, fp);
424 }
425
426 return ret;
427}
428
429/*
430 * histogram, sorted on item, collects counts
431 */
432
433static struct rb_root hist;
434
435struct hist_entry {
436 struct rb_node rb_node;
437
438 struct thread *thread;
439 struct map *map;
440 struct dso *dso;
441 struct symbol *sym;
442 uint64_t ip;
443 char level;
444
445 uint32_t count;
446};
447
448/*
449 * configurable sorting bits
450 */
451
452struct sort_entry {
453 struct list_head list;
454
455 char *header;
456
457 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
458 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
459 size_t (*print)(FILE *fp, struct hist_entry *);
460};
461
462/* --sort pid */
463
464static int64_t
465sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
466{
467 return right->thread->pid - left->thread->pid;
468}
469
470static size_t
471sort__thread_print(FILE *fp, struct hist_entry *self)
472{
473 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
474}
475
476static struct sort_entry sort_thread = {
477 .header = " Command: Pid",
478 .cmp = sort__thread_cmp,
479 .print = sort__thread_print,
480};
481
482/* --sort comm */
483
484static int64_t
485sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
486{
487 return right->thread->pid - left->thread->pid;
488}
489
490static int64_t
491sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
492{
493 char *comm_l = left->thread->comm;
494 char *comm_r = right->thread->comm;
495
496 if (!comm_l || !comm_r) {
497 if (!comm_l && !comm_r)
498 return 0;
499 else if (!comm_l)
500 return -1;
501 else
502 return 1;
503 }
504
505 return strcmp(comm_l, comm_r);
506}
507
508static size_t
509sort__comm_print(FILE *fp, struct hist_entry *self)
510{
511 return fprintf(fp, "%16s", self->thread->comm);
512}
513
514static struct sort_entry sort_comm = {
515 .header = " Command",
516 .cmp = sort__comm_cmp,
517 .collapse = sort__comm_collapse,
518 .print = sort__comm_print,
519};
520
521/* --sort dso */
522
523static int64_t
524sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
525{
526 struct dso *dso_l = left->dso;
527 struct dso *dso_r = right->dso;
528
529 if (!dso_l || !dso_r) {
530 if (!dso_l && !dso_r)
531 return 0;
532 else if (!dso_l)
533 return -1;
534 else
535 return 1;
536 }
537
538 return strcmp(dso_l->name, dso_r->name);
539}
540
541static size_t
542sort__dso_print(FILE *fp, struct hist_entry *self)
543{
544 if (self->dso)
545 return fprintf(fp, "%-25s", self->dso->name);
546
547 return fprintf(fp, "%016llx ", (__u64)self->ip);
548}
549
550static struct sort_entry sort_dso = {
551 .header = "Shared Object ",
552 .cmp = sort__dso_cmp,
553 .print = sort__dso_print,
554};
555
556/* --sort symbol */
557
558static int64_t
559sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
560{
561 uint64_t ip_l, ip_r;
562
563 if (left->sym == right->sym)
564 return 0;
565
566 ip_l = left->sym ? left->sym->start : left->ip;
567 ip_r = right->sym ? right->sym->start : right->ip;
568
569 return (int64_t)(ip_r - ip_l);
570}
571
572static size_t
573sort__sym_print(FILE *fp, struct hist_entry *self)
574{
575 size_t ret = 0;
576
577 if (verbose)
578 ret += fprintf(fp, "%#018llx ", (__u64)self->ip);
579
580 if (self->sym) {
581 ret += fprintf(fp, "[%c] %s",
582 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
583 } else {
584 ret += fprintf(fp, "%#016llx", (__u64)self->ip);
585 }
586
587 return ret;
588}
589
590static struct sort_entry sort_sym = {
591 .header = "Symbol",
592 .cmp = sort__sym_cmp,
593 .print = sort__sym_print,
594};
595
596static int sort__need_collapse = 0;
597
598struct sort_dimension {
599 char *name;
600 struct sort_entry *entry;
601 int taken;
602};
603
604static struct sort_dimension sort_dimensions[] = {
605 { .name = "pid", .entry = &sort_thread, },
606 { .name = "comm", .entry = &sort_comm, },
607 { .name = "dso", .entry = &sort_dso, },
608 { .name = "symbol", .entry = &sort_sym, },
609};
610
611static LIST_HEAD(hist_entry__sort_list);
612
613static int sort_dimension__add(char *tok)
614{
615 int i;
616
617 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
618 struct sort_dimension *sd = &sort_dimensions[i];
619
620 if (sd->taken)
621 continue;
622
623 if (strncasecmp(tok, sd->name, strlen(tok)))
624 continue;
625
626 if (sd->entry->collapse)
627 sort__need_collapse = 1;
628
629 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
630 sd->taken = 1;
631
632 return 0;
633 }
634
635 return -ESRCH;
636}
637
638static int64_t
639hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
640{
641 struct sort_entry *se;
642 int64_t cmp = 0;
643
644 list_for_each_entry(se, &hist_entry__sort_list, list) {
645 cmp = se->cmp(left, right);
646 if (cmp)
647 break;
648 }
649
650 return cmp;
651}
652
653static int64_t
654hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
655{
656 struct sort_entry *se;
657 int64_t cmp = 0;
658
659 list_for_each_entry(se, &hist_entry__sort_list, list) {
660 int64_t (*f)(struct hist_entry *, struct hist_entry *);
661
662 f = se->collapse ?: se->cmp;
663
664 cmp = f(left, right);
665 if (cmp)
666 break;
667 }
668
669 return cmp;
670}
671
672static size_t
673hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
674{
675 struct sort_entry *se;
676 size_t ret;
677
678 if (total_samples) {
679 double percent = self->count * 100.0 / total_samples;
680 char *color = PERF_COLOR_NORMAL;
681
682 /*
683 * We color high-overhead entries in red, low-overhead
684 * entries in green - and keep the middle ground normal:
685 */
686 if (percent >= 5.0)
687 color = PERF_COLOR_RED;
688 if (percent < 0.5)
689 color = PERF_COLOR_GREEN;
690
691 ret = color_fprintf(fp, color, " %6.2f%%",
692 (self->count * 100.0) / total_samples);
693 } else
694 ret = fprintf(fp, "%12d ", self->count);
695
696 list_for_each_entry(se, &hist_entry__sort_list, list) {
697 fprintf(fp, " ");
698 ret += se->print(fp, self);
699 }
700
701 ret += fprintf(fp, "\n");
702
703 return ret;
704}
705
706/*
707 * collect histogram counts
708 */
709
710static int
711hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
712 struct symbol *sym, uint64_t ip, char level)
713{
714 struct rb_node **p = &hist.rb_node;
715 struct rb_node *parent = NULL;
716 struct hist_entry *he;
717 struct hist_entry entry = {
718 .thread = thread,
719 .map = map,
720 .dso = dso,
721 .sym = sym,
722 .ip = ip,
723 .level = level,
724 .count = 1,
725 };
726 int cmp;
727
728 while (*p != NULL) {
729 parent = *p;
730 he = rb_entry(parent, struct hist_entry, rb_node);
731
732 cmp = hist_entry__cmp(&entry, he);
733
734 if (!cmp) {
735 he->count++;
736 return 0;
737 }
738
739 if (cmp < 0)
740 p = &(*p)->rb_left;
741 else
742 p = &(*p)->rb_right;
743 }
744
745 he = malloc(sizeof(*he));
746 if (!he)
747 return -ENOMEM;
748 *he = entry;
749 rb_link_node(&he->rb_node, parent, p);
750 rb_insert_color(&he->rb_node, &hist);
751
752 return 0;
753}
754
755static void hist_entry__free(struct hist_entry *he)
756{
757 free(he);
758}
759
760/*
761 * collapse the histogram
762 */
763
764static struct rb_root collapse_hists;
765
766static void collapse__insert_entry(struct hist_entry *he)
767{
768 struct rb_node **p = &collapse_hists.rb_node;
769 struct rb_node *parent = NULL;
770 struct hist_entry *iter;
771 int64_t cmp;
772
773 while (*p != NULL) {
774 parent = *p;
775 iter = rb_entry(parent, struct hist_entry, rb_node);
776
777 cmp = hist_entry__collapse(iter, he);
778
779 if (!cmp) {
780 iter->count += he->count;
781 hist_entry__free(he);
782 return;
783 }
784
785 if (cmp < 0)
786 p = &(*p)->rb_left;
787 else
788 p = &(*p)->rb_right;
789 }
790
791 rb_link_node(&he->rb_node, parent, p);
792 rb_insert_color(&he->rb_node, &collapse_hists);
793}
794
795static void collapse__resort(void)
796{
797 struct rb_node *next;
798 struct hist_entry *n;
799
800 if (!sort__need_collapse)
801 return;
802
803 next = rb_first(&hist);
804 while (next) {
805 n = rb_entry(next, struct hist_entry, rb_node);
806 next = rb_next(&n->rb_node);
807
808 rb_erase(&n->rb_node, &hist);
809 collapse__insert_entry(n);
810 }
811}
812
813/*
814 * reverse the map, sort on count.
815 */
816
817static struct rb_root output_hists;
818
819static void output__insert_entry(struct hist_entry *he)
820{
821 struct rb_node **p = &output_hists.rb_node;
822 struct rb_node *parent = NULL;
823 struct hist_entry *iter;
824
825 while (*p != NULL) {
826 parent = *p;
827 iter = rb_entry(parent, struct hist_entry, rb_node);
828
829 if (he->count > iter->count)
830 p = &(*p)->rb_left;
831 else
832 p = &(*p)->rb_right;
833 }
834
835 rb_link_node(&he->rb_node, parent, p);
836 rb_insert_color(&he->rb_node, &output_hists);
837}
838
839static void output__resort(void)
840{
841 struct rb_node *next;
842 struct hist_entry *n;
843 struct rb_root *tree = &hist;
844
845 if (sort__need_collapse)
846 tree = &collapse_hists;
847
848 next = rb_first(tree);
849
850 while (next) {
851 n = rb_entry(next, struct hist_entry, rb_node);
852 next = rb_next(&n->rb_node);
853
854 rb_erase(&n->rb_node, tree);
855 output__insert_entry(n);
856 }
857}
858
859static size_t output__fprintf(FILE *fp, uint64_t total_samples)
860{
861 struct hist_entry *pos;
862 struct sort_entry *se;
863 struct rb_node *nd;
864 size_t ret = 0;
865
866 fprintf(fp, "\n");
867 fprintf(fp, "#\n");
868 fprintf(fp, "# (%Ld samples)\n", (__u64)total_samples);
869 fprintf(fp, "#\n");
870
871 fprintf(fp, "# Overhead");
872 list_for_each_entry(se, &hist_entry__sort_list, list)
873 fprintf(fp, " %s", se->header);
874 fprintf(fp, "\n");
875
876 fprintf(fp, "# ........");
877 list_for_each_entry(se, &hist_entry__sort_list, list) {
878 int i;
879
880 fprintf(fp, " ");
881 for (i = 0; i < strlen(se->header); i++)
882 fprintf(fp, ".");
883 }
884 fprintf(fp, "\n");
885
886 fprintf(fp, "#\n");
887
888 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
889 pos = rb_entry(nd, struct hist_entry, rb_node);
890 ret += hist_entry__fprintf(fp, pos, total_samples);
891 }
892
893 if (!strcmp(sort_order, default_sort_order)) {
894 fprintf(fp, "#\n");
895 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n");
896 fprintf(fp, "#\n");
897 }
898 fprintf(fp, "\n");
899
900 return ret;
901}
902
903static void register_idle_thread(void)
904{
905 struct thread *thread = threads__findnew(0);
906
907 if (thread == NULL ||
908 thread__set_comm(thread, "[idle]")) {
909 fprintf(stderr, "problem inserting idle task.\n");
910 exit(-1);
911 }
912}
913
914static unsigned long total = 0,
915 total_mmap = 0,
916 total_comm = 0,
917 total_fork = 0,
918 total_unknown = 0;
919
920static int
921process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
922{
923 char level;
924 int show = 0;
925 struct dso *dso = NULL;
926 struct thread *thread = threads__findnew(event->ip.pid);
927 uint64_t ip = event->ip.ip;
928 struct map *map = NULL;
929
930 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
931 (void *)(offset + head),
932 (void *)(long)(event->header.size),
933 event->header.misc,
934 event->ip.pid,
935 (void *)(long)ip);
936
937 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
938
939 if (thread == NULL) {
940 fprintf(stderr, "problem processing %d event, skipping it.\n",
941 event->header.type);
942 return -1;
943 }
944
945 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
946 show = SHOW_KERNEL;
947 level = 'k';
948
949 dso = kernel_dso;
950
951 dprintf(" ...... dso: %s\n", dso->name);
952
953 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
954
955 show = SHOW_USER;
956 level = '.';
957
958 map = thread__find_map(thread, ip);
959 if (map != NULL) {
960 ip = map->map_ip(map, ip);
961 dso = map->dso;
962 } else {
963 /*
964 * If this is outside of all known maps,
965 * and is a negative address, try to look it
966 * up in the kernel dso, as it might be a
967 * vsyscall (which executes in user-mode):
968 */
969 if ((long long)ip < 0)
970 dso = kernel_dso;
971 }
972 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
973
974 } else {
975 show = SHOW_HV;
976 level = 'H';
977 dprintf(" ...... dso: [hypervisor]\n");
978 }
979
980 if (show & show_mask) {
981 struct symbol *sym = NULL;
982
983 if (dso)
984 sym = dso->find_symbol(dso, ip);
985
986 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
987 fprintf(stderr,
988 "problem incrementing symbol count, skipping event\n");
989 return -1;
990 }
991 }
992 total++;
993
994 return 0;
995}
996
997static int
998process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
999{
1000 struct thread *thread = threads__findnew(event->mmap.pid);
1001 struct map *map = map__new(&event->mmap);
1002
1003 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
1004 (void *)(offset + head),
1005 (void *)(long)(event->header.size),
1006 event->mmap.pid,
1007 (void *)(long)event->mmap.start,
1008 (void *)(long)event->mmap.len,
1009 (void *)(long)event->mmap.pgoff,
1010 event->mmap.filename);
1011
1012 if (thread == NULL || map == NULL) {
1013 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
1014 return 0;
1015 }
1016
1017 thread__insert_map(thread, map);
1018 total_mmap++;
1019
1020 return 0;
1021}
1022
1023static int
1024process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1025{
1026 struct thread *thread = threads__findnew(event->comm.pid);
1027
1028 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
1029 (void *)(offset + head),
1030 (void *)(long)(event->header.size),
1031 event->comm.comm, event->comm.pid);
1032
1033 if (thread == NULL ||
1034 thread__set_comm(thread, event->comm.comm)) {
1035 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
1036 return -1;
1037 }
1038 total_comm++;
1039
1040 return 0;
1041}
1042
1043static int
1044process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1045{
1046 struct thread *thread = threads__findnew(event->fork.pid);
1047 struct thread *parent = threads__findnew(event->fork.ppid);
1048
1049 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n",
1050 (void *)(offset + head),
1051 (void *)(long)(event->header.size),
1052 event->fork.pid, event->fork.ppid);
1053
1054 if (!thread || !parent || thread__fork(thread, parent)) {
1055 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
1056 return -1;
1057 }
1058 total_fork++;
1059
1060 return 0;
1061}
1062
1063static int
1064process_period_event(event_t *event, unsigned long offset, unsigned long head)
1065{
1066 dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
1067 (void *)(offset + head),
1068 (void *)(long)(event->header.size),
1069 event->period.time,
1070 event->period.id,
1071 event->period.sample_period);
1072
1073 return 0;
1074}
1075
1076static int
1077process_event(event_t *event, unsigned long offset, unsigned long head)
1078{
1079 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1080 return process_overflow_event(event, offset, head);
1081
1082 switch (event->header.type) {
1083 case PERF_EVENT_MMAP:
1084 return process_mmap_event(event, offset, head);
1085
1086 case PERF_EVENT_COMM:
1087 return process_comm_event(event, offset, head);
1088
1089 case PERF_EVENT_FORK:
1090 return process_fork_event(event, offset, head);
1091
1092 case PERF_EVENT_PERIOD:
1093 return process_period_event(event, offset, head);
1094 /*
1095 * We dont process them right now but they are fine:
1096 */
1097
1098 case PERF_EVENT_THROTTLE:
1099 case PERF_EVENT_UNTHROTTLE:
1100 return 0;
1101
1102 default:
1103 return -1;
1104 }
1105
1106 return 0;
1107}
1108
1109static int __cmd_report(void)
1110{
1111 int ret, rc = EXIT_FAILURE;
1112 unsigned long offset = 0;
1113 unsigned long head = 0;
1114 struct stat stat;
1115 event_t *event;
1116 uint32_t size;
1117 char *buf;
1118
1119 register_idle_thread();
1120
1121 input = open(input_name, O_RDONLY);
1122 if (input < 0) {
1123 perror("failed to open file");
1124 exit(-1);
1125 }
1126
1127 ret = fstat(input, &stat);
1128 if (ret < 0) {
1129 perror("failed to stat file");
1130 exit(-1);
1131 }
1132
1133 if (!stat.st_size) {
1134 fprintf(stderr, "zero-sized file, nothing to do!\n");
1135 exit(0);
1136 }
1137
1138 if (load_kernel() < 0) {
1139 perror("failed to load kernel symbols");
1140 return EXIT_FAILURE;
1141 }
1142
1143 if (!full_paths) {
1144 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1145 perror("failed to get the current directory");
1146 return EXIT_FAILURE;
1147 }
1148 cwdlen = strlen(cwd);
1149 } else {
1150 cwd = NULL;
1151 cwdlen = 0;
1152 }
1153remap:
1154 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1155 MAP_SHARED, input, offset);
1156 if (buf == MAP_FAILED) {
1157 perror("failed to mmap file");
1158 exit(-1);
1159 }
1160
1161more:
1162 event = (event_t *)(buf + head);
1163
1164 size = event->header.size;
1165 if (!size)
1166 size = 8;
1167
1168 if (head + event->header.size >= page_size * mmap_window) {
1169 unsigned long shift = page_size * (head / page_size);
1170 int ret;
1171
1172 ret = munmap(buf, page_size * mmap_window);
1173 assert(ret == 0);
1174
1175 offset += shift;
1176 head -= shift;
1177 goto remap;
1178 }
1179
1180 size = event->header.size;
1181
1182 dprintf("%p [%p]: event: %d\n",
1183 (void *)(offset + head),
1184 (void *)(long)event->header.size,
1185 event->header.type);
1186
1187 if (!size || process_event(event, offset, head) < 0) {
1188
1189 dprintf("%p [%p]: skipping unknown header type: %d\n",
1190 (void *)(offset + head),
1191 (void *)(long)(event->header.size),
1192 event->header.type);
1193
1194 total_unknown++;
1195
1196 /*
1197 * assume we lost track of the stream, check alignment, and
1198 * increment a single u64 in the hope to catch on again 'soon'.
1199 */
1200
1201 if (unlikely(head & 7))
1202 head &= ~7ULL;
1203
1204 size = 8;
1205 }
1206
1207 head += size;
1208
1209 if (offset + head < stat.st_size)
1210 goto more;
1211
1212 rc = EXIT_SUCCESS;
1213 close(input);
1214
1215 dprintf(" IP events: %10ld\n", total);
1216 dprintf(" mmap events: %10ld\n", total_mmap);
1217 dprintf(" comm events: %10ld\n", total_comm);
1218 dprintf(" fork events: %10ld\n", total_fork);
1219 dprintf(" unknown events: %10ld\n", total_unknown);
1220
1221 if (dump_trace)
1222 return 0;
1223
1224 if (verbose >= 3)
1225 threads__fprintf(stdout);
1226
1227 if (verbose >= 2)
1228 dsos__fprintf(stdout);
1229
1230 collapse__resort();
1231 output__resort();
1232 output__fprintf(stdout, total);
1233
1234 return rc;
1235}
1236
1237static const char * const report_usage[] = {
1238 "perf report [<options>] <command>",
1239 NULL
1240};
1241
1242static const struct option options[] = {
1243 OPT_STRING('i', "input", &input_name, "file",
1244 "input file name"),
1245 OPT_BOOLEAN('v', "verbose", &verbose,
1246 "be more verbose (show symbol address, etc)"),
1247 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1248 "dump raw trace in ASCII"),
1249 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
1250 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1251 "sort by key(s): pid, comm, dso, symbol. Default: pid,symbol"),
1252 OPT_BOOLEAN('P', "full-paths", &full_paths,
1253 "Don't shorten the pathnames taking into account the cwd"),
1254 OPT_END()
1255};
1256
1257static void setup_sorting(void)
1258{
1259 char *tmp, *tok, *str = strdup(sort_order);
1260
1261 for (tok = strtok_r(str, ", ", &tmp);
1262 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1263 if (sort_dimension__add(tok) < 0) {
1264 error("Unknown --sort key: `%s'", tok);
1265 usage_with_options(report_usage, options);
1266 }
1267 }
1268
1269 free(str);
1270}
1271
1272int cmd_report(int argc, const char **argv, const char *prefix)
1273{
1274 symbol__init();
1275
1276 page_size = getpagesize();
1277
1278 argc = parse_options(argc, argv, options, report_usage, 0);
1279
1280 setup_sorting();
1281
1282 /*
1283 * Any (unrecognized) arguments left?
1284 */
1285 if (argc)
1286 usage_with_options(report_usage, options);
1287
1288 setup_pager();
1289
1290 return __cmd_report();
1291}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
new file mode 100644
index 000000000000..2cbf5a189589
--- /dev/null
+++ b/tools/perf/builtin-stat.c
@@ -0,0 +1,339 @@
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
47static struct perf_counter_attr default_attrs[MAX_COUNTERS] = {
48
49 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_TASK_CLOCK },
50 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_CONTEXT_SWITCHES },
51 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_CPU_MIGRATIONS },
52 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_PAGE_FAULTS },
53
54 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_CPU_CYCLES },
55 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_INSTRUCTIONS },
56 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_CACHE_REFERENCES },
57 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_CACHE_MISSES },
58};
59
60static int system_wide = 0;
61static int inherit = 1;
62
63static int fd[MAX_NR_CPUS][MAX_COUNTERS];
64
65static int target_pid = -1;
66static int nr_cpus = 0;
67static unsigned int page_size;
68
69static int scale = 1;
70
71static const unsigned int default_count[] = {
72 1000000,
73 1000000,
74 10000,
75 10000,
76 1000000,
77 10000,
78};
79
80static __u64 event_res[MAX_COUNTERS][3];
81static __u64 event_scaled[MAX_COUNTERS];
82
83static __u64 runtime_nsecs;
84static __u64 walltime_nsecs;
85
86static void create_perfstat_counter(int counter)
87{
88 struct perf_counter_attr *attr = attrs + counter;
89
90 if (scale)
91 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
92 PERF_FORMAT_TOTAL_TIME_RUNNING;
93
94 if (system_wide) {
95 int cpu;
96 for (cpu = 0; cpu < nr_cpus; cpu ++) {
97 fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0);
98 if (fd[cpu][counter] < 0) {
99 printf("perfstat error: syscall returned with %d (%s)\n",
100 fd[cpu][counter], strerror(errno));
101 exit(-1);
102 }
103 }
104 } else {
105 attr->inherit = inherit;
106 attr->disabled = 1;
107
108 fd[0][counter] = sys_perf_counter_open(attr, 0, -1, -1, 0);
109 if (fd[0][counter] < 0) {
110 printf("perfstat error: syscall returned with %d (%s)\n",
111 fd[0][counter], strerror(errno));
112 exit(-1);
113 }
114 }
115}
116
117/*
118 * Does the counter have nsecs as a unit?
119 */
120static inline int nsec_counter(int counter)
121{
122 if (attrs[counter].type != PERF_TYPE_SOFTWARE)
123 return 0;
124
125 if (attrs[counter].config == PERF_COUNT_CPU_CLOCK)
126 return 1;
127
128 if (attrs[counter].config == PERF_COUNT_TASK_CLOCK)
129 return 1;
130
131 return 0;
132}
133
134/*
135 * Read out the results of a single counter:
136 */
137static void read_counter(int counter)
138{
139 __u64 *count, single_count[3];
140 ssize_t res;
141 int cpu, nv;
142 int scaled;
143
144 count = event_res[counter];
145
146 count[0] = count[1] = count[2] = 0;
147
148 nv = scale ? 3 : 1;
149 for (cpu = 0; cpu < nr_cpus; cpu ++) {
150 res = read(fd[cpu][counter], single_count, nv * sizeof(__u64));
151 assert(res == nv * sizeof(__u64));
152
153 count[0] += single_count[0];
154 if (scale) {
155 count[1] += single_count[1];
156 count[2] += single_count[2];
157 }
158 }
159
160 scaled = 0;
161 if (scale) {
162 if (count[2] == 0) {
163 event_scaled[counter] = -1;
164 count[0] = 0;
165 return;
166 }
167
168 if (count[2] < count[1]) {
169 event_scaled[counter] = 1;
170 count[0] = (unsigned long long)
171 ((double)count[0] * count[1] / count[2] + 0.5);
172 }
173 }
174 /*
175 * Save the full runtime - to allow normalization during printout:
176 */
177 if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
178 attrs[counter].config == PERF_COUNT_TASK_CLOCK)
179 runtime_nsecs = count[0];
180}
181
182/*
183 * Print out the results of a single counter:
184 */
185static void print_counter(int counter)
186{
187 __u64 *count;
188 int scaled;
189
190 count = event_res[counter];
191 scaled = event_scaled[counter];
192
193 if (scaled == -1) {
194 fprintf(stderr, " %14s %-20s\n",
195 "<not counted>", event_name(counter));
196 return;
197 }
198
199 if (nsec_counter(counter)) {
200 double msecs = (double)count[0] / 1000000;
201
202 fprintf(stderr, " %14.6f %-20s",
203 msecs, event_name(counter));
204 if (attrs[counter].type == PERF_TYPE_SOFTWARE &&
205 attrs[counter].config == PERF_COUNT_TASK_CLOCK) {
206
207 fprintf(stderr, " # %11.3f CPU utilization factor",
208 (double)count[0] / (double)walltime_nsecs);
209 }
210 } else {
211 fprintf(stderr, " %14Ld %-20s",
212 count[0], event_name(counter));
213 if (runtime_nsecs)
214 fprintf(stderr, " # %11.3f M/sec",
215 (double)count[0]/runtime_nsecs*1000.0);
216 }
217 if (scaled)
218 fprintf(stderr, " (scaled from %.2f%%)",
219 (double) count[2] / count[1] * 100);
220 fprintf(stderr, "\n");
221}
222
223static int do_perfstat(int argc, const char **argv)
224{
225 unsigned long long t0, t1;
226 int counter;
227 int status;
228 int pid;
229 int i;
230
231 if (!system_wide)
232 nr_cpus = 1;
233
234 for (counter = 0; counter < nr_counters; counter++)
235 create_perfstat_counter(counter);
236
237 /*
238 * Enable counters and exec the command:
239 */
240 t0 = rdclock();
241 prctl(PR_TASK_PERF_COUNTERS_ENABLE);
242
243 if ((pid = fork()) < 0)
244 perror("failed to fork");
245
246 if (!pid) {
247 if (execvp(argv[0], (char **)argv)) {
248 perror(argv[0]);
249 exit(-1);
250 }
251 }
252
253 while (wait(&status) >= 0)
254 ;
255
256 prctl(PR_TASK_PERF_COUNTERS_DISABLE);
257 t1 = rdclock();
258
259 walltime_nsecs = t1 - t0;
260
261 fflush(stdout);
262
263 fprintf(stderr, "\n");
264 fprintf(stderr, " Performance counter stats for \'%s", argv[0]);
265
266 for (i = 1; i < argc; i++)
267 fprintf(stderr, " %s", argv[i]);
268
269 fprintf(stderr, "\':\n");
270 fprintf(stderr, "\n");
271
272 for (counter = 0; counter < nr_counters; counter++)
273 read_counter(counter);
274
275 for (counter = 0; counter < nr_counters; counter++)
276 print_counter(counter);
277
278
279 fprintf(stderr, "\n");
280 fprintf(stderr, " Wall-clock time elapsed: %12.6f msecs\n",
281 (double)(t1-t0)/1e6);
282 fprintf(stderr, "\n");
283
284 return 0;
285}
286
287static void skip_signal(int signo)
288{
289}
290
291static const char * const stat_usage[] = {
292 "perf stat [<options>] <command>",
293 NULL
294};
295
296static const struct option options[] = {
297 OPT_CALLBACK('e', "event", NULL, "event",
298 "event selector. use 'perf list' to list available events",
299 parse_events),
300 OPT_BOOLEAN('i', "inherit", &inherit,
301 "child tasks inherit counters"),
302 OPT_INTEGER('p', "pid", &target_pid,
303 "stat events on existing pid"),
304 OPT_BOOLEAN('a', "all-cpus", &system_wide,
305 "system-wide collection from all CPUs"),
306 OPT_BOOLEAN('S', "scale", &scale,
307 "scale/normalize counters"),
308 OPT_END()
309};
310
311int cmd_stat(int argc, const char **argv, const char *prefix)
312{
313 page_size = sysconf(_SC_PAGE_SIZE);
314
315 memcpy(attrs, default_attrs, sizeof(attrs));
316
317 argc = parse_options(argc, argv, options, stat_usage, 0);
318 if (!argc)
319 usage_with_options(stat_usage, options);
320
321 if (!nr_counters)
322 nr_counters = 8;
323
324 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
325 assert(nr_cpus <= MAX_NR_CPUS);
326 assert(nr_cpus >= 0);
327
328 /*
329 * We dont want to block the signals - that would cause
330 * child tasks to inherit that and Ctrl-C would not work.
331 * What we want is for Ctrl-C to work in the exec()-ed
332 * task, but being ignored by perf stat itself:
333 */
334 signal(SIGINT, skip_signal);
335 signal(SIGALRM, skip_signal);
336 signal(SIGABRT, skip_signal);
337
338 return do_perfstat(argc, argv);
339}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
new file mode 100644
index 000000000000..f2e7312f85c9
--- /dev/null
+++ b/tools/perf/builtin-top.c
@@ -0,0 +1,692 @@
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;
68
69static char *sym_filter;
70static unsigned long filter_start;
71static unsigned long filter_end;
72
73static int delay_secs = 2;
74static int zero;
75static int dump_symtab;
76
77/*
78 * Symbols
79 */
80
81static uint64_t min_ip;
82static uint64_t max_ip = -1ll;
83
84struct sym_entry {
85 struct rb_node rb_node;
86 struct list_head node;
87 unsigned long count[MAX_COUNTERS];
88 unsigned long snap_count;
89 double weight;
90 int skip;
91};
92
93struct sym_entry *sym_filter_entry;
94
95struct dso *kernel_dso;
96
97/*
98 * Symbols will be added here in record_ip and will get out
99 * after decayed.
100 */
101static LIST_HEAD(active_symbols);
102static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER;
103
104/*
105 * Ordering weight: count-1 * count-2 * ... / count-n
106 */
107static double sym_weight(const struct sym_entry *sym)
108{
109 double weight = sym->snap_count;
110 int counter;
111
112 for (counter = 1; counter < nr_counters-1; counter++)
113 weight *= sym->count[counter];
114
115 weight /= (sym->count[counter] + 1);
116
117 return weight;
118}
119
120static long samples;
121static long userspace_samples;
122static const char CONSOLE_CLEAR[] = "";
123
124static void __list_insert_active_sym(struct sym_entry *syme)
125{
126 list_add(&syme->node, &active_symbols);
127}
128
129static void list_remove_active_sym(struct sym_entry *syme)
130{
131 pthread_mutex_lock(&active_symbols_lock);
132 list_del_init(&syme->node);
133 pthread_mutex_unlock(&active_symbols_lock);
134}
135
136static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
137{
138 struct rb_node **p = &tree->rb_node;
139 struct rb_node *parent = NULL;
140 struct sym_entry *iter;
141
142 while (*p != NULL) {
143 parent = *p;
144 iter = rb_entry(parent, struct sym_entry, rb_node);
145
146 if (se->weight > iter->weight)
147 p = &(*p)->rb_left;
148 else
149 p = &(*p)->rb_right;
150 }
151
152 rb_link_node(&se->rb_node, parent, p);
153 rb_insert_color(&se->rb_node, tree);
154}
155
156static void print_sym_table(void)
157{
158 int printed = 0, j;
159 int counter;
160 float samples_per_sec = samples/delay_secs;
161 float ksamples_per_sec = (samples-userspace_samples)/delay_secs;
162 float sum_ksamples = 0.0;
163 struct sym_entry *syme, *n;
164 struct rb_root tmp = RB_ROOT;
165 struct rb_node *nd;
166
167 samples = userspace_samples = 0;
168
169 /* Sort the active symbols */
170 pthread_mutex_lock(&active_symbols_lock);
171 syme = list_entry(active_symbols.next, struct sym_entry, node);
172 pthread_mutex_unlock(&active_symbols_lock);
173
174 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
175 syme->snap_count = syme->count[0];
176 if (syme->snap_count != 0) {
177 syme->weight = sym_weight(syme);
178 rb_insert_active_sym(&tmp, syme);
179 sum_ksamples += syme->snap_count;
180
181 for (j = 0; j < nr_counters; j++)
182 syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
183 } else
184 list_remove_active_sym(syme);
185 }
186
187 puts(CONSOLE_CLEAR);
188
189 printf(
190"------------------------------------------------------------------------------\n");
191 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [",
192 samples_per_sec,
193 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
194
195 if (nr_counters == 1) {
196 printf("%Ld", attrs[0].sample_period);
197 if (freq)
198 printf("Hz ");
199 else
200 printf(" ");
201 }
202
203 for (counter = 0; counter < nr_counters; counter++) {
204 if (counter)
205 printf("/");
206
207 printf("%s", event_name(counter));
208 }
209
210 printf( "], ");
211
212 if (target_pid != -1)
213 printf(" (target_pid: %d", target_pid);
214 else
215 printf(" (all");
216
217 if (profile_cpu != -1)
218 printf(", cpu: %d)\n", profile_cpu);
219 else {
220 if (target_pid != -1)
221 printf(")\n");
222 else
223 printf(", %d CPUs)\n", nr_cpus);
224 }
225
226 printf("------------------------------------------------------------------------------\n\n");
227
228 if (nr_counters == 1)
229 printf(" samples pcnt");
230 else
231 printf(" weight samples pcnt");
232
233 printf(" RIP kernel function\n"
234 " ______ _______ _____ ________________ _______________\n\n"
235 );
236
237 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
238 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
239 struct symbol *sym = (struct symbol *)(syme + 1);
240 char *color = PERF_COLOR_NORMAL;
241 double pcnt;
242
243 if (++printed > print_entries || syme->snap_count < count_filter)
244 continue;
245
246 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
247 sum_ksamples));
248
249 /*
250 * We color high-overhead entries in red, low-overhead
251 * entries in green - and keep the middle ground normal:
252 */
253 if (pcnt >= 5.0)
254 color = PERF_COLOR_RED;
255 if (pcnt < 0.5)
256 color = PERF_COLOR_GREEN;
257
258 if (nr_counters == 1)
259 printf("%20.2f - ", syme->weight);
260 else
261 printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
262
263 color_fprintf(stdout, color, "%4.1f%%", pcnt);
264 printf(" - %016llx : %s\n", sym->start, sym->name);
265 }
266}
267
268static void *display_thread(void *arg)
269{
270 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
271 int delay_msecs = delay_secs * 1000;
272
273 printf("PerfTop refresh period: %d seconds\n", delay_secs);
274
275 do {
276 print_sym_table();
277 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
278
279 printf("key pressed - exiting.\n");
280 exit(0);
281
282 return NULL;
283}
284
285static int symbol_filter(struct dso *self, struct symbol *sym)
286{
287 static int filter_match;
288 struct sym_entry *syme;
289 const char *name = sym->name;
290
291 if (!strcmp(name, "_text") ||
292 !strcmp(name, "_etext") ||
293 !strcmp(name, "_sinittext") ||
294 !strncmp("init_module", name, 11) ||
295 !strncmp("cleanup_module", name, 14) ||
296 strstr(name, "_text_start") ||
297 strstr(name, "_text_end"))
298 return 1;
299
300 syme = dso__sym_priv(self, sym);
301 /* Tag samples to be skipped. */
302 if (!strcmp("default_idle", name) ||
303 !strcmp("cpu_idle", name) ||
304 !strcmp("enter_idle", name) ||
305 !strcmp("exit_idle", name) ||
306 !strcmp("mwait_idle", name))
307 syme->skip = 1;
308
309 if (filter_match == 1) {
310 filter_end = sym->start;
311 filter_match = -1;
312 if (filter_end - filter_start > 10000) {
313 fprintf(stderr,
314 "hm, too large filter symbol <%s> - skipping.\n",
315 sym_filter);
316 fprintf(stderr, "symbol filter start: %016lx\n",
317 filter_start);
318 fprintf(stderr, " end: %016lx\n",
319 filter_end);
320 filter_end = filter_start = 0;
321 sym_filter = NULL;
322 sleep(1);
323 }
324 }
325
326 if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) {
327 filter_match = 1;
328 filter_start = sym->start;
329 }
330
331
332 return 0;
333}
334
335static int parse_symbols(void)
336{
337 struct rb_node *node;
338 struct symbol *sym;
339
340 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
341 if (kernel_dso == NULL)
342 return -1;
343
344 if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0)
345 goto out_delete_dso;
346
347 node = rb_first(&kernel_dso->syms);
348 sym = rb_entry(node, struct symbol, rb_node);
349 min_ip = sym->start;
350
351 node = rb_last(&kernel_dso->syms);
352 sym = rb_entry(node, struct symbol, rb_node);
353 max_ip = sym->end;
354
355 if (dump_symtab)
356 dso__fprintf(kernel_dso, stderr);
357
358 return 0;
359
360out_delete_dso:
361 dso__delete(kernel_dso);
362 kernel_dso = NULL;
363 return -1;
364}
365
366#define TRACE_COUNT 3
367
368/*
369 * Binary search in the histogram table and record the hit:
370 */
371static void record_ip(uint64_t ip, int counter)
372{
373 struct symbol *sym = dso__find_symbol(kernel_dso, ip);
374
375 if (sym != NULL) {
376 struct sym_entry *syme = dso__sym_priv(kernel_dso, sym);
377
378 if (!syme->skip) {
379 syme->count[counter]++;
380 pthread_mutex_lock(&active_symbols_lock);
381 if (list_empty(&syme->node) || !syme->node.next)
382 __list_insert_active_sym(syme);
383 pthread_mutex_unlock(&active_symbols_lock);
384 return;
385 }
386 }
387
388 samples--;
389}
390
391static void process_event(uint64_t ip, int counter)
392{
393 samples++;
394
395 if (ip < min_ip || ip > max_ip) {
396 userspace_samples++;
397 return;
398 }
399
400 record_ip(ip, counter);
401}
402
403struct mmap_data {
404 int counter;
405 void *base;
406 unsigned int mask;
407 unsigned int prev;
408};
409
410static unsigned int mmap_read_head(struct mmap_data *md)
411{
412 struct perf_counter_mmap_page *pc = md->base;
413 int head;
414
415 head = pc->data_head;
416 rmb();
417
418 return head;
419}
420
421struct timeval last_read, this_read;
422
423static void mmap_read(struct mmap_data *md)
424{
425 unsigned int head = mmap_read_head(md);
426 unsigned int old = md->prev;
427 unsigned char *data = md->base + page_size;
428 int diff;
429
430 gettimeofday(&this_read, NULL);
431
432 /*
433 * If we're further behind than half the buffer, there's a chance
434 * the writer will bite our tail and mess up the samples under us.
435 *
436 * If we somehow ended up ahead of the head, we got messed up.
437 *
438 * In either case, truncate and restart at head.
439 */
440 diff = head - old;
441 if (diff > md->mask / 2 || diff < 0) {
442 struct timeval iv;
443 unsigned long msecs;
444
445 timersub(&this_read, &last_read, &iv);
446 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
447
448 fprintf(stderr, "WARNING: failed to keep up with mmap data."
449 " Last read %lu msecs ago.\n", msecs);
450
451 /*
452 * head points to a known good entry, start there.
453 */
454 old = head;
455 }
456
457 last_read = this_read;
458
459 for (; old != head;) {
460 struct ip_event {
461 struct perf_event_header header;
462 __u64 ip;
463 __u32 pid, target_pid;
464 };
465 struct mmap_event {
466 struct perf_event_header header;
467 __u32 pid, target_pid;
468 __u64 start;
469 __u64 len;
470 __u64 pgoff;
471 char filename[PATH_MAX];
472 };
473
474 typedef union event_union {
475 struct perf_event_header header;
476 struct ip_event ip;
477 struct mmap_event mmap;
478 } event_t;
479
480 event_t *event = (event_t *)&data[old & md->mask];
481
482 event_t event_copy;
483
484 size_t size = event->header.size;
485
486 /*
487 * Event straddles the mmap boundary -- header should always
488 * be inside due to u64 alignment of output.
489 */
490 if ((old & md->mask) + size != ((old + size) & md->mask)) {
491 unsigned int offset = old;
492 unsigned int len = min(sizeof(*event), size), cpy;
493 void *dst = &event_copy;
494
495 do {
496 cpy = min(md->mask + 1 - (offset & md->mask), len);
497 memcpy(dst, &data[offset & md->mask], cpy);
498 offset += cpy;
499 dst += cpy;
500 len -= cpy;
501 } while (len);
502
503 event = &event_copy;
504 }
505
506 old += size;
507
508 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
509 if (event->header.type & PERF_SAMPLE_IP)
510 process_event(event->ip.ip, md->counter);
511 }
512 }
513
514 md->prev = old;
515}
516
517static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
518static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
519
520static int __cmd_top(void)
521{
522 struct perf_counter_attr *attr;
523 pthread_t thread;
524 int i, counter, group_fd, nr_poll = 0;
525 unsigned int cpu;
526 int ret;
527
528 for (i = 0; i < nr_cpus; i++) {
529 group_fd = -1;
530 for (counter = 0; counter < nr_counters; counter++) {
531
532 cpu = profile_cpu;
533 if (target_pid == -1 && profile_cpu == -1)
534 cpu = i;
535
536 attr = attrs + counter;
537
538 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
539 attr->freq = freq;
540
541 fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0);
542 if (fd[i][counter] < 0) {
543 int err = errno;
544
545 error("syscall returned with %d (%s)\n",
546 fd[i][counter], strerror(err));
547 if (err == EPERM)
548 printf("Are you root?\n");
549 exit(-1);
550 }
551 assert(fd[i][counter] >= 0);
552 fcntl(fd[i][counter], F_SETFL, O_NONBLOCK);
553
554 /*
555 * First counter acts as the group leader:
556 */
557 if (group && group_fd == -1)
558 group_fd = fd[i][counter];
559
560 event_array[nr_poll].fd = fd[i][counter];
561 event_array[nr_poll].events = POLLIN;
562 nr_poll++;
563
564 mmap_array[i][counter].counter = counter;
565 mmap_array[i][counter].prev = 0;
566 mmap_array[i][counter].mask = mmap_pages*page_size - 1;
567 mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
568 PROT_READ, MAP_SHARED, fd[i][counter], 0);
569 if (mmap_array[i][counter].base == MAP_FAILED)
570 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
571 }
572 }
573
574 if (pthread_create(&thread, NULL, display_thread, NULL)) {
575 printf("Could not create display thread.\n");
576 exit(-1);
577 }
578
579 if (realtime_prio) {
580 struct sched_param param;
581
582 param.sched_priority = realtime_prio;
583 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
584 printf("Could not set realtime priority.\n");
585 exit(-1);
586 }
587 }
588
589 while (1) {
590 int hits = samples;
591
592 for (i = 0; i < nr_cpus; i++) {
593 for (counter = 0; counter < nr_counters; counter++)
594 mmap_read(&mmap_array[i][counter]);
595 }
596
597 if (hits == samples)
598 ret = poll(event_array, nr_poll, 100);
599 }
600
601 return 0;
602}
603
604static const char * const top_usage[] = {
605 "perf top [<options>]",
606 NULL
607};
608
609static const struct option options[] = {
610 OPT_CALLBACK('e', "event", NULL, "event",
611 "event selector. use 'perf list' to list available events",
612 parse_events),
613 OPT_INTEGER('c', "count", &default_interval,
614 "event period to sample"),
615 OPT_INTEGER('p', "pid", &target_pid,
616 "profile events on existing pid"),
617 OPT_BOOLEAN('a', "all-cpus", &system_wide,
618 "system-wide collection from all CPUs"),
619 OPT_INTEGER('C', "CPU", &profile_cpu,
620 "CPU to profile on"),
621 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
622 "number of mmap data pages"),
623 OPT_INTEGER('r', "realtime", &realtime_prio,
624 "collect data with this RT SCHED_FIFO priority"),
625 OPT_INTEGER('d', "delay", &delay_secs,
626 "number of seconds to delay between refreshes"),
627 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
628 "dump the symbol table used for profiling"),
629 OPT_INTEGER('f', "count-filter", &count_filter,
630 "only display functions with more events than this"),
631 OPT_BOOLEAN('g', "group", &group,
632 "put the counters into a counter group"),
633 OPT_STRING('s', "sym-filter", &sym_filter, "pattern",
634 "only display symbols matchig this pattern"),
635 OPT_BOOLEAN('z', "zero", &group,
636 "zero history across updates"),
637 OPT_INTEGER('F', "freq", &freq,
638 "profile at this frequency"),
639 OPT_INTEGER('E', "entries", &print_entries,
640 "display this many functions"),
641 OPT_END()
642};
643
644int cmd_top(int argc, const char **argv, const char *prefix)
645{
646 int counter;
647
648 page_size = sysconf(_SC_PAGE_SIZE);
649
650 argc = parse_options(argc, argv, options, top_usage, 0);
651 if (argc)
652 usage_with_options(top_usage, options);
653
654 if (freq) {
655 default_interval = freq;
656 freq = 1;
657 }
658
659 /* CPU and PID are mutually exclusive */
660 if (target_pid != -1 && profile_cpu != -1) {
661 printf("WARNING: PID switch overriding CPU\n");
662 sleep(1);
663 profile_cpu = -1;
664 }
665
666 if (!nr_counters)
667 nr_counters = 1;
668
669 if (delay_secs < 1)
670 delay_secs = 1;
671
672 parse_symbols();
673
674 /*
675 * Fill in the ones not specifically initialized via -c:
676 */
677 for (counter = 0; counter < nr_counters; counter++) {
678 if (attrs[counter].sample_period)
679 continue;
680
681 attrs[counter].sample_period = default_interval;
682 }
683
684 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
685 assert(nr_cpus <= MAX_NR_CPUS);
686 assert(nr_cpus >= 0);
687
688 if (target_pid != -1 || profile_cpu != -1)
689 nr_cpus = 1;
690
691 return __cmd_top();
692}
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..d3250763dc92
--- /dev/null
+++ b/tools/perf/design.txt
@@ -0,0 +1,442 @@
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_CPU_CYCLES = 0,
103 PERF_COUNT_INSTRUCTIONS = 1,
104 PERF_COUNT_CACHE_REFERENCES = 2,
105 PERF_COUNT_CACHE_MISSES = 3,
106 PERF_COUNT_BRANCH_INSTRUCTIONS = 4,
107 PERF_COUNT_BRANCH_MISSES = 5,
108 PERF_COUNT_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_CPU_CLOCK = 0,
134 PERF_COUNT_TASK_CLOCK = 1,
135 PERF_COUNT_PAGE_FAULTS = 2,
136 PERF_COUNT_CONTEXT_SWITCHES = 3,
137 PERF_COUNT_CPU_MIGRATIONS = 4,
138 PERF_COUNT_PAGE_FAULTS_MIN = 5,
139 PERF_COUNT_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
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..af0a5046d743
--- /dev/null
+++ b/tools/perf/perf.h
@@ -0,0 +1,67 @@
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#include <time.h>
17#include <unistd.h>
18#include <sys/types.h>
19#include <sys/syscall.h>
20
21#include "../../include/linux/perf_counter.h"
22
23/*
24 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
25 * counters in the current task.
26 */
27#define PR_TASK_PERF_COUNTERS_DISABLE 31
28#define PR_TASK_PERF_COUNTERS_ENABLE 32
29
30#ifndef NSEC_PER_SEC
31# define NSEC_PER_SEC 1000000000ULL
32#endif
33
34static inline unsigned long long rdclock(void)
35{
36 struct timespec ts;
37
38 clock_gettime(CLOCK_MONOTONIC, &ts);
39 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
40}
41
42/*
43 * Pick up some kernel type conventions:
44 */
45#define __user
46#define asmlinkage
47
48#define unlikely(x) __builtin_expect(!!(x), 0)
49#define min(x, y) ({ \
50 typeof(x) _min1 = (x); \
51 typeof(y) _min2 = (y); \
52 (void) (&_min1 == &_min2); \
53 _min1 < _min2 ? _min1 : _min2; })
54
55static inline int
56sys_perf_counter_open(struct perf_counter_attr *attr_uptr,
57 pid_t pid, int cpu, int group_fd,
58 unsigned long flags)
59{
60 return syscall(__NR_perf_counter_open, attr_uptr, pid, cpu,
61 group_fd, flags);
62}
63
64#define MAX_COUNTERS 256
65#define MAX_NR_CPUS 256
66
67#endif
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
new file mode 100755
index 000000000000..c561d1538c03
--- /dev/null
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -0,0 +1,42 @@
1#!/bin/sh
2
3GVF=PERF-VERSION-FILE
4DEF_VER=v0.0.1.PERF
5
6LF='
7'
8
9# First see if there is a version file (included in release tarballs),
10# then try git-describe, then default.
11if test -f version
12then
13 VN=$(cat version) || VN="$DEF_VER"
14elif test -d .git -o -f .git &&
15 VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
16 case "$VN" in
17 *$LF*) (exit 1) ;;
18 v[0-9]*)
19 git update-index -q --refresh
20 test -z "$(git diff-index --name-only HEAD --)" ||
21 VN="$VN-dirty" ;;
22 esac
23then
24 VN=$(echo "$VN" | sed -e 's/-/./g');
25else
26 VN="$DEF_VER"
27fi
28
29VN=$(expr "$VN" : v*'\(.*\)')
30
31if test -r $GVF
32then
33 VC=$(sed -e 's/^PERF_VERSION = //' <$GVF)
34else
35 VC=unset
36fi
37test "$VN" = "$VC" || {
38 echo >&2 "PERF_VERSION = $VN"
39 echo "PERF_VERSION = $VN" >$GVF
40}
41
42
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
new file mode 100644
index 000000000000..61d33b81fc97
--- /dev/null
+++ b/tools/perf/util/abspath.c
@@ -0,0 +1,117 @@
1#include "cache.h"
2
3/*
4 * Do not use this for inspecting *tracked* content. When path is a
5 * symlink to a directory, we do not want to say it is a directory when
6 * dealing with tracked content in the working tree.
7 */
8static int is_directory(const char *path)
9{
10 struct stat st;
11 return (!stat(path, &st) && S_ISDIR(st.st_mode));
12}
13
14/* We allow "recursive" symbolic links. Only within reason, though. */
15#define MAXDEPTH 5
16
17const char *make_absolute_path(const char *path)
18{
19 static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
20 char cwd[1024] = "";
21 int buf_index = 1, len;
22
23 int depth = MAXDEPTH;
24 char *last_elem = NULL;
25 struct stat st;
26
27 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
28 die ("Too long path: %.*s", 60, path);
29
30 while (depth--) {
31 if (!is_directory(buf)) {
32 char *last_slash = strrchr(buf, '/');
33 if (last_slash) {
34 *last_slash = '\0';
35 last_elem = xstrdup(last_slash + 1);
36 } else {
37 last_elem = xstrdup(buf);
38 *buf = '\0';
39 }
40 }
41
42 if (*buf) {
43 if (!*cwd && !getcwd(cwd, sizeof(cwd)))
44 die ("Could not get current working directory");
45
46 if (chdir(buf))
47 die ("Could not switch to '%s'", buf);
48 }
49 if (!getcwd(buf, PATH_MAX))
50 die ("Could not get current working directory");
51
52 if (last_elem) {
53 int len = strlen(buf);
54 if (len + strlen(last_elem) + 2 > PATH_MAX)
55 die ("Too long path name: '%s/%s'",
56 buf, last_elem);
57 buf[len] = '/';
58 strcpy(buf + len + 1, last_elem);
59 free(last_elem);
60 last_elem = NULL;
61 }
62
63 if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
64 len = readlink(buf, next_buf, PATH_MAX);
65 if (len < 0)
66 die ("Invalid symlink: %s", buf);
67 if (PATH_MAX <= len)
68 die("symbolic link too long: %s", buf);
69 next_buf[len] = '\0';
70 buf = next_buf;
71 buf_index = 1 - buf_index;
72 next_buf = bufs[buf_index];
73 } else
74 break;
75 }
76
77 if (*cwd && chdir(cwd))
78 die ("Could not change back to '%s'", cwd);
79
80 return buf;
81}
82
83static const char *get_pwd_cwd(void)
84{
85 static char cwd[PATH_MAX + 1];
86 char *pwd;
87 struct stat cwd_stat, pwd_stat;
88 if (getcwd(cwd, PATH_MAX) == NULL)
89 return NULL;
90 pwd = getenv("PWD");
91 if (pwd && strcmp(pwd, cwd)) {
92 stat(cwd, &cwd_stat);
93 if (!stat(pwd, &pwd_stat) &&
94 pwd_stat.st_dev == cwd_stat.st_dev &&
95 pwd_stat.st_ino == cwd_stat.st_ino) {
96 strlcpy(cwd, pwd, PATH_MAX);
97 }
98 }
99 return cwd;
100}
101
102const char *make_nonrelative_path(const char *path)
103{
104 static char buf[PATH_MAX + 1];
105
106 if (is_absolute_path(path)) {
107 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
108 die("Too long path: %.*s", 60, path);
109 } else {
110 const char *cwd = get_pwd_cwd();
111 if (!cwd)
112 die("Cannot determine the current working directory");
113 if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
114 die("Too long path: %.*s", 60, path);
115 }
116 return buf;
117}
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
new file mode 100644
index 000000000000..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..b90ec004f29c
--- /dev/null
+++ b/tools/perf/util/ctype.c
@@ -0,0 +1,26 @@
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};
15
16unsigned char sane_ctype[256] = {
17 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */
18 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */
19 S, 0, 0, 0, R, 0, 0, 0, R, R, G, R, 0, 0, R, 0, /* 32.. 47 */
20 D, D, D, D, D, D, D, D, D, D, 0, 0, 0, 0, 0, G, /* 48.. 63 */
21 0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */
22 A, A, A, A, A, A, A, A, A, A, A, G, G, 0, R, 0, /* 80.. 95 */
23 0, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */
24 A, A, A, A, A, A, A, A, A, A, A, R, R, 0, 0, 0, /* 112..127 */
25 /* Nothing in the 128.. range */
26};
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..e0820b4388ae
--- /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, CPU_CYCLES), "cpu-cycles", },
26 { C(HARDWARE, CPU_CYCLES), "cycles", },
27 { C(HARDWARE, INSTRUCTIONS), "instructions", },
28 { C(HARDWARE, CACHE_REFERENCES), "cache-references", },
29 { C(HARDWARE, CACHE_MISSES), "cache-misses", },
30 { C(HARDWARE, BRANCH_INSTRUCTIONS), "branch-instructions", },
31 { C(HARDWARE, BRANCH_INSTRUCTIONS), "branches", },
32 { C(HARDWARE, BRANCH_MISSES), "branch-misses", },
33 { C(HARDWARE, BUS_CYCLES), "bus-cycles", },
34
35 { C(SOFTWARE, CPU_CLOCK), "cpu-clock", },
36 { C(SOFTWARE, TASK_CLOCK), "task-clock", },
37 { C(SOFTWARE, PAGE_FAULTS), "page-faults", },
38 { C(SOFTWARE, PAGE_FAULTS), "faults", },
39 { C(SOFTWARE, PAGE_FAULTS_MIN), "minor-faults", },
40 { C(SOFTWARE, PAGE_FAULTS_MAJ), "major-faults", },
41 { C(SOFTWARE, CONTEXT_SWITCHES), "context-switches", },
42 { C(SOFTWARE, CONTEXT_SWITCHES), "cs", },
43 { C(SOFTWARE, CPU_MIGRATIONS), "cpu-migrations", },
44 { C(SOFTWARE, 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-ticks",
67 "task-clock-ticks",
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", "l1" },
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_HW_EVENTS_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_SW_EVENTS_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 0;
164}
165
166static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
167{
168 __u8 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_type == -1)
183 cache_type = 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..ec33c0c7f4e2
--- /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..72812c1c9a7a
--- /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 <linux/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..23f4f7b3b83d
--- /dev/null
+++ b/tools/perf/util/symbol.c
@@ -0,0 +1,574 @@
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(uint64_t start, uint64_t len,
13 const char *name, unsigned int priv_size,
14 uint64_t 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, len, name, self->hist, (void *)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 uint64_t 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, uint64_t 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
223/**
224 * elf_symtab__for_each_symbol - iterate thru all the symbols
225 *
226 * @self: struct elf_symtab instance to iterate
227 * @index: uint32_t index
228 * @sym: GElf_Sym iterator
229 */
230#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
231 for (index = 0, gelf_getsym(syms, index, &sym);\
232 index < nr_syms; \
233 index++, gelf_getsym(syms, index, &sym))
234
235static inline uint8_t elf_sym__type(const GElf_Sym *sym)
236{
237 return GELF_ST_TYPE(sym->st_info);
238}
239
240static inline int elf_sym__is_function(const GElf_Sym *sym)
241{
242 return elf_sym__type(sym) == STT_FUNC &&
243 sym->st_name != 0 &&
244 sym->st_shndx != SHN_UNDEF &&
245 sym->st_size != 0;
246}
247
248static inline const char *elf_sym__name(const GElf_Sym *sym,
249 const Elf_Data *symstrs)
250{
251 return symstrs->d_buf + sym->st_name;
252}
253
254static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
255 GElf_Shdr *shp, const char *name,
256 size_t *index)
257{
258 Elf_Scn *sec = NULL;
259 size_t cnt = 1;
260
261 while ((sec = elf_nextscn(elf, sec)) != NULL) {
262 char *str;
263
264 gelf_getshdr(sec, shp);
265 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
266 if (!strcmp(name, str)) {
267 if (index)
268 *index = cnt;
269 break;
270 }
271 ++cnt;
272 }
273
274 return sec;
275}
276
277#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
278 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
279 idx < nr_entries; \
280 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
281
282#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
283 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
284 idx < nr_entries; \
285 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
286
287static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
288 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym,
289 GElf_Shdr *shdr_dynsym,
290 size_t dynsym_idx, int verbose)
291{
292 uint32_t nr_rel_entries, idx;
293 GElf_Sym sym;
294 __u64 plt_offset;
295 GElf_Shdr shdr_plt;
296 struct symbol *f;
297 GElf_Shdr shdr_rel_plt;
298 Elf_Data *reldata, *syms, *symstrs;
299 Elf_Scn *scn_plt_rel, *scn_symstrs;
300 char sympltname[1024];
301 int nr = 0, symidx;
302
303 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
304 ".rela.plt", NULL);
305 if (scn_plt_rel == NULL) {
306 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
307 ".rel.plt", NULL);
308 if (scn_plt_rel == NULL)
309 return 0;
310 }
311
312 if (shdr_rel_plt.sh_link != dynsym_idx)
313 return 0;
314
315 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL)
316 return 0;
317
318 /*
319 * Fetch the relocation section to find the indexes to the GOT
320 * and the symbols in the .dynsym they refer to.
321 */
322 reldata = elf_getdata(scn_plt_rel, NULL);
323 if (reldata == NULL)
324 return -1;
325
326 syms = elf_getdata(scn_dynsym, NULL);
327 if (syms == NULL)
328 return -1;
329
330 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link);
331 if (scn_symstrs == NULL)
332 return -1;
333
334 symstrs = elf_getdata(scn_symstrs, NULL);
335 if (symstrs == NULL)
336 return -1;
337
338 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
339 plt_offset = shdr_plt.sh_offset;
340
341 if (shdr_rel_plt.sh_type == SHT_RELA) {
342 GElf_Rela pos_mem, *pos;
343
344 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
345 nr_rel_entries) {
346 symidx = GELF_R_SYM(pos->r_info);
347 plt_offset += shdr_plt.sh_entsize;
348 gelf_getsym(syms, symidx, &sym);
349 snprintf(sympltname, sizeof(sympltname),
350 "%s@plt", elf_sym__name(&sym, symstrs));
351
352 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
353 sympltname, self->sym_priv_size, 0, verbose);
354 if (!f)
355 return -1;
356
357 dso__insert_symbol(self, f);
358 ++nr;
359 }
360 } else if (shdr_rel_plt.sh_type == SHT_REL) {
361 GElf_Rel pos_mem, *pos;
362 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
363 nr_rel_entries) {
364 symidx = GELF_R_SYM(pos->r_info);
365 plt_offset += shdr_plt.sh_entsize;
366 gelf_getsym(syms, symidx, &sym);
367 snprintf(sympltname, sizeof(sympltname),
368 "%s@plt", elf_sym__name(&sym, symstrs));
369
370 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
371 sympltname, self->sym_priv_size, 0, verbose);
372 if (!f)
373 return -1;
374
375 dso__insert_symbol(self, f);
376 ++nr;
377 }
378 } else {
379 /*
380 * TODO: There are still one more shdr_rel_plt.sh_type
381 * I have to investigate, but probably should be ignored.
382 */
383 }
384
385 return nr;
386}
387
388static int dso__load_sym(struct dso *self, int fd, const char *name,
389 symbol_filter_t filter, int verbose)
390{
391 Elf_Data *symstrs;
392 uint32_t nr_syms;
393 int err = -1;
394 uint32_t index;
395 GElf_Ehdr ehdr;
396 GElf_Shdr shdr;
397 Elf_Data *syms;
398 GElf_Sym sym;
399 Elf_Scn *sec, *sec_dynsym;
400 Elf *elf;
401 size_t dynsym_idx;
402 int nr = 0;
403
404 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
405 if (elf == NULL) {
406 if (verbose)
407 fprintf(stderr, "%s: cannot read %s ELF file.\n",
408 __func__, name);
409 goto out_close;
410 }
411
412 if (gelf_getehdr(elf, &ehdr) == NULL) {
413 if (verbose)
414 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
415 goto out_elf_end;
416 }
417
418 /*
419 * We need to check if we have a .dynsym, so that we can handle the
420 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
421 * .dynsym or .symtab)
422 */
423 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
424 ".dynsym", &dynsym_idx);
425 if (sec_dynsym != NULL) {
426 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
427 sec_dynsym, &shdr,
428 dynsym_idx, verbose);
429 if (nr < 0)
430 goto out_elf_end;
431 }
432
433 /*
434 * But if we have a full .symtab (that is a superset of .dynsym) we
435 * should add the symbols not in the .dynsyn
436 */
437 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
438 if (sec == NULL) {
439 if (sec_dynsym == NULL)
440 goto out_elf_end;
441
442 sec = sec_dynsym;
443 gelf_getshdr(sec, &shdr);
444 }
445
446 syms = elf_getdata(sec, NULL);
447 if (syms == NULL)
448 goto out_elf_end;
449
450 sec = elf_getscn(elf, shdr.sh_link);
451 if (sec == NULL)
452 goto out_elf_end;
453
454 symstrs = elf_getdata(sec, NULL);
455 if (symstrs == NULL)
456 goto out_elf_end;
457
458 nr_syms = shdr.sh_size / shdr.sh_entsize;
459
460 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
461 struct symbol *f;
462 uint64_t obj_start;
463
464 if (!elf_sym__is_function(&sym))
465 continue;
466
467 sec = elf_getscn(elf, sym.st_shndx);
468 if (!sec)
469 goto out_elf_end;
470
471 gelf_getshdr(sec, &shdr);
472 obj_start = sym.st_value;
473
474 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
475
476 f = symbol__new(sym.st_value, sym.st_size,
477 elf_sym__name(&sym, symstrs),
478 self->sym_priv_size, obj_start, verbose);
479 if (!f)
480 goto out_elf_end;
481
482 if (filter && filter(self, f))
483 symbol__delete(f, self->sym_priv_size);
484 else {
485 dso__insert_symbol(self, f);
486 nr++;
487 }
488 }
489
490 err = nr;
491out_elf_end:
492 elf_end(elf);
493out_close:
494 return err;
495}
496
497int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
498{
499 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
500 char *name = malloc(size);
501 int variant = 0;
502 int ret = -1;
503 int fd;
504
505 if (!name)
506 return -1;
507
508more:
509 do {
510 switch (variant) {
511 case 0: /* Fedora */
512 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
513 break;
514 case 1: /* Ubuntu */
515 snprintf(name, size, "/usr/lib/debug%s", self->name);
516 break;
517 case 2: /* Sane people */
518 snprintf(name, size, "%s", self->name);
519 break;
520
521 default:
522 goto out;
523 }
524 variant++;
525
526 fd = open(name, O_RDONLY);
527 } while (fd < 0);
528
529 ret = dso__load_sym(self, fd, name, filter, verbose);
530 close(fd);
531
532 /*
533 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
534 */
535 if (!ret)
536 goto more;
537
538out:
539 free(name);
540 return ret;
541}
542
543static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
544 symbol_filter_t filter, int verbose)
545{
546 int err, fd = open(vmlinux, O_RDONLY);
547
548 if (fd < 0)
549 return -1;
550
551 err = dso__load_sym(self, fd, vmlinux, filter, verbose);
552 close(fd);
553
554 return err;
555}
556
557int dso__load_kernel(struct dso *self, const char *vmlinux,
558 symbol_filter_t filter, int verbose)
559{
560 int err = -1;
561
562 if (vmlinux)
563 err = dso__load_vmlinux(self, vmlinux, filter, verbose);
564
565 if (err)
566 err = dso__load_kallsyms(self, filter, verbose);
567
568 return err;
569}
570
571void symbol__init(void)
572{
573 elf_version(EV_CURRENT);
574}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
new file mode 100644
index 000000000000..4839d68f14f0
--- /dev/null
+++ b/tools/perf/util/symbol.h
@@ -0,0 +1,47 @@
1#ifndef _PERF_SYMBOL_
2#define _PERF_SYMBOL_ 1
3
4#include <linux/types.h>
5#include "list.h"
6#include "rbtree.h"
7
8struct symbol {
9 struct rb_node rb_node;
10 __u64 start;
11 __u64 end;
12 __u64 obj_start;
13 __u64 hist_sum;
14 __u64 *hist;
15 char name[0];
16};
17
18struct dso {
19 struct list_head node;
20 struct rb_root syms;
21 unsigned int sym_priv_size;
22 struct symbol *(*find_symbol)(struct dso *, uint64_t ip);
23 char name[0];
24};
25
26const char *sym_hist_filter;
27
28typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
29
30struct dso *dso__new(const char *name, unsigned int sym_priv_size);
31void dso__delete(struct dso *self);
32
33static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
34{
35 return ((void *)sym) - self->sym_priv_size;
36}
37
38struct symbol *dso__find_symbol(struct dso *self, uint64_t ip);
39
40int dso__load_kernel(struct dso *self, const char *vmlinux,
41 symbol_filter_t filter, int verbose);
42int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
43
44size_t dso__fprintf(struct dso *self, FILE *fp);
45
46void symbol__init(void);
47#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
new file mode 100644
index 000000000000..2cad286e4371
--- /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..76590a16c271
--- /dev/null
+++ b/tools/perf/util/util.h
@@ -0,0 +1,410 @@
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#ifndef NO_OPENSSL
104#include <openssl/ssl.h>
105#include <openssl/err.h>
106#endif
107
108/* On most systems <limits.h> would have given us this, but
109 * not on some systems (e.g. GNU/Hurd).
110 */
111#ifndef PATH_MAX
112#define PATH_MAX 4096
113#endif
114
115#ifndef PRIuMAX
116#define PRIuMAX "llu"
117#endif
118
119#ifndef PRIu32
120#define PRIu32 "u"
121#endif
122
123#ifndef PRIx32
124#define PRIx32 "x"
125#endif
126
127#ifndef PATH_SEP
128#define PATH_SEP ':'
129#endif
130
131#ifndef STRIP_EXTENSION
132#define STRIP_EXTENSION ""
133#endif
134
135#ifndef has_dos_drive_prefix
136#define has_dos_drive_prefix(path) 0
137#endif
138
139#ifndef is_dir_sep
140#define is_dir_sep(c) ((c) == '/')
141#endif
142
143#ifdef __GNUC__
144#define NORETURN __attribute__((__noreturn__))
145#else
146#define NORETURN
147#ifndef __attribute__
148#define __attribute__(x)
149#endif
150#endif
151
152/* General helper functions */
153extern void usage(const char *err) NORETURN;
154extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
155extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
156extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
157
158extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
159
160extern int prefixcmp(const char *str, const char *prefix);
161extern time_t tm_to_time_t(const struct tm *tm);
162
163static inline const char *skip_prefix(const char *str, const char *prefix)
164{
165 size_t len = strlen(prefix);
166 return strncmp(str, prefix, len) ? NULL : str + len;
167}
168
169#if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
170
171#ifndef PROT_READ
172#define PROT_READ 1
173#define PROT_WRITE 2
174#define MAP_PRIVATE 1
175#define MAP_FAILED ((void*)-1)
176#endif
177
178#define mmap git_mmap
179#define munmap git_munmap
180extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
181extern int git_munmap(void *start, size_t length);
182
183#else /* NO_MMAP || USE_WIN32_MMAP */
184
185#include <sys/mman.h>
186
187#endif /* NO_MMAP || USE_WIN32_MMAP */
188
189#ifdef NO_MMAP
190
191/* This value must be multiple of (pagesize * 2) */
192#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024)
193
194#else /* NO_MMAP */
195
196/* This value must be multiple of (pagesize * 2) */
197#define DEFAULT_PACKED_GIT_WINDOW_SIZE \
198 (sizeof(void*) >= 8 \
199 ? 1 * 1024 * 1024 * 1024 \
200 : 32 * 1024 * 1024)
201
202#endif /* NO_MMAP */
203
204#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
205#define on_disk_bytes(st) ((st).st_size)
206#else
207#define on_disk_bytes(st) ((st).st_blocks * 512)
208#endif
209
210#define DEFAULT_PACKED_GIT_LIMIT \
211 ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
212
213#ifdef NO_PREAD
214#define pread git_pread
215extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
216#endif
217/*
218 * Forward decl that will remind us if its twin in cache.h changes.
219 * This function is used in compat/pread.c. But we can't include
220 * cache.h there.
221 */
222extern ssize_t read_in_full(int fd, void *buf, size_t count);
223
224#ifdef NO_SETENV
225#define setenv gitsetenv
226extern int gitsetenv(const char *, const char *, int);
227#endif
228
229#ifdef NO_MKDTEMP
230#define mkdtemp gitmkdtemp
231extern char *gitmkdtemp(char *);
232#endif
233
234#ifdef NO_UNSETENV
235#define unsetenv gitunsetenv
236extern void gitunsetenv(const char *);
237#endif
238
239#ifdef NO_STRCASESTR
240#define strcasestr gitstrcasestr
241extern char *gitstrcasestr(const char *haystack, const char *needle);
242#endif
243
244#ifdef NO_STRLCPY
245#define strlcpy gitstrlcpy
246extern size_t gitstrlcpy(char *, const char *, size_t);
247#endif
248
249#ifdef NO_STRTOUMAX
250#define strtoumax gitstrtoumax
251extern uintmax_t gitstrtoumax(const char *, char **, int);
252#endif
253
254#ifdef NO_HSTRERROR
255#define hstrerror githstrerror
256extern const char *githstrerror(int herror);
257#endif
258
259#ifdef NO_MEMMEM
260#define memmem gitmemmem
261void *gitmemmem(const void *haystack, size_t haystacklen,
262 const void *needle, size_t needlelen);
263#endif
264
265#ifdef FREAD_READS_DIRECTORIES
266#ifdef fopen
267#undef fopen
268#endif
269#define fopen(a,b) git_fopen(a,b)
270extern FILE *git_fopen(const char*, const char*);
271#endif
272
273#ifdef SNPRINTF_RETURNS_BOGUS
274#define snprintf git_snprintf
275extern int git_snprintf(char *str, size_t maxsize,
276 const char *format, ...);
277#define vsnprintf git_vsnprintf
278extern int git_vsnprintf(char *str, size_t maxsize,
279 const char *format, va_list ap);
280#endif
281
282#ifdef __GLIBC_PREREQ
283#if __GLIBC_PREREQ(2, 1)
284#define HAVE_STRCHRNUL
285#endif
286#endif
287
288#ifndef HAVE_STRCHRNUL
289#define strchrnul gitstrchrnul
290static inline char *gitstrchrnul(const char *s, int c)
291{
292 while (*s && *s != c)
293 s++;
294 return (char *)s;
295}
296#endif
297
298/*
299 * Wrappers:
300 */
301extern char *xstrdup(const char *str);
302extern void *xmalloc(size_t size);
303extern void *xmemdupz(const void *data, size_t len);
304extern char *xstrndup(const char *str, size_t len);
305extern void *xrealloc(void *ptr, size_t size);
306extern void *xcalloc(size_t nmemb, size_t size);
307extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
308extern ssize_t xread(int fd, void *buf, size_t len);
309extern ssize_t xwrite(int fd, const void *buf, size_t len);
310extern int xdup(int fd);
311extern FILE *xfdopen(int fd, const char *mode);
312extern int xmkstemp(char *template);
313
314static inline size_t xsize_t(off_t len)
315{
316 return (size_t)len;
317}
318
319static inline int has_extension(const char *filename, const char *ext)
320{
321 size_t len = strlen(filename);
322 size_t extlen = strlen(ext);
323 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
324}
325
326/* Sane ctype - no locale, and works with signed chars */
327#undef isascii
328#undef isspace
329#undef isdigit
330#undef isalpha
331#undef isalnum
332#undef tolower
333#undef toupper
334extern unsigned char sane_ctype[256];
335#define GIT_SPACE 0x01
336#define GIT_DIGIT 0x02
337#define GIT_ALPHA 0x04
338#define GIT_GLOB_SPECIAL 0x08
339#define GIT_REGEX_SPECIAL 0x10
340#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
341#define isascii(x) (((x) & ~0x7f) == 0)
342#define isspace(x) sane_istest(x,GIT_SPACE)
343#define isdigit(x) sane_istest(x,GIT_DIGIT)
344#define isalpha(x) sane_istest(x,GIT_ALPHA)
345#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
346#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
347#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
348#define tolower(x) sane_case((unsigned char)(x), 0x20)
349#define toupper(x) sane_case((unsigned char)(x), 0)
350
351static inline int sane_case(int x, int high)
352{
353 if (sane_istest(x, GIT_ALPHA))
354 x = (x & ~0x20) | high;
355 return x;
356}
357
358static inline int strtoul_ui(char const *s, int base, unsigned int *result)
359{
360 unsigned long ul;
361 char *p;
362
363 errno = 0;
364 ul = strtoul(s, &p, base);
365 if (errno || *p || p == s || (unsigned int) ul != ul)
366 return -1;
367 *result = ul;
368 return 0;
369}
370
371static inline int strtol_i(char const *s, int base, int *result)
372{
373 long ul;
374 char *p;
375
376 errno = 0;
377 ul = strtol(s, &p, base);
378 if (errno || *p || p == s || (int) ul != ul)
379 return -1;
380 *result = ul;
381 return 0;
382}
383
384#ifdef INTERNAL_QSORT
385void git_qsort(void *base, size_t nmemb, size_t size,
386 int(*compar)(const void *, const void *));
387#define qsort git_qsort
388#endif
389
390#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
391# define FORCE_DIR_SET_GID S_ISGID
392#else
393# define FORCE_DIR_SET_GID 0
394#endif
395
396#ifdef NO_NSEC
397#undef USE_NSEC
398#define ST_CTIME_NSEC(st) 0
399#define ST_MTIME_NSEC(st) 0
400#else
401#ifdef USE_ST_TIMESPEC
402#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
403#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
404#else
405#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
406#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
407#endif
408#endif
409
410#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}