aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-05-24 04:13:01 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-05-24 04:13:01 -0400
commite644dae645e167d154c0526358940986682a72b0 (patch)
tree972993c6568085b8d407fc7e13de10f4b93c651d /tools/perf
parent899c612d74d4a242158a4db20367388d6299c028 (diff)
parent86809173ce32ef03bd4d0389dfc72df0c805e9c4 (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/.gitignore2
-rw-r--r--tools/perf/Documentation/Makefile86
-rw-r--r--tools/perf/Documentation/perf-lock.txt20
-rw-r--r--tools/perf/Documentation/perf-record.txt38
-rw-r--r--tools/perf/Documentation/perf-report.txt15
-rw-r--r--tools/perf/Documentation/perf-script.txt5
-rw-r--r--tools/perf/Documentation/perf-stat.txt4
-rw-r--r--tools/perf/Documentation/perf-top.txt8
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile91
-rw-r--r--tools/perf/arch/powerpc/util/header.c2
-rw-r--r--tools/perf/arch/x86/util/header.c2
-rw-r--r--tools/perf/bench/bench.h1
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm-def.h8
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm.S6
-rw-r--r--tools/perf/bench/mem-memcpy.c12
-rw-r--r--tools/perf/bench/mem-memset-arch.h12
-rw-r--r--tools/perf/bench/mem-memset-x86-64-asm-def.h12
-rw-r--r--tools/perf/bench/mem-memset-x86-64-asm.S13
-rw-r--r--tools/perf/bench/mem-memset.c297
-rw-r--r--tools/perf/builtin-bench.c3
-rw-r--r--tools/perf/builtin-diff.c60
-rw-r--r--tools/perf/builtin-lock.c4
-rw-r--r--tools/perf/builtin-probe.c12
-rw-r--r--tools/perf/builtin-record.c181
-rw-r--r--tools/perf/builtin-report.c218
-rw-r--r--tools/perf/builtin-sched.c1
-rw-r--r--tools/perf/builtin-script.c80
-rw-r--r--tools/perf/builtin-stat.c41
-rw-r--r--tools/perf/builtin-test.c362
-rw-r--r--tools/perf/builtin-top.c100
-rw-r--r--tools/perf/config/feature-tests.mak15
-rw-r--r--tools/perf/perf-archive.sh3
-rw-r--r--tools/perf/perf.h33
-rwxr-xr-xtools/perf/python/twatch.py2
-rw-r--r--tools/perf/util/annotate.c24
-rw-r--r--tools/perf/util/bitmap.c10
-rw-r--r--tools/perf/util/cache.h12
-rw-r--r--tools/perf/util/color.c9
-rw-r--r--tools/perf/util/cpumap.c11
-rw-r--r--tools/perf/util/cpumap.h4
-rw-r--r--tools/perf/util/ctype.c2
-rw-r--r--tools/perf/util/debugfs.c141
-rw-r--r--tools/perf/util/debugfs.h6
-rw-r--r--tools/perf/util/event.h1
-rw-r--r--tools/perf/util/evlist.c23
-rw-r--r--tools/perf/util/evlist.h9
-rw-r--r--tools/perf/util/evsel.c30
-rw-r--r--tools/perf/util/evsel.h5
-rw-r--r--tools/perf/util/gtk/browser.c189
-rw-r--r--tools/perf/util/gtk/gtk.h8
-rw-r--r--tools/perf/util/header.c590
-rw-r--r--tools/perf/util/header.h3
-rw-r--r--tools/perf/util/hist.c356
-rw-r--r--tools/perf/util/hist.h32
-rw-r--r--tools/perf/util/include/asm/dwarf2.h4
-rw-r--r--tools/perf/util/include/asm/unistd_32.h1
-rw-r--r--tools/perf/util/include/asm/unistd_64.h1
-rw-r--r--tools/perf/util/include/linux/bitmap.h11
-rw-r--r--tools/perf/util/include/linux/bitops.h2
-rw-r--r--tools/perf/util/include/linux/export.h (renamed from tools/perf/util/include/linux/module.h)0
-rw-r--r--tools/perf/util/map.c16
-rw-r--r--tools/perf/util/map.h2
-rw-r--r--tools/perf/util/parse-events.c605
-rw-r--r--tools/perf/util/parse-events.h49
-rw-r--r--tools/perf/util/parse-events.l127
-rw-r--r--tools/perf/util/parse-events.y229
-rw-r--r--tools/perf/util/pmu.c469
-rw-r--r--tools/perf/util/pmu.h41
-rw-r--r--tools/perf/util/pmu.l43
-rw-r--r--tools/perf/util/pmu.y93
-rw-r--r--tools/perf/util/probe-event.c33
-rw-r--r--tools/perf/util/probe-finder.c5
-rw-r--r--tools/perf/util/python-ext-sources19
-rw-r--r--tools/perf/util/python.c10
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c141
-rw-r--r--tools/perf/util/session.h6
-rw-r--r--tools/perf/util/setup.py8
-rw-r--r--tools/perf/util/sort.c290
-rw-r--r--tools/perf/util/sort.h11
-rw-r--r--tools/perf/util/strbuf.c7
-rw-r--r--tools/perf/util/symbol.c27
-rw-r--r--tools/perf/util/symbol.h24
-rw-r--r--tools/perf/util/sysfs.c60
-rw-r--r--tools/perf/util/sysfs.h6
-rw-r--r--tools/perf/util/thread_map.c237
-rw-r--r--tools/perf/util/thread_map.h11
-rw-r--r--tools/perf/util/top.c13
-rw-r--r--tools/perf/util/top.h7
-rw-r--r--tools/perf/util/trace-event-parse.c23
-rw-r--r--tools/perf/util/trace-event-read.c1
-rw-r--r--tools/perf/util/trace-event-scripting.c1
-rw-r--r--tools/perf/util/ui/browser.h2
-rw-r--r--tools/perf/util/ui/browsers/annotate.c18
-rw-r--r--tools/perf/util/ui/browsers/hists.c134
-rw-r--r--tools/perf/util/ui/browsers/map.c2
-rw-r--r--tools/perf/util/ui/helpline.c2
-rw-r--r--tools/perf/util/ui/keysyms.h2
-rw-r--r--tools/perf/util/ui/util.c82
-rw-r--r--tools/perf/util/usage.c39
-rw-r--r--tools/perf/util/util.c4
-rw-r--r--tools/perf/util/util.h6
103 files changed, 4916 insertions, 1224 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 416684be0ad3..26b823b61aa1 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -19,3 +19,5 @@ TAGS
19cscope* 19cscope*
20config.mak 20config.mak
21config.mak.autogen 21config.mak.autogen
22*-bison.*
23*-flex.*
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index 4626a398836a..ca600e09c8d4 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -1,3 +1,10 @@
1OUTPUT := ./
2ifeq ("$(origin O)", "command line")
3 ifneq ($(O),)
4 OUTPUT := $(O)/
5 endif
6endif
7
1MAN1_TXT= \ 8MAN1_TXT= \
2 $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \ 9 $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
3 $(wildcard perf-*.txt)) \ 10 $(wildcard perf-*.txt)) \
@@ -6,10 +13,11 @@ MAN5_TXT=
6MAN7_TXT= 13MAN7_TXT=
7 14
8MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT) 15MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
9MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT)) 16_MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
10MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT)) 17_MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
11 18
12DOC_HTML=$(MAN_HTML) 19MAN_XML=$(addprefix $(OUTPUT),$(_MAN_XML))
20MAN_HTML=$(addprefix $(OUTPUT),$(_MAN_HTML))
13 21
14ARTICLES = 22ARTICLES =
15# with their own formatting rules. 23# with their own formatting rules.
@@ -18,11 +26,17 @@ API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technica
18SP_ARTICLES += $(API_DOCS) 26SP_ARTICLES += $(API_DOCS)
19SP_ARTICLES += technical/api-index 27SP_ARTICLES += technical/api-index
20 28
21DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES)) 29_DOC_HTML = $(_MAN_HTML)
30_DOC_HTML+=$(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
31DOC_HTML=$(addprefix $(OUTPUT),$(_DOC_HTML))
22 32
23DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT)) 33_DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
24DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) 34_DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
25DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) 35_DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
36
37DOC_MAN1=$(addprefix $(OUTPUT),$(_DOC_MAN1))
38DOC_MAN5=$(addprefix $(OUTPUT),$(_DOC_MAN5))
39DOC_MAN7=$(addprefix $(OUTPUT),$(_DOC_MAN7))
26 40
27# Make the path relative to DESTDIR, not prefix 41# Make the path relative to DESTDIR, not prefix
28ifndef DESTDIR 42ifndef DESTDIR
@@ -150,9 +164,9 @@ man1: $(DOC_MAN1)
150man5: $(DOC_MAN5) 164man5: $(DOC_MAN5)
151man7: $(DOC_MAN7) 165man7: $(DOC_MAN7)
152 166
153info: perf.info perfman.info 167info: $(OUTPUT)perf.info $(OUTPUT)perfman.info
154 168
155pdf: user-manual.pdf 169pdf: $(OUTPUT)user-manual.pdf
156 170
157install: install-man 171install: install-man
158 172
@@ -166,7 +180,7 @@ install-man: man
166 180
167install-info: info 181install-info: info
168 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir) 182 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
169 $(INSTALL) -m 644 perf.info perfman.info $(DESTDIR)$(infodir) 183 $(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir)
170 if test -r $(DESTDIR)$(infodir)/dir; then \ 184 if test -r $(DESTDIR)$(infodir)/dir; then \
171 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\ 185 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\
172 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\ 186 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\
@@ -176,7 +190,7 @@ install-info: info
176 190
177install-pdf: pdf 191install-pdf: pdf
178 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir) 192 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
179 $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir) 193 $(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(DESTDIR)$(pdfdir)
180 194
181#install-html: html 195#install-html: html
182# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) 196# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
@@ -189,14 +203,14 @@ install-pdf: pdf
189# 203#
190# Determine "include::" file references in asciidoc files. 204# Determine "include::" file references in asciidoc files.
191# 205#
192doc.dep : $(wildcard *.txt) build-docdep.perl 206$(OUTPUT)doc.dep : $(wildcard *.txt) build-docdep.perl
193 $(QUIET_GEN)$(RM) $@+ $@ && \ 207 $(QUIET_GEN)$(RM) $@+ $@ && \
194 $(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \ 208 $(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \
195 mv $@+ $@ 209 mv $@+ $@
196 210
197-include doc.dep 211-include $(OUPTUT)doc.dep
198 212
199cmds_txt = cmds-ancillaryinterrogators.txt \ 213_cmds_txt = cmds-ancillaryinterrogators.txt \
200 cmds-ancillarymanipulators.txt \ 214 cmds-ancillarymanipulators.txt \
201 cmds-mainporcelain.txt \ 215 cmds-mainporcelain.txt \
202 cmds-plumbinginterrogators.txt \ 216 cmds-plumbinginterrogators.txt \
@@ -205,32 +219,36 @@ cmds_txt = cmds-ancillaryinterrogators.txt \
205 cmds-synchelpers.txt \ 219 cmds-synchelpers.txt \
206 cmds-purehelpers.txt \ 220 cmds-purehelpers.txt \
207 cmds-foreignscminterface.txt 221 cmds-foreignscminterface.txt
222cmds_txt=$(addprefix $(OUTPUT),$(_cmds_txt))
208 223
209$(cmds_txt): cmd-list.made 224$(cmds_txt): $(OUTPUT)cmd-list.made
210 225
211cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) 226$(OUTPUT)cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
212 $(QUIET_GEN)$(RM) $@ && \ 227 $(QUIET_GEN)$(RM) $@ && \
213 $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \ 228 $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
214 date >$@ 229 date >$@
215 230
216clean: 231clean:
217 $(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 232 $(RM) $(MAN_XML) $(addsuffix +,$(MAN_XML))
218 $(RM) *.texi *.texi+ *.texi++ perf.info perfman.info 233 $(RM) $(MAN_HTML) $(addsuffix +,$(MAN_HTML))
219 $(RM) howto-index.txt howto/*.html doc.dep 234 $(RM) $(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7)
220 $(RM) technical/api-*.html technical/api-index.txt 235 $(RM) $(OUTPUT)*.texi $(OUTPUT)*.texi+ $(OUTPUT)*.texi++
221 $(RM) $(cmds_txt) *.made 236 $(RM) $(OUTPUT)perf.info $(OUTPUT)perfman.info
222 237 $(RM) $(OUTPUT)howto-index.txt $(OUTPUT)howto/*.html $(OUTPUT)doc.dep
223$(MAN_HTML): %.html : %.txt 238 $(RM) $(OUTPUT)technical/api-*.html $(OUTPUT)technical/api-index.txt
239 $(RM) $(cmds_txt) $(OUTPUT)*.made
240
241$(MAN_HTML): $(OUTPUT)%.html : %.txt
224 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ 242 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
225 $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \ 243 $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
226 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \ 244 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
227 mv $@+ $@ 245 mv $@+ $@
228 246
229%.1 %.5 %.7 : %.xml 247$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
230 $(QUIET_XMLTO)$(RM) $@ && \ 248 $(QUIET_XMLTO)$(RM) $@ && \
231 xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< 249 xmlto -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
232 250
233%.xml : %.txt 251$(OUTPUT)%.xml : %.txt
234 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ 252 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
235 $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \ 253 $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
236 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \ 254 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
@@ -239,25 +257,25 @@ $(MAN_HTML): %.html : %.txt
239XSLT = docbook.xsl 257XSLT = docbook.xsl
240XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css 258XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
241 259
242user-manual.html: user-manual.xml 260$(OUTPUT)user-manual.html: $(OUTPUT)user-manual.xml
243 $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $< 261 $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
244 262
245perf.info: user-manual.texi 263$(OUTPUT)perf.info: $(OUTPUT)user-manual.texi
246 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi 264 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ $(OUTPUT)user-manual.texi
247 265
248user-manual.texi: user-manual.xml 266$(OUTPUT)user-manual.texi: $(OUTPUT)user-manual.xml
249 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ 267 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
250 $(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \ 268 $(DOCBOOK2X_TEXI) $(OUTPUT)user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \
251 $(PERL_PATH) fix-texi.perl <$@++ >$@+ && \ 269 $(PERL_PATH) fix-texi.perl <$@++ >$@+ && \
252 rm $@++ && \ 270 rm $@++ && \
253 mv $@+ $@ 271 mv $@+ $@
254 272
255user-manual.pdf: user-manual.xml 273$(OUTPUT)user-manual.pdf: $(OUTPUT)user-manual.xml
256 $(QUIET_DBLATEX)$(RM) $@+ $@ && \ 274 $(QUIET_DBLATEX)$(RM) $@+ $@ && \
257 $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \ 275 $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \
258 mv $@+ $@ 276 mv $@+ $@
259 277
260perfman.texi: $(MAN_XML) cat-texi.perl 278$(OUTPUT)perfman.texi: $(MAN_XML) cat-texi.perl
261 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ 279 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
262 ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \ 280 ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \
263 --to-stdout $(xml) &&) true) > $@++ && \ 281 --to-stdout $(xml) &&) true) > $@++ && \
@@ -265,7 +283,7 @@ perfman.texi: $(MAN_XML) cat-texi.perl
265 rm $@++ && \ 283 rm $@++ && \
266 mv $@+ $@ 284 mv $@+ $@
267 285
268perfman.info: perfman.texi 286$(OUTPUT)perfman.info: $(OUTPUT)perfman.texi
269 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi 287 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi
270 288
271$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml 289$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
index d6b2a4f2108b..c7f5f55634ac 100644
--- a/tools/perf/Documentation/perf-lock.txt
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -8,7 +8,7 @@ perf-lock - Analyze lock events
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf lock' {record|report|trace} 11'perf lock' {record|report|script|info}
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -20,10 +20,13 @@ and statistics with this 'perf lock' command.
20 produces the file "perf.data" which contains tracing 20 produces the file "perf.data" which contains tracing
21 results of lock events. 21 results of lock events.
22 22
23 'perf lock trace' shows raw lock events.
24
25 'perf lock report' reports statistical data. 23 'perf lock report' reports statistical data.
26 24
25 'perf lock script' shows raw lock events.
26
27 'perf lock info' shows metadata like threads or addresses
28 of lock instances.
29
27COMMON OPTIONS 30COMMON OPTIONS
28-------------- 31--------------
29 32
@@ -47,6 +50,17 @@ REPORT OPTIONS
47 Sorting key. Possible values: acquired (default), contended, 50 Sorting key. Possible values: acquired (default), contended,
48 wait_total, wait_max, wait_min. 51 wait_total, wait_max, wait_min.
49 52
53INFO OPTIONS
54------------
55
56-t::
57--threads::
58 dump thread list in perf.data
59
60-m::
61--map::
62 dump map of lock instances (address:name table)
63
50SEE ALSO 64SEE ALSO
51-------- 65--------
52linkperf:perf[1] 66linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 2937f7e14bb7..a1386b2fff00 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -52,11 +52,15 @@ OPTIONS
52 52
53-p:: 53-p::
54--pid=:: 54--pid=::
55 Record events on existing process ID. 55 Record events on existing process ID (comma separated list).
56 56
57-t:: 57-t::
58--tid=:: 58--tid=::
59 Record events on existing thread ID. 59 Record events on existing thread ID (comma separated list).
60
61-u::
62--uid=::
63 Record events in threads owned by uid. Name or number.
60 64
61-r:: 65-r::
62--realtime=:: 66--realtime=::
@@ -148,6 +152,36 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha
148corresponding events, i.e., they always refer to events defined earlier on the command 152corresponding events, i.e., they always refer to events defined earlier on the command
149line. 153line.
150 154
155-b::
156--branch-any::
157Enable taken branch stack sampling. Any type of taken branch may be sampled.
158This is a shortcut for --branch-filter any. See --branch-filter for more infos.
159
160-j::
161--branch-filter::
162Enable taken branch stack sampling. Each sample captures a series of consecutive
163taken branches. The number of branches captured with each sample depends on the
164underlying hardware, the type of branches of interest, and the executed code.
165It is possible to select the types of branches captured by enabling filters. The
166following filters are defined:
167
168 - any: any type of branches
169 - any_call: any function call or system call
170 - any_ret: any function return or system call return
171 - any_ind: any indirect branch
172 - u: only when the branch target is at the user level
173 - k: only when the branch target is in the kernel
174 - hv: only when the target is at the hypervisor level
175
176+
177The option requires at least one branch type among any, any_call, any_ret, ind_call.
178The privilege levels may be ommitted, in which case, the privilege levels of the associated
179event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege
180levels are subject to permissions. When sampling on multiple events, branch stack sampling
181is enabled for all the sampling events. The sampled branch type is the same for all events.
182The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
183Note that this feature may not be available on all processors.
184
151SEE ALSO 185SEE ALSO
152-------- 186--------
153linkperf:perf-stat[1], linkperf:perf-list[1] 187linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 9b430e98712e..2d89f02719b5 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -48,6 +48,9 @@ OPTIONS
48 Only consider these symbols. CSV that understands 48 Only consider these symbols. CSV that understands
49 file://filename entries. 49 file://filename entries.
50 50
51--symbol-filter=::
52 Only show symbols that match (partially) with this filter.
53
51-U:: 54-U::
52--hide-unresolved:: 55--hide-unresolved::
53 Only display entries resolved to a symbol. 56 Only display entries resolved to a symbol.
@@ -110,6 +113,8 @@ OPTIONS
110 requires a tty, if one is not present, as when piping to other 113 requires a tty, if one is not present, as when piping to other
111 commands, the stdio interface is used. 114 commands, the stdio interface is used.
112 115
116--gtk:: Use the GTK2 interface.
117
113-k:: 118-k::
114--vmlinux=<file>:: 119--vmlinux=<file>::
115 vmlinux pathname 120 vmlinux pathname
@@ -153,6 +158,16 @@ OPTIONS
153 information which may be very large and thus may clutter the display. 158 information which may be very large and thus may clutter the display.
154 It currently includes: cpu and numa topology of the host system. 159 It currently includes: cpu and numa topology of the host system.
155 160
161-b::
162--branch-stack::
163 Use the addresses of sampled taken branches instead of the instruction
164 address to build the histograms. To generate meaningful output, the
165 perf.data file must have been obtained using perf record -b or
166 perf record --branch-filter xxx where xxx is a branch filter option.
167 perf report is able to auto-detect whether a perf.data file contains
168 branch stacks and it will automatically switch to the branch view mode,
169 unless --no-branch-stack is used.
170
156SEE ALSO 171SEE ALSO
157-------- 172--------
158linkperf:perf-stat[1], linkperf:perf-annotate[1] 173linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 2f6cef43da25..e9cbfcddfa3f 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -115,7 +115,7 @@ OPTIONS
115-f:: 115-f::
116--fields:: 116--fields::
117 Comma separated list of fields to print. Options are: 117 Comma separated list of fields to print. Options are:
118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr. 118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff.
119 Field list can be prepended with the type, trace, sw or hw, 119 Field list can be prepended with the type, trace, sw or hw,
120 to indicate to which event type the field list applies. 120 to indicate to which event type the field list applies.
121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace 121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
@@ -200,6 +200,9 @@ OPTIONS
200 It currently includes: cpu and numa topology of the host system. 200 It currently includes: cpu and numa topology of the host system.
201 It can only be used with the perf script report mode. 201 It can only be used with the perf script report mode.
202 202
203--show-kernel-path::
204 Try to resolve the path of [kernel.kallsyms]
205
203SEE ALSO 206SEE ALSO
204-------- 207--------
205linkperf:perf-record[1], linkperf:perf-script-perl[1], 208linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 8966b9ab2014..2fa173b51970 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -35,11 +35,11 @@ OPTIONS
35 child tasks do not inherit counters 35 child tasks do not inherit counters
36-p:: 36-p::
37--pid=<pid>:: 37--pid=<pid>::
38 stat events on existing process id 38 stat events on existing process id (comma separated list)
39 39
40-t:: 40-t::
41--tid=<tid>:: 41--tid=<tid>::
42 stat events on existing thread id 42 stat events on existing thread id (comma separated list)
43 43
44 44
45-a:: 45-a::
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index b1a5bbbfebef..4a5680cb242e 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -72,11 +72,15 @@ Default is to monitor all CPUS.
72 72
73-p <pid>:: 73-p <pid>::
74--pid=<pid>:: 74--pid=<pid>::
75 Profile events on existing Process ID. 75 Profile events on existing Process ID (comma separated list).
76 76
77-t <tid>:: 77-t <tid>::
78--tid=<tid>:: 78--tid=<tid>::
79 Profile events on existing thread ID. 79 Profile events on existing thread ID (comma separated list).
80
81-u::
82--uid=::
83 Record events in threads owned by uid. Name or number.
80 84
81-r <priority>:: 85-r <priority>::
82--realtime=<priority>:: 86--realtime=<priority>::
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 1078c5fadd5b..5476bc0a1eac 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -9,6 +9,7 @@ lib/rbtree.c
9include/linux/swab.h 9include/linux/swab.h
10arch/*/include/asm/unistd*.h 10arch/*/include/asm/unistd*.h
11arch/*/lib/memcpy*.S 11arch/*/lib/memcpy*.S
12arch/*/lib/memset*.S
12include/linux/poison.h 13include/linux/poison.h
13include/linux/magic.h 14include/linux/magic.h
14include/linux/hw_breakpoint.h 15include/linux/hw_breakpoint.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7c12650165ae..03059e75665a 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -15,6 +15,16 @@ endif
15 15
16# Define V to have a more verbose compile. 16# Define V to have a more verbose compile.
17# 17#
18# Define O to save output files in a separate directory.
19#
20# Define ARCH as name of target architecture if you want cross-builds.
21#
22# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
23#
24# Define NO_LIBPERL to disable perl script extension.
25#
26# Define NO_LIBPYTHON to disable python script extension.
27#
18# Define PYTHON to point to the python binary if the default 28# Define PYTHON to point to the python binary if the default
19# `python' is not correct; for example: PYTHON=python2 29# `python' is not correct; for example: PYTHON=python2
20# 30#
@@ -32,6 +42,10 @@ endif
32# Define NO_DWARF if you do not want debug-info analysis feature at all. 42# Define NO_DWARF if you do not want debug-info analysis feature at all.
33# 43#
34# Define WERROR=0 to disable treating any warnings as errors. 44# Define WERROR=0 to disable treating any warnings as errors.
45#
46# Define NO_NEWT if you do not want TUI support.
47#
48# Define NO_DEMANGLE if you do not want C++ symbol demangling.
35 49
36$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 50$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
37 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 51 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
@@ -61,7 +75,7 @@ ifeq ($(ARCH),x86_64)
61 ifeq (${IS_X86_64}, 1) 75 ifeq (${IS_X86_64}, 1)
62 RAW_ARCH := x86_64 76 RAW_ARCH := x86_64
63 ARCH_CFLAGS := -DARCH_X86_64 77 ARCH_CFLAGS := -DARCH_X86_64
64 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S 78 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
65 endif 79 endif
66endif 80endif
67 81
@@ -168,7 +182,7 @@ endif
168 182
169### --- END CONFIGURATION SECTION --- 183### --- END CONFIGURATION SECTION ---
170 184
171BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 185BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
172BASIC_LDFLAGS = 186BASIC_LDFLAGS =
173 187
174# Guard against environment variables 188# Guard against environment variables
@@ -183,7 +197,10 @@ SCRIPT_SH += perf-archive.sh
183grep-libs = $(filter -l%,$(1)) 197grep-libs = $(filter -l%,$(1))
184strip-libs = $(filter-out -l%,$(1)) 198strip-libs = $(filter-out -l%,$(1))
185 199
186$(OUTPUT)python/perf.so: $(PYRF_OBJS) 200PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
201PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py
202
203$(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
187 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ 204 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
188 --quiet build_ext; \ 205 --quiet build_ext; \
189 mkdir -p $(OUTPUT)python && \ 206 mkdir -p $(OUTPUT)python && \
@@ -217,6 +234,24 @@ endif
217 234
218export PERL_PATH 235export PERL_PATH
219 236
237FLEX = $(CROSS_COMPILE)flex
238BISON= $(CROSS_COMPILE)bison
239
240$(OUTPUT)util/parse-events-flex.c: util/parse-events.l
241 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
242
243$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
244 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c
245
246$(OUTPUT)util/pmu-flex.c: util/pmu.l
247 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
248
249$(OUTPUT)util/pmu-bison.c: util/pmu.y
250 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c
251
252$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
253$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
254
220LIB_FILE=$(OUTPUT)libperf.a 255LIB_FILE=$(OUTPUT)libperf.a
221 256
222LIB_H += ../../include/linux/perf_event.h 257LIB_H += ../../include/linux/perf_event.h
@@ -232,7 +267,7 @@ LIB_H += util/include/linux/const.h
232LIB_H += util/include/linux/ctype.h 267LIB_H += util/include/linux/ctype.h
233LIB_H += util/include/linux/kernel.h 268LIB_H += util/include/linux/kernel.h
234LIB_H += util/include/linux/list.h 269LIB_H += util/include/linux/list.h
235LIB_H += util/include/linux/module.h 270LIB_H += util/include/linux/export.h
236LIB_H += util/include/linux/poison.h 271LIB_H += util/include/linux/poison.h
237LIB_H += util/include/linux/prefetch.h 272LIB_H += util/include/linux/prefetch.h
238LIB_H += util/include/linux/rbtree.h 273LIB_H += util/include/linux/rbtree.h
@@ -249,6 +284,8 @@ LIB_H += util/include/asm/uaccess.h
249LIB_H += util/include/dwarf-regs.h 284LIB_H += util/include/dwarf-regs.h
250LIB_H += util/include/asm/dwarf2.h 285LIB_H += util/include/asm/dwarf2.h
251LIB_H += util/include/asm/cpufeature.h 286LIB_H += util/include/asm/cpufeature.h
287LIB_H += util/include/asm/unistd_32.h
288LIB_H += util/include/asm/unistd_64.h
252LIB_H += perf.h 289LIB_H += perf.h
253LIB_H += util/annotate.h 290LIB_H += util/annotate.h
254LIB_H += util/cache.h 291LIB_H += util/cache.h
@@ -256,6 +293,8 @@ LIB_H += util/callchain.h
256LIB_H += util/build-id.h 293LIB_H += util/build-id.h
257LIB_H += util/debug.h 294LIB_H += util/debug.h
258LIB_H += util/debugfs.h 295LIB_H += util/debugfs.h
296LIB_H += util/sysfs.h
297LIB_H += util/pmu.h
259LIB_H += util/event.h 298LIB_H += util/event.h
260LIB_H += util/evsel.h 299LIB_H += util/evsel.h
261LIB_H += util/evlist.h 300LIB_H += util/evlist.h
@@ -302,6 +341,8 @@ LIB_OBJS += $(OUTPUT)util/build-id.o
302LIB_OBJS += $(OUTPUT)util/config.o 341LIB_OBJS += $(OUTPUT)util/config.o
303LIB_OBJS += $(OUTPUT)util/ctype.o 342LIB_OBJS += $(OUTPUT)util/ctype.o
304LIB_OBJS += $(OUTPUT)util/debugfs.o 343LIB_OBJS += $(OUTPUT)util/debugfs.o
344LIB_OBJS += $(OUTPUT)util/sysfs.o
345LIB_OBJS += $(OUTPUT)util/pmu.o
305LIB_OBJS += $(OUTPUT)util/environment.o 346LIB_OBJS += $(OUTPUT)util/environment.o
306LIB_OBJS += $(OUTPUT)util/event.o 347LIB_OBJS += $(OUTPUT)util/event.o
307LIB_OBJS += $(OUTPUT)util/evlist.o 348LIB_OBJS += $(OUTPUT)util/evlist.o
@@ -338,6 +379,10 @@ LIB_OBJS += $(OUTPUT)util/session.o
338LIB_OBJS += $(OUTPUT)util/thread.o 379LIB_OBJS += $(OUTPUT)util/thread.o
339LIB_OBJS += $(OUTPUT)util/thread_map.o 380LIB_OBJS += $(OUTPUT)util/thread_map.o
340LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 381LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
382LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
383LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
384LIB_OBJS += $(OUTPUT)util/pmu-flex.o
385LIB_OBJS += $(OUTPUT)util/pmu-bison.o
341LIB_OBJS += $(OUTPUT)util/trace-event-read.o 386LIB_OBJS += $(OUTPUT)util/trace-event-read.o
342LIB_OBJS += $(OUTPUT)util/trace-event-info.o 387LIB_OBJS += $(OUTPUT)util/trace-event-info.o
343LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o 388LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -359,8 +404,10 @@ BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
359BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o 404BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
360ifeq ($(RAW_ARCH),x86_64) 405ifeq ($(RAW_ARCH),x86_64)
361BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o 406BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
407BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
362endif 408endif
363BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o 409BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
410BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
364 411
365BUILTIN_OBJS += $(OUTPUT)builtin-diff.o 412BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
366BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o 413BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
@@ -478,6 +525,20 @@ else
478 endif 525 endif
479endif 526endif
480 527
528ifdef NO_GTK2
529 BASIC_CFLAGS += -DNO_GTK2_SUPPORT
530else
531 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0)
532 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y)
533 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
534 BASIC_CFLAGS += -DNO_GTK2_SUPPORT
535 else
536 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
537 EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
538 LIB_OBJS += $(OUTPUT)util/gtk/browser.o
539 endif
540endif
541
481ifdef NO_LIBPERL 542ifdef NO_LIBPERL
482 BASIC_CFLAGS += -DNO_LIBPERL 543 BASIC_CFLAGS += -DNO_LIBPERL
483else 544else
@@ -624,6 +685,8 @@ ifndef V
624 QUIET_LINK = @echo ' ' LINK $@; 685 QUIET_LINK = @echo ' ' LINK $@;
625 QUIET_MKDIR = @echo ' ' MKDIR $@; 686 QUIET_MKDIR = @echo ' ' MKDIR $@;
626 QUIET_GEN = @echo ' ' GEN $@; 687 QUIET_GEN = @echo ' ' GEN $@;
688 QUIET_FLEX = @echo ' ' FLEX $@;
689 QUIET_BISON = @echo ' ' BISON $@;
627endif 690endif
628endif 691endif
629 692
@@ -704,12 +767,28 @@ $(OUTPUT)perf.o perf.spec \
704 $(SCRIPTS) \ 767 $(SCRIPTS) \
705 : $(OUTPUT)PERF-VERSION-FILE 768 : $(OUTPUT)PERF-VERSION-FILE
706 769
770.SUFFIXES:
771.SUFFIXES: .o .c .S .s
772
773# These two need to be here so that when O= is not used they take precedence
774# over the general rule for .o
775
776$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
777 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
778
779$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
780 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
781
707$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 782$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
708 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 783 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
784$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
785 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
709$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS 786$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
710 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< 787 $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $<
711$(OUTPUT)%.o: %.S 788$(OUTPUT)%.o: %.S
712 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 789 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
790$(OUTPUT)%.s: %.S
791 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
713 792
714$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS 793$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
715 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 794 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
@@ -792,7 +871,6 @@ help:
792 @echo ' quick-install-html - install the html documentation quickly' 871 @echo ' quick-install-html - install the html documentation quickly'
793 @echo '' 872 @echo ''
794 @echo 'Perf maintainer targets:' 873 @echo 'Perf maintainer targets:'
795 @echo ' distclean - alias to clean'
796 @echo ' clean - clean all binary objects and build output' 874 @echo ' clean - clean all binary objects and build output'
797 875
798doc: 876doc:
@@ -909,6 +987,7 @@ clean:
909 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 987 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
910 $(MAKE) -C Documentation/ clean 988 $(MAKE) -C Documentation/ clean
911 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS 989 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
990 $(RM) $(OUTPUT)util/*-{bison,flex}*
912 $(python-clean) 991 $(python-clean)
913 992
914.PHONY: all install clean strip 993.PHONY: all install clean strip
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index eba80c292945..2f7073d107fd 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -25,7 +25,7 @@ get_cpuid(char *buffer, size_t sz)
25 25
26 pvr = mfspr(SPRN_PVR); 26 pvr = mfspr(SPRN_PVR);
27 27
28 nb = snprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr)); 28 nb = scnprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr));
29 29
30 /* look for end marker to ensure the entire data fit */ 30 /* look for end marker to ensure the entire data fit */
31 if (strchr(buffer, '$')) { 31 if (strchr(buffer, '$')) {
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
index f94006068d2b..146d12a1cec0 100644
--- a/tools/perf/arch/x86/util/header.c
+++ b/tools/perf/arch/x86/util/header.c
@@ -48,7 +48,7 @@ get_cpuid(char *buffer, size_t sz)
48 if (family >= 0x6) 48 if (family >= 0x6)
49 model += ((a >> 16) & 0xf) << 4; 49 model += ((a >> 16) & 0xf) << 4;
50 } 50 }
51 nb = snprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step); 51 nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
52 52
53 /* look for end marker to ensure the entire data fit */ 53 /* look for end marker to ensure the entire data fit */
54 if (strchr(buffer, '$')) { 54 if (strchr(buffer, '$')) {
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index f7781c6267c0..a09bece6dad2 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -4,6 +4,7 @@
4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); 4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); 5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
6extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used); 6extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
7extern int bench_mem_memset(int argc, const char **argv, const char *prefix);
7 8
8#define BENCH_FORMAT_DEFAULT_STR "default" 9#define BENCH_FORMAT_DEFAULT_STR "default"
9#define BENCH_FORMAT_DEFAULT 0 10#define BENCH_FORMAT_DEFAULT 0
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
index d588b87696fc..d66ab799b35f 100644
--- a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
@@ -2,3 +2,11 @@
2MEMCPY_FN(__memcpy, 2MEMCPY_FN(__memcpy,
3 "x86-64-unrolled", 3 "x86-64-unrolled",
4 "unrolled memcpy() in arch/x86/lib/memcpy_64.S") 4 "unrolled memcpy() in arch/x86/lib/memcpy_64.S")
5
6MEMCPY_FN(memcpy_c,
7 "x86-64-movsq",
8 "movsq-based memcpy() in arch/x86/lib/memcpy_64.S")
9
10MEMCPY_FN(memcpy_c_e,
11 "x86-64-movsb",
12 "movsb-based memcpy() in arch/x86/lib/memcpy_64.S")
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm.S b/tools/perf/bench/mem-memcpy-x86-64-asm.S
index 185a96d66dd1..fcd9cf00600a 100644
--- a/tools/perf/bench/mem-memcpy-x86-64-asm.S
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S
@@ -1,4 +1,8 @@
1 1#define memcpy MEMCPY /* don't hide glibc's memcpy() */
2#define altinstr_replacement text
3#define globl p2align 4; .globl
4#define Lmemcpy_c globl memcpy_c; memcpy_c
5#define Lmemcpy_c_e globl memcpy_c_e; memcpy_c_e
2#include "../../../arch/x86/lib/memcpy_64.S" 6#include "../../../arch/x86/lib/memcpy_64.S"
3/* 7/*
4 * We need to provide note.GNU-stack section, saying that we want 8 * We need to provide note.GNU-stack section, saying that we want
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index db82021f4b91..71557225bf92 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -5,7 +5,6 @@
5 * 5 *
6 * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 6 * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
7 */ 7 */
8#include <ctype.h>
9 8
10#include "../perf.h" 9#include "../perf.h"
11#include "../util/util.h" 10#include "../util/util.h"
@@ -24,6 +23,7 @@
24 23
25static const char *length_str = "1MB"; 24static const char *length_str = "1MB";
26static const char *routine = "default"; 25static const char *routine = "default";
26static int iterations = 1;
27static bool use_clock; 27static bool use_clock;
28static int clock_fd; 28static int clock_fd;
29static bool only_prefault; 29static bool only_prefault;
@@ -35,6 +35,8 @@ static const struct option options[] = {
35 "available unit: B, MB, GB (upper and lower)"), 35 "available unit: B, MB, GB (upper and lower)"),
36 OPT_STRING('r', "routine", &routine, "default", 36 OPT_STRING('r', "routine", &routine, "default",
37 "Specify routine to copy"), 37 "Specify routine to copy"),
38 OPT_INTEGER('i', "iterations", &iterations,
39 "repeat memcpy() invocation this number of times"),
38 OPT_BOOLEAN('c', "clock", &use_clock, 40 OPT_BOOLEAN('c', "clock", &use_clock,
39 "Use CPU clock for measuring"), 41 "Use CPU clock for measuring"),
40 OPT_BOOLEAN('o', "only-prefault", &only_prefault, 42 OPT_BOOLEAN('o', "only-prefault", &only_prefault,
@@ -121,6 +123,7 @@ static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
121{ 123{
122 u64 clock_start = 0ULL, clock_end = 0ULL; 124 u64 clock_start = 0ULL, clock_end = 0ULL;
123 void *src = NULL, *dst = NULL; 125 void *src = NULL, *dst = NULL;
126 int i;
124 127
125 alloc_mem(&src, &dst, len); 128 alloc_mem(&src, &dst, len);
126 129
@@ -128,7 +131,8 @@ static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
128 fn(dst, src, len); 131 fn(dst, src, len);
129 132
130 clock_start = get_clock(); 133 clock_start = get_clock();
131 fn(dst, src, len); 134 for (i = 0; i < iterations; ++i)
135 fn(dst, src, len);
132 clock_end = get_clock(); 136 clock_end = get_clock();
133 137
134 free(src); 138 free(src);
@@ -140,6 +144,7 @@ static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
140{ 144{
141 struct timeval tv_start, tv_end, tv_diff; 145 struct timeval tv_start, tv_end, tv_diff;
142 void *src = NULL, *dst = NULL; 146 void *src = NULL, *dst = NULL;
147 int i;
143 148
144 alloc_mem(&src, &dst, len); 149 alloc_mem(&src, &dst, len);
145 150
@@ -147,7 +152,8 @@ static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
147 fn(dst, src, len); 152 fn(dst, src, len);
148 153
149 BUG_ON(gettimeofday(&tv_start, NULL)); 154 BUG_ON(gettimeofday(&tv_start, NULL));
150 fn(dst, src, len); 155 for (i = 0; i < iterations; ++i)
156 fn(dst, src, len);
151 BUG_ON(gettimeofday(&tv_end, NULL)); 157 BUG_ON(gettimeofday(&tv_end, NULL));
152 158
153 timersub(&tv_end, &tv_start, &tv_diff); 159 timersub(&tv_end, &tv_start, &tv_diff);
diff --git a/tools/perf/bench/mem-memset-arch.h b/tools/perf/bench/mem-memset-arch.h
new file mode 100644
index 000000000000..a040fa77665b
--- /dev/null
+++ b/tools/perf/bench/mem-memset-arch.h
@@ -0,0 +1,12 @@
1
2#ifdef ARCH_X86_64
3
4#define MEMSET_FN(fn, name, desc) \
5 extern void *fn(void *, int, size_t);
6
7#include "mem-memset-x86-64-asm-def.h"
8
9#undef MEMSET_FN
10
11#endif
12
diff --git a/tools/perf/bench/mem-memset-x86-64-asm-def.h b/tools/perf/bench/mem-memset-x86-64-asm-def.h
new file mode 100644
index 000000000000..a71dff97c1f5
--- /dev/null
+++ b/tools/perf/bench/mem-memset-x86-64-asm-def.h
@@ -0,0 +1,12 @@
1
2MEMSET_FN(__memset,
3 "x86-64-unrolled",
4 "unrolled memset() in arch/x86/lib/memset_64.S")
5
6MEMSET_FN(memset_c,
7 "x86-64-stosq",
8 "movsq-based memset() in arch/x86/lib/memset_64.S")
9
10MEMSET_FN(memset_c_e,
11 "x86-64-stosb",
12 "movsb-based memset() in arch/x86/lib/memset_64.S")
diff --git a/tools/perf/bench/mem-memset-x86-64-asm.S b/tools/perf/bench/mem-memset-x86-64-asm.S
new file mode 100644
index 000000000000..9e5af89ed13a
--- /dev/null
+++ b/tools/perf/bench/mem-memset-x86-64-asm.S
@@ -0,0 +1,13 @@
1#define memset MEMSET /* don't hide glibc's memset() */
2#define altinstr_replacement text
3#define globl p2align 4; .globl
4#define Lmemset_c globl memset_c; memset_c
5#define Lmemset_c_e globl memset_c_e; memset_c_e
6#include "../../../arch/x86/lib/memset_64.S"
7
8/*
9 * We need to provide note.GNU-stack section, saying that we want
10 * NOT executable stack. Otherwise the final linking will assume that
11 * the ELF stack should not be restricted at all and set it RWX.
12 */
13.section .note.GNU-stack,"",@progbits
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c
new file mode 100644
index 000000000000..e9079185bd72
--- /dev/null
+++ b/tools/perf/bench/mem-memset.c
@@ -0,0 +1,297 @@
1/*
2 * mem-memset.c
3 *
4 * memset: Simple memory set in various ways
5 *
6 * Trivial clone of mem-memcpy.c.
7 */
8
9#include "../perf.h"
10#include "../util/util.h"
11#include "../util/parse-options.h"
12#include "../util/header.h"
13#include "bench.h"
14#include "mem-memset-arch.h"
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/time.h>
20#include <errno.h>
21
22#define K 1024
23
24static const char *length_str = "1MB";
25static const char *routine = "default";
26static int iterations = 1;
27static bool use_clock;
28static int clock_fd;
29static bool only_prefault;
30static bool no_prefault;
31
32static const struct option options[] = {
33 OPT_STRING('l', "length", &length_str, "1MB",
34 "Specify length of memory to copy. "
35 "available unit: B, MB, GB (upper and lower)"),
36 OPT_STRING('r', "routine", &routine, "default",
37 "Specify routine to copy"),
38 OPT_INTEGER('i', "iterations", &iterations,
39 "repeat memset() invocation this number of times"),
40 OPT_BOOLEAN('c', "clock", &use_clock,
41 "Use CPU clock for measuring"),
42 OPT_BOOLEAN('o', "only-prefault", &only_prefault,
43 "Show only the result with page faults before memset()"),
44 OPT_BOOLEAN('n', "no-prefault", &no_prefault,
45 "Show only the result without page faults before memset()"),
46 OPT_END()
47};
48
49typedef void *(*memset_t)(void *, int, size_t);
50
51struct routine {
52 const char *name;
53 const char *desc;
54 memset_t fn;
55};
56
57static const struct routine routines[] = {
58 { "default",
59 "Default memset() provided by glibc",
60 memset },
61#ifdef ARCH_X86_64
62
63#define MEMSET_FN(fn, name, desc) { name, desc, fn },
64#include "mem-memset-x86-64-asm-def.h"
65#undef MEMSET_FN
66
67#endif
68
69 { NULL,
70 NULL,
71 NULL }
72};
73
74static const char * const bench_mem_memset_usage[] = {
75 "perf bench mem memset <options>",
76 NULL
77};
78
79static struct perf_event_attr clock_attr = {
80 .type = PERF_TYPE_HARDWARE,
81 .config = PERF_COUNT_HW_CPU_CYCLES
82};
83
84static void init_clock(void)
85{
86 clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
87
88 if (clock_fd < 0 && errno == ENOSYS)
89 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
90 else
91 BUG_ON(clock_fd < 0);
92}
93
94static u64 get_clock(void)
95{
96 int ret;
97 u64 clk;
98
99 ret = read(clock_fd, &clk, sizeof(u64));
100 BUG_ON(ret != sizeof(u64));
101
102 return clk;
103}
104
105static double timeval2double(struct timeval *ts)
106{
107 return (double)ts->tv_sec +
108 (double)ts->tv_usec / (double)1000000;
109}
110
111static void alloc_mem(void **dst, size_t length)
112{
113 *dst = zalloc(length);
114 if (!dst)
115 die("memory allocation failed - maybe length is too large?\n");
116}
117
118static u64 do_memset_clock(memset_t fn, size_t len, bool prefault)
119{
120 u64 clock_start = 0ULL, clock_end = 0ULL;
121 void *dst = NULL;
122 int i;
123
124 alloc_mem(&dst, len);
125
126 if (prefault)
127 fn(dst, -1, len);
128
129 clock_start = get_clock();
130 for (i = 0; i < iterations; ++i)
131 fn(dst, i, len);
132 clock_end = get_clock();
133
134 free(dst);
135 return clock_end - clock_start;
136}
137
138static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault)
139{
140 struct timeval tv_start, tv_end, tv_diff;
141 void *dst = NULL;
142 int i;
143
144 alloc_mem(&dst, len);
145
146 if (prefault)
147 fn(dst, -1, len);
148
149 BUG_ON(gettimeofday(&tv_start, NULL));
150 for (i = 0; i < iterations; ++i)
151 fn(dst, i, len);
152 BUG_ON(gettimeofday(&tv_end, NULL));
153
154 timersub(&tv_end, &tv_start, &tv_diff);
155
156 free(dst);
157 return (double)((double)len / timeval2double(&tv_diff));
158}
159
160#define pf (no_prefault ? 0 : 1)
161
162#define print_bps(x) do { \
163 if (x < K) \
164 printf(" %14lf B/Sec", x); \
165 else if (x < K * K) \
166 printf(" %14lfd KB/Sec", x / K); \
167 else if (x < K * K * K) \
168 printf(" %14lf MB/Sec", x / K / K); \
169 else \
170 printf(" %14lf GB/Sec", x / K / K / K); \
171 } while (0)
172
173int bench_mem_memset(int argc, const char **argv,
174 const char *prefix __used)
175{
176 int i;
177 size_t len;
178 double result_bps[2];
179 u64 result_clock[2];
180
181 argc = parse_options(argc, argv, options,
182 bench_mem_memset_usage, 0);
183
184 if (use_clock)
185 init_clock();
186
187 len = (size_t)perf_atoll((char *)length_str);
188
189 result_clock[0] = result_clock[1] = 0ULL;
190 result_bps[0] = result_bps[1] = 0.0;
191
192 if ((s64)len <= 0) {
193 fprintf(stderr, "Invalid length:%s\n", length_str);
194 return 1;
195 }
196
197 /* same to without specifying either of prefault and no-prefault */
198 if (only_prefault && no_prefault)
199 only_prefault = no_prefault = false;
200
201 for (i = 0; routines[i].name; i++) {
202 if (!strcmp(routines[i].name, routine))
203 break;
204 }
205 if (!routines[i].name) {
206 printf("Unknown routine:%s\n", routine);
207 printf("Available routines...\n");
208 for (i = 0; routines[i].name; i++) {
209 printf("\t%s ... %s\n",
210 routines[i].name, routines[i].desc);
211 }
212 return 1;
213 }
214
215 if (bench_format == BENCH_FORMAT_DEFAULT)
216 printf("# Copying %s Bytes ...\n\n", length_str);
217
218 if (!only_prefault && !no_prefault) {
219 /* show both of results */
220 if (use_clock) {
221 result_clock[0] =
222 do_memset_clock(routines[i].fn, len, false);
223 result_clock[1] =
224 do_memset_clock(routines[i].fn, len, true);
225 } else {
226 result_bps[0] =
227 do_memset_gettimeofday(routines[i].fn,
228 len, false);
229 result_bps[1] =
230 do_memset_gettimeofday(routines[i].fn,
231 len, true);
232 }
233 } else {
234 if (use_clock) {
235 result_clock[pf] =
236 do_memset_clock(routines[i].fn,
237 len, only_prefault);
238 } else {
239 result_bps[pf] =
240 do_memset_gettimeofday(routines[i].fn,
241 len, only_prefault);
242 }
243 }
244
245 switch (bench_format) {
246 case BENCH_FORMAT_DEFAULT:
247 if (!only_prefault && !no_prefault) {
248 if (use_clock) {
249 printf(" %14lf Clock/Byte\n",
250 (double)result_clock[0]
251 / (double)len);
252 printf(" %14lf Clock/Byte (with prefault)\n ",
253 (double)result_clock[1]
254 / (double)len);
255 } else {
256 print_bps(result_bps[0]);
257 printf("\n");
258 print_bps(result_bps[1]);
259 printf(" (with prefault)\n");
260 }
261 } else {
262 if (use_clock) {
263 printf(" %14lf Clock/Byte",
264 (double)result_clock[pf]
265 / (double)len);
266 } else
267 print_bps(result_bps[pf]);
268
269 printf("%s\n", only_prefault ? " (with prefault)" : "");
270 }
271 break;
272 case BENCH_FORMAT_SIMPLE:
273 if (!only_prefault && !no_prefault) {
274 if (use_clock) {
275 printf("%lf %lf\n",
276 (double)result_clock[0] / (double)len,
277 (double)result_clock[1] / (double)len);
278 } else {
279 printf("%lf %lf\n",
280 result_bps[0], result_bps[1]);
281 }
282 } else {
283 if (use_clock) {
284 printf("%lf\n", (double)result_clock[pf]
285 / (double)len);
286 } else
287 printf("%lf\n", result_bps[pf]);
288 }
289 break;
290 default:
291 /* reaching this means there's some disaster: */
292 die("unknown format: %d\n", bench_format);
293 break;
294 }
295
296 return 0;
297}
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index fcb96269852a..b0e74ab2d7a2 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -52,6 +52,9 @@ static struct bench_suite mem_suites[] = {
52 { "memcpy", 52 { "memcpy",
53 "Simple memory copy in various ways", 53 "Simple memory copy in various ways",
54 bench_mem_memcpy }, 54 bench_mem_memcpy },
55 { "memset",
56 "Simple memory set in various ways",
57 bench_mem_memset },
55 suite_all, 58 suite_all,
56 { NULL, 59 { NULL,
57 NULL, 60 NULL,
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 4f19513d7dda..d29d350fb2b7 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -24,6 +24,11 @@ static char diff__default_sort_order[] = "dso,symbol";
24static bool force; 24static bool force;
25static bool show_displacement; 25static bool show_displacement;
26 26
27struct perf_diff {
28 struct perf_tool tool;
29 struct perf_session *session;
30};
31
27static int hists__add_entry(struct hists *self, 32static int hists__add_entry(struct hists *self,
28 struct addr_location *al, u64 period) 33 struct addr_location *al, u64 period)
29{ 34{
@@ -32,12 +37,14 @@ static int hists__add_entry(struct hists *self,
32 return -ENOMEM; 37 return -ENOMEM;
33} 38}
34 39
35static int diff__process_sample_event(struct perf_tool *tool __used, 40static int diff__process_sample_event(struct perf_tool *tool,
36 union perf_event *event, 41 union perf_event *event,
37 struct perf_sample *sample, 42 struct perf_sample *sample,
38 struct perf_evsel *evsel __used, 43 struct perf_evsel *evsel __used,
39 struct machine *machine) 44 struct machine *machine)
40{ 45{
46 struct perf_diff *_diff = container_of(tool, struct perf_diff, tool);
47 struct perf_session *session = _diff->session;
41 struct addr_location al; 48 struct addr_location al;
42 49
43 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { 50 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
@@ -49,24 +56,26 @@ static int diff__process_sample_event(struct perf_tool *tool __used,
49 if (al.filtered || al.sym == NULL) 56 if (al.filtered || al.sym == NULL)
50 return 0; 57 return 0;
51 58
52 if (hists__add_entry(&evsel->hists, &al, sample->period)) { 59 if (hists__add_entry(&session->hists, &al, sample->period)) {
53 pr_warning("problem incrementing symbol period, skipping event\n"); 60 pr_warning("problem incrementing symbol period, skipping event\n");
54 return -1; 61 return -1;
55 } 62 }
56 63
57 evsel->hists.stats.total_period += sample->period; 64 session->hists.stats.total_period += sample->period;
58 return 0; 65 return 0;
59} 66}
60 67
61static struct perf_tool perf_diff = { 68static struct perf_diff diff = {
62 .sample = diff__process_sample_event, 69 .tool = {
63 .mmap = perf_event__process_mmap, 70 .sample = diff__process_sample_event,
64 .comm = perf_event__process_comm, 71 .mmap = perf_event__process_mmap,
65 .exit = perf_event__process_task, 72 .comm = perf_event__process_comm,
66 .fork = perf_event__process_task, 73 .exit = perf_event__process_task,
67 .lost = perf_event__process_lost, 74 .fork = perf_event__process_task,
68 .ordered_samples = true, 75 .lost = perf_event__process_lost,
69 .ordering_requires_timestamps = true, 76 .ordered_samples = true,
77 .ordering_requires_timestamps = true,
78 },
70}; 79};
71 80
72static void perf_session__insert_hist_entry_by_name(struct rb_root *root, 81static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@@ -107,12 +116,6 @@ static void hists__resort_entries(struct hists *self)
107 self->entries = tmp; 116 self->entries = tmp;
108} 117}
109 118
110static void hists__set_positions(struct hists *self)
111{
112 hists__output_resort(self);
113 hists__resort_entries(self);
114}
115
116static struct hist_entry *hists__find_entry(struct hists *self, 119static struct hist_entry *hists__find_entry(struct hists *self,
117 struct hist_entry *he) 120 struct hist_entry *he)
118{ 121{
@@ -146,30 +149,37 @@ static void hists__match(struct hists *older, struct hists *newer)
146static int __cmd_diff(void) 149static int __cmd_diff(void)
147{ 150{
148 int ret, i; 151 int ret, i;
152#define older (session[0])
153#define newer (session[1])
149 struct perf_session *session[2]; 154 struct perf_session *session[2];
150 155
151 session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff); 156 older = perf_session__new(input_old, O_RDONLY, force, false,
152 session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff); 157 &diff.tool);
158 newer = perf_session__new(input_new, O_RDONLY, force, false,
159 &diff.tool);
153 if (session[0] == NULL || session[1] == NULL) 160 if (session[0] == NULL || session[1] == NULL)
154 return -ENOMEM; 161 return -ENOMEM;
155 162
156 for (i = 0; i < 2; ++i) { 163 for (i = 0; i < 2; ++i) {
157 ret = perf_session__process_events(session[i], &perf_diff); 164 diff.session = session[i];
165 ret = perf_session__process_events(session[i], &diff.tool);
158 if (ret) 166 if (ret)
159 goto out_delete; 167 goto out_delete;
168 hists__output_resort(&session[i]->hists);
160 } 169 }
161 170
162 hists__output_resort(&session[1]->hists);
163 if (show_displacement) 171 if (show_displacement)
164 hists__set_positions(&session[0]->hists); 172 hists__resort_entries(&older->hists);
165 173
166 hists__match(&session[0]->hists, &session[1]->hists); 174 hists__match(&older->hists, &newer->hists);
167 hists__fprintf(&session[1]->hists, &session[0]->hists, 175 hists__fprintf(&newer->hists, &older->hists,
168 show_displacement, true, 0, 0, stdout); 176 show_displacement, true, 0, 0, stdout);
169out_delete: 177out_delete:
170 for (i = 0; i < 2; ++i) 178 for (i = 0; i < 2; ++i)
171 perf_session__delete(session[i]); 179 perf_session__delete(session[i]);
172 return ret; 180 return ret;
181#undef older
182#undef newer
173} 183}
174 184
175static const char * const diff_usage[] = { 185static const char * const diff_usage[] = {
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 2296c391d0f5..12c814838993 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -922,12 +922,12 @@ static const struct option info_options[] = {
922 OPT_BOOLEAN('t', "threads", &info_threads, 922 OPT_BOOLEAN('t', "threads", &info_threads,
923 "dump thread list in perf.data"), 923 "dump thread list in perf.data"),
924 OPT_BOOLEAN('m', "map", &info_map, 924 OPT_BOOLEAN('m', "map", &info_map,
925 "map of lock instances (name:address table)"), 925 "map of lock instances (address:name table)"),
926 OPT_END() 926 OPT_END()
927}; 927};
928 928
929static const char * const lock_usage[] = { 929static const char * const lock_usage[] = {
930 "perf lock [<options>] {record|trace|report}", 930 "perf lock [<options>] {record|report|script|info}",
931 NULL 931 NULL
932}; 932};
933 933
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index fb8566181f27..4935c09dd5b5 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -58,7 +58,7 @@ static struct {
58 struct perf_probe_event events[MAX_PROBES]; 58 struct perf_probe_event events[MAX_PROBES];
59 struct strlist *dellist; 59 struct strlist *dellist;
60 struct line_range line_range; 60 struct line_range line_range;
61 const char *target_module; 61 const char *target;
62 int max_probe_points; 62 int max_probe_points;
63 struct strfilter *filter; 63 struct strfilter *filter;
64} params; 64} params;
@@ -246,7 +246,7 @@ static const struct option options[] = {
246 "file", "vmlinux pathname"), 246 "file", "vmlinux pathname"),
247 OPT_STRING('s', "source", &symbol_conf.source_prefix, 247 OPT_STRING('s', "source", &symbol_conf.source_prefix,
248 "directory", "path to kernel source"), 248 "directory", "path to kernel source"),
249 OPT_STRING('m', "module", &params.target_module, 249 OPT_STRING('m', "module", &params.target,
250 "modname|path", 250 "modname|path",
251 "target module name (for online) or path (for offline)"), 251 "target module name (for online) or path (for offline)"),
252#endif 252#endif
@@ -333,7 +333,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
333 if (!params.filter) 333 if (!params.filter)
334 params.filter = strfilter__new(DEFAULT_FUNC_FILTER, 334 params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
335 NULL); 335 NULL);
336 ret = show_available_funcs(params.target_module, 336 ret = show_available_funcs(params.target,
337 params.filter); 337 params.filter);
338 strfilter__delete(params.filter); 338 strfilter__delete(params.filter);
339 if (ret < 0) 339 if (ret < 0)
@@ -354,7 +354,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
354 usage_with_options(probe_usage, options); 354 usage_with_options(probe_usage, options);
355 } 355 }
356 356
357 ret = show_line_range(&params.line_range, params.target_module); 357 ret = show_line_range(&params.line_range, params.target);
358 if (ret < 0) 358 if (ret < 0)
359 pr_err(" Error: Failed to show lines. (%d)\n", ret); 359 pr_err(" Error: Failed to show lines. (%d)\n", ret);
360 return ret; 360 return ret;
@@ -371,7 +371,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
371 371
372 ret = show_available_vars(params.events, params.nevents, 372 ret = show_available_vars(params.events, params.nevents,
373 params.max_probe_points, 373 params.max_probe_points,
374 params.target_module, 374 params.target,
375 params.filter, 375 params.filter,
376 params.show_ext_vars); 376 params.show_ext_vars);
377 strfilter__delete(params.filter); 377 strfilter__delete(params.filter);
@@ -393,7 +393,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
393 if (params.nevents) { 393 if (params.nevents) {
394 ret = add_perf_probe_events(params.events, params.nevents, 394 ret = add_perf_probe_events(params.events, params.nevents,
395 params.max_probe_points, 395 params.max_probe_points,
396 params.target_module, 396 params.target,
397 params.force_add); 397 params.force_add);
398 if (ret < 0) { 398 if (ret < 0) {
399 pr_err(" Error: Failed to add events. (%d)\n", ret); 399 pr_err(" Error: Failed to add events. (%d)\n", ret);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 0abfb18b911f..be4e1eee782e 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -44,6 +44,7 @@ struct perf_record {
44 struct perf_evlist *evlist; 44 struct perf_evlist *evlist;
45 struct perf_session *session; 45 struct perf_session *session;
46 const char *progname; 46 const char *progname;
47 const char *uid_str;
47 int output; 48 int output;
48 unsigned int page_size; 49 unsigned int page_size;
49 int realtime_prio; 50 int realtime_prio;
@@ -204,8 +205,11 @@ static void perf_record__open(struct perf_record *rec)
204 205
205 if (opts->group && pos != first) 206 if (opts->group && pos != first)
206 group_fd = first->fd; 207 group_fd = first->fd;
208fallback_missing_features:
209 if (opts->exclude_guest_missing)
210 attr->exclude_guest = attr->exclude_host = 0;
207retry_sample_id: 211retry_sample_id:
208 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; 212 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
209try_again: 213try_again:
210 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, 214 if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
211 opts->group, group_fd) < 0) { 215 opts->group, group_fd) < 0) {
@@ -217,15 +221,23 @@ try_again:
217 } else if (err == ENODEV && opts->cpu_list) { 221 } else if (err == ENODEV && opts->cpu_list) {
218 die("No such device - did you specify" 222 die("No such device - did you specify"
219 " an out-of-range profile CPU?\n"); 223 " an out-of-range profile CPU?\n");
220 } else if (err == EINVAL && opts->sample_id_all_avail) { 224 } else if (err == EINVAL) {
221 /* 225 if (!opts->exclude_guest_missing &&
222 * Old kernel, no attr->sample_id_type_all field 226 (attr->exclude_guest || attr->exclude_host)) {
223 */ 227 pr_debug("Old kernel, cannot exclude "
224 opts->sample_id_all_avail = false; 228 "guest or host samples.\n");
225 if (!opts->sample_time && !opts->raw_samples && !time_needed) 229 opts->exclude_guest_missing = true;
226 attr->sample_type &= ~PERF_SAMPLE_TIME; 230 goto fallback_missing_features;
227 231 } else if (!opts->sample_id_all_missing) {
228 goto retry_sample_id; 232 /*
233 * Old kernel, no attr->sample_id_type_all field
234 */
235 opts->sample_id_all_missing = true;
236 if (!opts->sample_time && !opts->raw_samples && !time_needed)
237 attr->sample_type &= ~PERF_SAMPLE_TIME;
238
239 goto retry_sample_id;
240 }
229 } 241 }
230 242
231 /* 243 /*
@@ -385,7 +397,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
385{ 397{
386 struct stat st; 398 struct stat st;
387 int flags; 399 int flags;
388 int err, output; 400 int err, output, feat;
389 unsigned long waking = 0; 401 unsigned long waking = 0;
390 const bool forks = argc > 0; 402 const bool forks = argc > 0;
391 struct machine *machine; 403 struct machine *machine;
@@ -452,8 +464,17 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
452 464
453 rec->session = session; 465 rec->session = session;
454 466
455 if (!rec->no_buildid) 467 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
456 perf_header__set_feat(&session->header, HEADER_BUILD_ID); 468 perf_header__set_feat(&session->header, feat);
469
470 if (rec->no_buildid)
471 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
472
473 if (!have_tracepoints(&evsel_list->entries))
474 perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
475
476 if (!rec->opts.branch_stack)
477 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
457 478
458 if (!rec->file_new) { 479 if (!rec->file_new) {
459 err = perf_session__read_header(session, output); 480 err = perf_session__read_header(session, output);
@@ -461,22 +482,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
461 goto out_delete_session; 482 goto out_delete_session;
462 } 483 }
463 484
464 if (have_tracepoints(&evsel_list->entries))
465 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
466
467 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
468 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
469 perf_header__set_feat(&session->header, HEADER_ARCH);
470 perf_header__set_feat(&session->header, HEADER_CPUDESC);
471 perf_header__set_feat(&session->header, HEADER_NRCPUS);
472 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
473 perf_header__set_feat(&session->header, HEADER_CMDLINE);
474 perf_header__set_feat(&session->header, HEADER_VERSION);
475 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
476 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
477 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
478 perf_header__set_feat(&session->header, HEADER_CPUID);
479
480 if (forks) { 485 if (forks) {
481 err = perf_evlist__prepare_workload(evsel_list, opts, argv); 486 err = perf_evlist__prepare_workload(evsel_list, opts, argv);
482 if (err < 0) { 487 if (err < 0) {
@@ -503,9 +508,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
503 return err; 508 return err;
504 } 509 }
505 510
506 if (!!rec->no_buildid 511 if (!rec->no_buildid
507 && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { 512 && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
508 pr_err("Couldn't generating buildids. " 513 pr_err("Couldn't generate buildids. "
509 "Use --no-buildid to profile anyway.\n"); 514 "Use --no-buildid to profile anyway.\n");
510 return -1; 515 return -1;
511 } 516 }
@@ -636,6 +641,90 @@ out_delete_session:
636 return err; 641 return err;
637} 642}
638 643
644#define BRANCH_OPT(n, m) \
645 { .name = n, .mode = (m) }
646
647#define BRANCH_END { .name = NULL }
648
649struct branch_mode {
650 const char *name;
651 int mode;
652};
653
654static const struct branch_mode branch_modes[] = {
655 BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
656 BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
657 BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
658 BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
659 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
660 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
661 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
662 BRANCH_END
663};
664
665static int
666parse_branch_stack(const struct option *opt, const char *str, int unset)
667{
668#define ONLY_PLM \
669 (PERF_SAMPLE_BRANCH_USER |\
670 PERF_SAMPLE_BRANCH_KERNEL |\
671 PERF_SAMPLE_BRANCH_HV)
672
673 uint64_t *mode = (uint64_t *)opt->value;
674 const struct branch_mode *br;
675 char *s, *os = NULL, *p;
676 int ret = -1;
677
678 if (unset)
679 return 0;
680
681 /*
682 * cannot set it twice, -b + --branch-filter for instance
683 */
684 if (*mode)
685 return -1;
686
687 /* str may be NULL in case no arg is passed to -b */
688 if (str) {
689 /* because str is read-only */
690 s = os = strdup(str);
691 if (!s)
692 return -1;
693
694 for (;;) {
695 p = strchr(s, ',');
696 if (p)
697 *p = '\0';
698
699 for (br = branch_modes; br->name; br++) {
700 if (!strcasecmp(s, br->name))
701 break;
702 }
703 if (!br->name) {
704 ui__warning("unknown branch filter %s,"
705 " check man page\n", s);
706 goto error;
707 }
708
709 *mode |= br->mode;
710
711 if (!p)
712 break;
713
714 s = p + 1;
715 }
716 }
717 ret = 0;
718
719 /* default to any branch */
720 if ((*mode & ~ONLY_PLM) == 0) {
721 *mode = PERF_SAMPLE_BRANCH_ANY;
722 }
723error:
724 free(os);
725 return ret;
726}
727
639static const char * const record_usage[] = { 728static const char * const record_usage[] = {
640 "perf record [<options>] [<command>]", 729 "perf record [<options>] [<command>]",
641 "perf record [<options>] -- <command> [<options>]", 730 "perf record [<options>] -- <command> [<options>]",
@@ -654,13 +743,10 @@ static const char * const record_usage[] = {
654 */ 743 */
655static struct perf_record record = { 744static struct perf_record record = {
656 .opts = { 745 .opts = {
657 .target_pid = -1,
658 .target_tid = -1,
659 .mmap_pages = UINT_MAX, 746 .mmap_pages = UINT_MAX,
660 .user_freq = UINT_MAX, 747 .user_freq = UINT_MAX,
661 .user_interval = ULLONG_MAX, 748 .user_interval = ULLONG_MAX,
662 .freq = 1000, 749 .freq = 1000,
663 .sample_id_all_avail = true,
664 }, 750 },
665 .write_mode = WRITE_FORCE, 751 .write_mode = WRITE_FORCE,
666 .file_new = true, 752 .file_new = true,
@@ -679,9 +765,9 @@ const struct option record_options[] = {
679 parse_events_option), 765 parse_events_option),
680 OPT_CALLBACK(0, "filter", &record.evlist, "filter", 766 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
681 "event filter", parse_filter), 767 "event filter", parse_filter),
682 OPT_INTEGER('p', "pid", &record.opts.target_pid, 768 OPT_STRING('p', "pid", &record.opts.target_pid, "pid",
683 "record events on existing process id"), 769 "record events on existing process id"),
684 OPT_INTEGER('t', "tid", &record.opts.target_tid, 770 OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
685 "record events on existing thread id"), 771 "record events on existing thread id"),
686 OPT_INTEGER('r', "realtime", &record.realtime_prio, 772 OPT_INTEGER('r', "realtime", &record.realtime_prio,
687 "collect data with this RT SCHED_FIFO priority"), 773 "collect data with this RT SCHED_FIFO priority"),
@@ -727,6 +813,15 @@ const struct option record_options[] = {
727 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 813 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
728 "monitor event in cgroup name only", 814 "monitor event in cgroup name only",
729 parse_cgroups), 815 parse_cgroups),
816 OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
817
818 OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
819 "branch any", "sample any taken branches",
820 parse_branch_stack),
821
822 OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
823 "branch filter mask", "branch stack filter modes",
824 parse_branch_stack),
730 OPT_END() 825 OPT_END()
731}; 826};
732 827
@@ -747,8 +842,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
747 842
748 argc = parse_options(argc, argv, record_options, record_usage, 843 argc = parse_options(argc, argv, record_options, record_usage,
749 PARSE_OPT_STOP_AT_NON_OPTION); 844 PARSE_OPT_STOP_AT_NON_OPTION);
750 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 && 845 if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
751 !rec->opts.system_wide && !rec->opts.cpu_list) 846 !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
752 usage_with_options(record_usage, record_options); 847 usage_with_options(record_usage, record_options);
753 848
754 if (rec->force && rec->append_file) { 849 if (rec->force && rec->append_file) {
@@ -788,11 +883,17 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
788 goto out_symbol_exit; 883 goto out_symbol_exit;
789 } 884 }
790 885
791 if (rec->opts.target_pid != -1) 886 rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
887 rec->opts.target_pid);
888 if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
889 goto out_free_fd;
890
891 if (rec->opts.target_pid)
792 rec->opts.target_tid = rec->opts.target_pid; 892 rec->opts.target_tid = rec->opts.target_pid;
793 893
794 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, 894 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
795 rec->opts.target_tid, rec->opts.cpu_list) < 0) 895 rec->opts.target_tid, rec->opts.uid,
896 rec->opts.cpu_list) < 0)
796 usage_with_options(record_usage, record_options); 897 usage_with_options(record_usage, record_options);
797 898
798 list_for_each_entry(pos, &evsel_list->entries, node) { 899 list_for_each_entry(pos, &evsel_list->entries, node) {
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 25d34d483e49..2e317438980b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -40,7 +40,7 @@ struct perf_report {
40 struct perf_tool tool; 40 struct perf_tool tool;
41 struct perf_session *session; 41 struct perf_session *session;
42 char const *input_name; 42 char const *input_name;
43 bool force, use_tui, use_stdio; 43 bool force, use_tui, use_gtk, use_stdio;
44 bool hide_unresolved; 44 bool hide_unresolved;
45 bool dont_use_callchains; 45 bool dont_use_callchains;
46 bool show_full_info; 46 bool show_full_info;
@@ -50,9 +50,86 @@ struct perf_report {
50 const char *pretty_printing_style; 50 const char *pretty_printing_style;
51 symbol_filter_t annotate_init; 51 symbol_filter_t annotate_init;
52 const char *cpu_list; 52 const char *cpu_list;
53 const char *symbol_filter_str;
53 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 54 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
54}; 55};
55 56
57static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
58 struct addr_location *al,
59 struct perf_sample *sample,
60 struct perf_evsel *evsel,
61 struct machine *machine)
62{
63 struct perf_report *rep = container_of(tool, struct perf_report, tool);
64 struct symbol *parent = NULL;
65 int err = 0;
66 unsigned i;
67 struct hist_entry *he;
68 struct branch_info *bi, *bx;
69
70 if ((sort__has_parent || symbol_conf.use_callchain)
71 && sample->callchain) {
72 err = machine__resolve_callchain(machine, evsel, al->thread,
73 sample->callchain, &parent);
74 if (err)
75 return err;
76 }
77
78 bi = machine__resolve_bstack(machine, al->thread,
79 sample->branch_stack);
80 if (!bi)
81 return -ENOMEM;
82
83 for (i = 0; i < sample->branch_stack->nr; i++) {
84 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
85 continue;
86 /*
87 * The report shows the percentage of total branches captured
88 * and not events sampled. Thus we use a pseudo period of 1.
89 */
90 he = __hists__add_branch_entry(&evsel->hists, al, parent,
91 &bi[i], 1);
92 if (he) {
93 struct annotation *notes;
94 err = -ENOMEM;
95 bx = he->branch_info;
96 if (bx->from.sym && use_browser > 0) {
97 notes = symbol__annotation(bx->from.sym);
98 if (!notes->src
99 && symbol__alloc_hist(bx->from.sym) < 0)
100 goto out;
101
102 err = symbol__inc_addr_samples(bx->from.sym,
103 bx->from.map,
104 evsel->idx,
105 bx->from.al_addr);
106 if (err)
107 goto out;
108 }
109
110 if (bx->to.sym && use_browser > 0) {
111 notes = symbol__annotation(bx->to.sym);
112 if (!notes->src
113 && symbol__alloc_hist(bx->to.sym) < 0)
114 goto out;
115
116 err = symbol__inc_addr_samples(bx->to.sym,
117 bx->to.map,
118 evsel->idx,
119 bx->to.al_addr);
120 if (err)
121 goto out;
122 }
123 evsel->hists.stats.total_period += 1;
124 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
125 err = 0;
126 } else
127 return -ENOMEM;
128 }
129out:
130 return err;
131}
132
56static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, 133static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
57 struct addr_location *al, 134 struct addr_location *al,
58 struct perf_sample *sample, 135 struct perf_sample *sample,
@@ -126,14 +203,21 @@ static int process_sample_event(struct perf_tool *tool,
126 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 203 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
127 return 0; 204 return 0;
128 205
129 if (al.map != NULL) 206 if (sort__branch_mode == 1) {
130 al.map->dso->hit = 1; 207 if (perf_report__add_branch_hist_entry(tool, &al, sample,
208 evsel, machine)) {
209 pr_debug("problem adding lbr entry, skipping event\n");
210 return -1;
211 }
212 } else {
213 if (al.map != NULL)
214 al.map->dso->hit = 1;
131 215
132 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { 216 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
133 pr_debug("problem incrementing symbol period, skipping event\n"); 217 pr_debug("problem incrementing symbol period, skipping event\n");
134 return -1; 218 return -1;
219 }
135 } 220 }
136
137 return 0; 221 return 0;
138} 222}
139 223
@@ -188,6 +272,15 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
188 } 272 }
189 } 273 }
190 274
275 if (sort__branch_mode == 1) {
276 if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
277 fprintf(stderr, "selected -b but no branch data."
278 " Did you call perf record without"
279 " -b?\n");
280 return -1;
281 }
282 }
283
191 return 0; 284 return 0;
192} 285}
193 286
@@ -246,7 +339,7 @@ static int __cmd_report(struct perf_report *rep)
246{ 339{
247 int ret = -EINVAL; 340 int ret = -EINVAL;
248 u64 nr_samples; 341 u64 nr_samples;
249 struct perf_session *session; 342 struct perf_session *session = rep->session;
250 struct perf_evsel *pos; 343 struct perf_evsel *pos;
251 struct map *kernel_map; 344 struct map *kernel_map;
252 struct kmap *kernel_kmap; 345 struct kmap *kernel_kmap;
@@ -254,13 +347,6 @@ static int __cmd_report(struct perf_report *rep)
254 347
255 signal(SIGINT, sig_handler); 348 signal(SIGINT, sig_handler);
256 349
257 session = perf_session__new(rep->input_name, O_RDONLY,
258 rep->force, false, &rep->tool);
259 if (session == NULL)
260 return -ENOMEM;
261
262 rep->session = session;
263
264 if (rep->cpu_list) { 350 if (rep->cpu_list) {
265 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 351 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
266 rep->cpu_bitmap); 352 rep->cpu_bitmap);
@@ -315,6 +401,9 @@ static int __cmd_report(struct perf_report *rep)
315 list_for_each_entry(pos, &session->evlist->entries, node) { 401 list_for_each_entry(pos, &session->evlist->entries, node) {
316 struct hists *hists = &pos->hists; 402 struct hists *hists = &pos->hists;
317 403
404 if (pos->idx == 0)
405 hists->symbol_filter_str = rep->symbol_filter_str;
406
318 hists__collapse_resort(hists); 407 hists__collapse_resort(hists);
319 hists__output_resort(hists); 408 hists__output_resort(hists);
320 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; 409 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
@@ -326,8 +415,13 @@ static int __cmd_report(struct perf_report *rep)
326 } 415 }
327 416
328 if (use_browser > 0) { 417 if (use_browser > 0) {
329 perf_evlist__tui_browse_hists(session->evlist, help, 418 if (use_browser == 1) {
330 NULL, NULL, 0); 419 perf_evlist__tui_browse_hists(session->evlist, help,
420 NULL, NULL, 0);
421 } else if (use_browser == 2) {
422 perf_evlist__gtk_browse_hists(session->evlist, help,
423 NULL, NULL, 0);
424 }
331 } else 425 } else
332 perf_evlist__tty_browse_hists(session->evlist, rep, help); 426 perf_evlist__tty_browse_hists(session->evlist, rep, help);
333 427
@@ -427,9 +521,19 @@ setup:
427 return 0; 521 return 0;
428} 522}
429 523
524static int
525parse_branch_mode(const struct option *opt __used, const char *str __used, int unset)
526{
527 sort__branch_mode = !unset;
528 return 0;
529}
530
430int cmd_report(int argc, const char **argv, const char *prefix __used) 531int cmd_report(int argc, const char **argv, const char *prefix __used)
431{ 532{
533 struct perf_session *session;
432 struct stat st; 534 struct stat st;
535 bool has_br_stack = false;
536 int ret = -1;
433 char callchain_default_opt[] = "fractal,0.5,callee"; 537 char callchain_default_opt[] = "fractal,0.5,callee";
434 const char * const report_usage[] = { 538 const char * const report_usage[] = {
435 "perf report [<options>]", 539 "perf report [<options>]",
@@ -474,10 +578,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
474 OPT_STRING(0, "pretty", &report.pretty_printing_style, "key", 578 OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
475 "pretty printing style key: normal raw"), 579 "pretty printing style key: normal raw"),
476 OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"), 580 OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
581 OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
477 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 582 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
478 "Use the stdio interface"), 583 "Use the stdio interface"),
479 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 584 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
480 "sort by key(s): pid, comm, dso, symbol, parent"), 585 "sort by key(s): pid, comm, dso, symbol, parent, dso_to,"
586 " dso_from, symbol_to, symbol_from, mispredict"),
481 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 587 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
482 "Show sample percentage for different cpu modes"), 588 "Show sample percentage for different cpu modes"),
483 OPT_STRING('p', "parent", &parent_pattern, "regex", 589 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -495,6 +601,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
495 "only consider symbols in these comms"), 601 "only consider symbols in these comms"),
496 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 602 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
497 "only consider these symbols"), 603 "only consider these symbols"),
604 OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
605 "only show symbols that (partially) match with this filter"),
498 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, 606 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
499 "width[,width...]", 607 "width[,width...]",
500 "don't try to adjust column width, use these fixed values"), 608 "don't try to adjust column width, use these fixed values"),
@@ -517,6 +625,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
517 "Specify disassembler style (e.g. -M intel for intel syntax)"), 625 "Specify disassembler style (e.g. -M intel for intel syntax)"),
518 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 626 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
519 "Show a column with the sum of periods"), 627 "Show a column with the sum of periods"),
628 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
629 "use branch records for histogram filling", parse_branch_mode),
520 OPT_END() 630 OPT_END()
521 }; 631 };
522 632
@@ -526,6 +636,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
526 use_browser = 0; 636 use_browser = 0;
527 else if (report.use_tui) 637 else if (report.use_tui)
528 use_browser = 1; 638 use_browser = 1;
639 else if (report.use_gtk)
640 use_browser = 2;
529 641
530 if (report.inverted_callchain) 642 if (report.inverted_callchain)
531 callchain_param.order = ORDER_CALLER; 643 callchain_param.order = ORDER_CALLER;
@@ -536,11 +648,39 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
536 else 648 else
537 report.input_name = "perf.data"; 649 report.input_name = "perf.data";
538 } 650 }
651 session = perf_session__new(report.input_name, O_RDONLY,
652 report.force, false, &report.tool);
653 if (session == NULL)
654 return -ENOMEM;
539 655
540 if (strcmp(report.input_name, "-") != 0) 656 report.session = session;
541 setup_browser(true); 657
542 else 658 has_br_stack = perf_header__has_feat(&session->header,
659 HEADER_BRANCH_STACK);
660
661 if (sort__branch_mode == -1 && has_br_stack)
662 sort__branch_mode = 1;
663
664 /* sort__branch_mode could be 0 if --no-branch-stack */
665 if (sort__branch_mode == 1) {
666 /*
667 * if no sort_order is provided, then specify
668 * branch-mode specific order
669 */
670 if (sort_order == default_sort_order)
671 sort_order = "comm,dso_from,symbol_from,"
672 "dso_to,symbol_to";
673
674 }
675
676 if (strcmp(report.input_name, "-") != 0) {
677 if (report.use_gtk)
678 perf_gtk_setup_browser(argc, argv, true);
679 else
680 setup_browser(true);
681 } else {
543 use_browser = 0; 682 use_browser = 0;
683 }
544 684
545 /* 685 /*
546 * Only in the newt browser we are doing integrated annotation, 686 * Only in the newt browser we are doing integrated annotation,
@@ -568,13 +708,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
568 } 708 }
569 709
570 if (symbol__init() < 0) 710 if (symbol__init() < 0)
571 return -1; 711 goto error;
572 712
573 setup_sorting(report_usage, options); 713 setup_sorting(report_usage, options);
574 714
575 if (parent_pattern != default_parent_pattern) { 715 if (parent_pattern != default_parent_pattern) {
576 if (sort_dimension__add("parent") < 0) 716 if (sort_dimension__add("parent") < 0)
577 return -1; 717 goto error;
578 718
579 /* 719 /*
580 * Only show the parent fields if we explicitly 720 * Only show the parent fields if we explicitly
@@ -586,15 +726,31 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
586 } else 726 } else
587 symbol_conf.exclude_other = false; 727 symbol_conf.exclude_other = false;
588 728
589 /* 729 if (argc) {
590 * Any (unrecognized) arguments left? 730 /*
591 */ 731 * Special case: if there's an argument left then assume that
592 if (argc) 732 * it's a symbol filter:
593 usage_with_options(report_usage, options); 733 */
734 if (argc > 1)
735 usage_with_options(report_usage, options);
736
737 report.symbol_filter_str = argv[0];
738 }
594 739
595 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
596 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 740 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
597 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
598 741
599 return __cmd_report(&report); 742 if (sort__branch_mode == 1) {
743 sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
744 sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
745 sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
746 sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
747 } else {
748 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
749 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
750 }
751
752 ret = __cmd_report(&report);
753error:
754 perf_session__delete(session);
755 return ret;
600} 756}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index fb8b5f83b4a0..1cad3af4bf4c 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -17,6 +17,7 @@
17#include "util/debug.h" 17#include "util/debug.h"
18 18
19#include <sys/prctl.h> 19#include <sys/prctl.h>
20#include <sys/resource.h>
20 21
21#include <semaphore.h> 22#include <semaphore.h>
22#include <pthread.h> 23#include <pthread.h>
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index bb68ddf257b7..d4ce733b9eba 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -40,6 +40,7 @@ enum perf_output_field {
40 PERF_OUTPUT_SYM = 1U << 8, 40 PERF_OUTPUT_SYM = 1U << 8,
41 PERF_OUTPUT_DSO = 1U << 9, 41 PERF_OUTPUT_DSO = 1U << 9,
42 PERF_OUTPUT_ADDR = 1U << 10, 42 PERF_OUTPUT_ADDR = 1U << 10,
43 PERF_OUTPUT_SYMOFFSET = 1U << 11,
43}; 44};
44 45
45struct output_option { 46struct output_option {
@@ -57,6 +58,7 @@ struct output_option {
57 {.str = "sym", .field = PERF_OUTPUT_SYM}, 58 {.str = "sym", .field = PERF_OUTPUT_SYM},
58 {.str = "dso", .field = PERF_OUTPUT_DSO}, 59 {.str = "dso", .field = PERF_OUTPUT_DSO},
59 {.str = "addr", .field = PERF_OUTPUT_ADDR}, 60 {.str = "addr", .field = PERF_OUTPUT_ADDR},
61 {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
60}; 62};
61 63
62/* default set to maintain compatibility with current format */ 64/* default set to maintain compatibility with current format */
@@ -193,6 +195,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
193 "to symbols.\n"); 195 "to symbols.\n");
194 return -EINVAL; 196 return -EINVAL;
195 } 197 }
198 if (PRINT_FIELD(SYMOFFSET) && !PRINT_FIELD(SYM)) {
199 pr_err("Display of offsets requested but symbol is not"
200 "selected.\n");
201 return -EINVAL;
202 }
196 if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { 203 if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
197 pr_err("Display of DSO requested but neither sample IP nor " 204 pr_err("Display of DSO requested but neither sample IP nor "
198 "sample address\nis selected. Hence, no addresses to convert " 205 "sample address\nis selected. Hence, no addresses to convert "
@@ -300,10 +307,17 @@ static void print_sample_start(struct perf_sample *sample,
300 } else 307 } else
301 evname = __event_name(attr->type, attr->config); 308 evname = __event_name(attr->type, attr->config);
302 309
303 printf("%s: ", evname ? evname : "(unknown)"); 310 printf("%s: ", evname ? evname : "[unknown]");
304 } 311 }
305} 312}
306 313
314static bool is_bts_event(struct perf_event_attr *attr)
315{
316 return ((attr->type == PERF_TYPE_HARDWARE) &&
317 (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
318 (attr->sample_period == 1));
319}
320
307static bool sample_addr_correlates_sym(struct perf_event_attr *attr) 321static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
308{ 322{
309 if ((attr->type == PERF_TYPE_SOFTWARE) && 323 if ((attr->type == PERF_TYPE_SOFTWARE) &&
@@ -312,6 +326,9 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
312 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))) 326 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
313 return true; 327 return true;
314 328
329 if (is_bts_event(attr))
330 return true;
331
315 return false; 332 return false;
316} 333}
317 334
@@ -323,7 +340,6 @@ static void print_sample_addr(union perf_event *event,
323{ 340{
324 struct addr_location al; 341 struct addr_location al;
325 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 342 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
326 const char *symname, *dsoname;
327 343
328 printf("%16" PRIx64, sample->addr); 344 printf("%16" PRIx64, sample->addr);
329 345
@@ -343,22 +359,46 @@ static void print_sample_addr(union perf_event *event,
343 al.sym = map__find_symbol(al.map, al.addr, NULL); 359 al.sym = map__find_symbol(al.map, al.addr, NULL);
344 360
345 if (PRINT_FIELD(SYM)) { 361 if (PRINT_FIELD(SYM)) {
346 if (al.sym && al.sym->name) 362 printf(" ");
347 symname = al.sym->name; 363 if (PRINT_FIELD(SYMOFFSET))
364 symbol__fprintf_symname_offs(al.sym, &al, stdout);
348 else 365 else
349 symname = ""; 366 symbol__fprintf_symname(al.sym, stdout);
350
351 printf(" %16s", symname);
352 } 367 }
353 368
354 if (PRINT_FIELD(DSO)) { 369 if (PRINT_FIELD(DSO)) {
355 if (al.map && al.map->dso && al.map->dso->name) 370 printf(" (");
356 dsoname = al.map->dso->name; 371 map__fprintf_dsoname(al.map, stdout);
357 else 372 printf(")");
358 dsoname = ""; 373 }
374}
359 375
360 printf(" (%s)", dsoname); 376static void print_sample_bts(union perf_event *event,
377 struct perf_sample *sample,
378 struct perf_evsel *evsel,
379 struct machine *machine,
380 struct thread *thread)
381{
382 struct perf_event_attr *attr = &evsel->attr;
383
384 /* print branch_from information */
385 if (PRINT_FIELD(IP)) {
386 if (!symbol_conf.use_callchain)
387 printf(" ");
388 else
389 printf("\n");
390 perf_event__print_ip(event, sample, machine, evsel,
391 PRINT_FIELD(SYM), PRINT_FIELD(DSO),
392 PRINT_FIELD(SYMOFFSET));
361 } 393 }
394
395 printf(" => ");
396
397 /* print branch_to information */
398 if (PRINT_FIELD(ADDR))
399 print_sample_addr(event, sample, machine, thread, attr);
400
401 printf("\n");
362} 402}
363 403
364static void process_event(union perf_event *event __unused, 404static void process_event(union perf_event *event __unused,
@@ -374,6 +414,11 @@ static void process_event(union perf_event *event __unused,
374 414
375 print_sample_start(sample, thread, attr); 415 print_sample_start(sample, thread, attr);
376 416
417 if (is_bts_event(attr)) {
418 print_sample_bts(event, sample, evsel, machine, thread);
419 return;
420 }
421
377 if (PRINT_FIELD(TRACE)) 422 if (PRINT_FIELD(TRACE))
378 print_trace_event(sample->cpu, sample->raw_data, 423 print_trace_event(sample->cpu, sample->raw_data,
379 sample->raw_size); 424 sample->raw_size);
@@ -387,7 +432,8 @@ static void process_event(union perf_event *event __unused,
387 else 432 else
388 printf("\n"); 433 printf("\n");
389 perf_event__print_ip(event, sample, machine, evsel, 434 perf_event__print_ip(event, sample, machine, evsel,
390 PRINT_FIELD(SYM), PRINT_FIELD(DSO)); 435 PRINT_FIELD(SYM), PRINT_FIELD(DSO),
436 PRINT_FIELD(SYMOFFSET));
391 } 437 }
392 438
393 printf("\n"); 439 printf("\n");
@@ -1097,7 +1143,10 @@ static const struct option options[] = {
1097 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 1143 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1098 "Look for files with symbols relative to this directory"), 1144 "Look for files with symbols relative to this directory"),
1099 OPT_CALLBACK('f', "fields", NULL, "str", 1145 OPT_CALLBACK('f', "fields", NULL, "str",
1100 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", 1146 "comma separated output fields prepend with 'type:'. "
1147 "Valid types: hw,sw,trace,raw. "
1148 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
1149 "addr,symoff",
1101 parse_output_fields), 1150 parse_output_fields),
1102 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1151 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1103 "system-wide collection from all CPUs"), 1152 "system-wide collection from all CPUs"),
@@ -1106,6 +1155,9 @@ static const struct option options[] = {
1106 "only display events for these comms"), 1155 "only display events for these comms"),
1107 OPT_BOOLEAN('I', "show-info", &show_full_info, 1156 OPT_BOOLEAN('I', "show-info", &show_full_info,
1108 "display extended information from perf.data file"), 1157 "display extended information from perf.data file"),
1158 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
1159 "Show the path of [kernel.kallsyms]"),
1160
1109 OPT_END() 1161 OPT_END()
1110}; 1162};
1111 1163
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index f5d2a63eba66..c941bb640f49 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -182,8 +182,8 @@ static int run_count = 1;
182static bool no_inherit = false; 182static bool no_inherit = false;
183static bool scale = true; 183static bool scale = true;
184static bool no_aggr = false; 184static bool no_aggr = false;
185static pid_t target_pid = -1; 185static const char *target_pid;
186static pid_t target_tid = -1; 186static const char *target_tid;
187static pid_t child_pid = -1; 187static pid_t child_pid = -1;
188static bool null_run = false; 188static bool null_run = false;
189static int detailed_run = 0; 189static int detailed_run = 0;
@@ -296,7 +296,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
296 if (system_wide) 296 if (system_wide)
297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, 297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
298 group, group_fd); 298 group, group_fd);
299 if (target_pid == -1 && target_tid == -1) { 299 if (!target_pid && !target_tid && (!group || evsel == first)) {
300 attr->disabled = 1; 300 attr->disabled = 1;
301 attr->enable_on_exec = 1; 301 attr->enable_on_exec = 1;
302 } 302 }
@@ -446,7 +446,7 @@ static int run_perf_stat(int argc __used, const char **argv)
446 exit(-1); 446 exit(-1);
447 } 447 }
448 448
449 if (target_tid == -1 && target_pid == -1 && !system_wide) 449 if (!target_tid && !target_pid && !system_wide)
450 evsel_list->threads->map[0] = child_pid; 450 evsel_list->threads->map[0] = child_pid;
451 451
452 /* 452 /*
@@ -576,6 +576,8 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
576 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 576 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
577 fprintf(output, " # %8.3f CPUs utilized ", 577 fprintf(output, " # %8.3f CPUs utilized ",
578 avg / avg_stats(&walltime_nsecs_stats)); 578 avg / avg_stats(&walltime_nsecs_stats));
579 else
580 fprintf(output, " ");
579} 581}
580 582
581/* used for get_ratio_color() */ 583/* used for get_ratio_color() */
@@ -844,12 +846,18 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
844 846
845 fprintf(output, " # %8.3f GHz ", ratio); 847 fprintf(output, " # %8.3f GHz ", ratio);
846 } else if (runtime_nsecs_stats[cpu].n != 0) { 848 } else if (runtime_nsecs_stats[cpu].n != 0) {
849 char unit = 'M';
850
847 total = avg_stats(&runtime_nsecs_stats[cpu]); 851 total = avg_stats(&runtime_nsecs_stats[cpu]);
848 852
849 if (total) 853 if (total)
850 ratio = 1000.0 * avg / total; 854 ratio = 1000.0 * avg / total;
855 if (ratio < 0.001) {
856 ratio *= 1000;
857 unit = 'K';
858 }
851 859
852 fprintf(output, " # %8.3f M/sec ", ratio); 860 fprintf(output, " # %8.3f %c/sec ", ratio, unit);
853 } else { 861 } else {
854 fprintf(output, " "); 862 fprintf(output, " ");
855 } 863 }
@@ -960,14 +968,14 @@ static void print_stat(int argc, const char **argv)
960 if (!csv_output) { 968 if (!csv_output) {
961 fprintf(output, "\n"); 969 fprintf(output, "\n");
962 fprintf(output, " Performance counter stats for "); 970 fprintf(output, " Performance counter stats for ");
963 if(target_pid == -1 && target_tid == -1) { 971 if (!target_pid && !target_tid) {
964 fprintf(output, "\'%s", argv[0]); 972 fprintf(output, "\'%s", argv[0]);
965 for (i = 1; i < argc; i++) 973 for (i = 1; i < argc; i++)
966 fprintf(output, " %s", argv[i]); 974 fprintf(output, " %s", argv[i]);
967 } else if (target_pid != -1) 975 } else if (target_pid)
968 fprintf(output, "process id \'%d", target_pid); 976 fprintf(output, "process id \'%s", target_pid);
969 else 977 else
970 fprintf(output, "thread id \'%d", target_tid); 978 fprintf(output, "thread id \'%s", target_tid);
971 979
972 fprintf(output, "\'"); 980 fprintf(output, "\'");
973 if (run_count > 1) 981 if (run_count > 1)
@@ -1041,10 +1049,10 @@ static const struct option options[] = {
1041 "event filter", parse_filter), 1049 "event filter", parse_filter),
1042 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 1050 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
1043 "child tasks do not inherit counters"), 1051 "child tasks do not inherit counters"),
1044 OPT_INTEGER('p', "pid", &target_pid, 1052 OPT_STRING('p', "pid", &target_pid, "pid",
1045 "stat events on existing process id"), 1053 "stat events on existing process id"),
1046 OPT_INTEGER('t', "tid", &target_tid, 1054 OPT_STRING('t', "tid", &target_tid, "tid",
1047 "stat events on existing thread id"), 1055 "stat events on existing thread id"),
1048 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1056 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1049 "system-wide collection from all CPUs"), 1057 "system-wide collection from all CPUs"),
1050 OPT_BOOLEAN('g', "group", &group, 1058 OPT_BOOLEAN('g', "group", &group,
@@ -1182,7 +1190,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1182 } else if (big_num_opt == 0) /* User passed --no-big-num */ 1190 } else if (big_num_opt == 0) /* User passed --no-big-num */
1183 big_num = false; 1191 big_num = false;
1184 1192
1185 if (!argc && target_pid == -1 && target_tid == -1) 1193 if (!argc && !target_pid && !target_tid)
1186 usage_with_options(stat_usage, options); 1194 usage_with_options(stat_usage, options);
1187 if (run_count <= 0) 1195 if (run_count <= 0)
1188 usage_with_options(stat_usage, options); 1196 usage_with_options(stat_usage, options);
@@ -1198,10 +1206,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1198 if (add_default_attributes()) 1206 if (add_default_attributes())
1199 goto out; 1207 goto out;
1200 1208
1201 if (target_pid != -1) 1209 if (target_pid)
1202 target_tid = target_pid; 1210 target_tid = target_pid;
1203 1211
1204 evsel_list->threads = thread_map__new(target_pid, target_tid); 1212 evsel_list->threads = thread_map__new_str(target_pid,
1213 target_tid, UINT_MAX);
1205 if (evsel_list->threads == NULL) { 1214 if (evsel_list->threads == NULL) {
1206 pr_err("Problems finding threads of monitor\n"); 1215 pr_err("Problems finding threads of monitor\n");
1207 usage_with_options(stat_usage, options); 1216 usage_with_options(stat_usage, options);
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 3854e869dce1..1c5b9801ac61 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -13,8 +13,11 @@
13#include "util/parse-events.h" 13#include "util/parse-events.h"
14#include "util/symbol.h" 14#include "util/symbol.h"
15#include "util/thread_map.h" 15#include "util/thread_map.h"
16#include "util/pmu.h"
16#include "../../include/linux/hw_breakpoint.h" 17#include "../../include/linux/hw_breakpoint.h"
17 18
19#include <sys/mman.h>
20
18static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) 21static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
19{ 22{
20 bool *visited = symbol__priv(sym); 23 bool *visited = symbol__priv(sym);
@@ -276,7 +279,7 @@ static int test__open_syscall_event(void)
276 return -1; 279 return -1;
277 } 280 }
278 281
279 threads = thread_map__new(-1, getpid()); 282 threads = thread_map__new(-1, getpid(), UINT_MAX);
280 if (threads == NULL) { 283 if (threads == NULL) {
281 pr_debug("thread_map__new\n"); 284 pr_debug("thread_map__new\n");
282 return -1; 285 return -1;
@@ -342,7 +345,7 @@ static int test__open_syscall_event_on_all_cpus(void)
342 return -1; 345 return -1;
343 } 346 }
344 347
345 threads = thread_map__new(-1, getpid()); 348 threads = thread_map__new(-1, getpid(), UINT_MAX);
346 if (threads == NULL) { 349 if (threads == NULL) {
347 pr_debug("thread_map__new\n"); 350 pr_debug("thread_map__new\n");
348 return -1; 351 return -1;
@@ -490,7 +493,7 @@ static int test__basic_mmap(void)
490 expected_nr_events[i] = random() % 257; 493 expected_nr_events[i] = random() % 257;
491 } 494 }
492 495
493 threads = thread_map__new(-1, getpid()); 496 threads = thread_map__new(-1, getpid(), UINT_MAX);
494 if (threads == NULL) { 497 if (threads == NULL) {
495 pr_debug("thread_map__new\n"); 498 pr_debug("thread_map__new\n");
496 return -1; 499 return -1;
@@ -648,7 +651,7 @@ static int test__checkevent_raw(struct perf_evlist *evlist)
648 651
649 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 652 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
650 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); 653 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
651 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); 654 TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
652 return 0; 655 return 0;
653} 656}
654 657
@@ -675,6 +678,24 @@ static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
675 return 0; 678 return 0;
676} 679}
677 680
681static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
682{
683 struct perf_evsel *evsel = list_entry(evlist->entries.next,
684 struct perf_evsel, node);
685
686 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
687 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
688 TEST_ASSERT_VAL("wrong config",
689 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
690 TEST_ASSERT_VAL("wrong period",
691 100000 == evsel->attr.sample_period);
692 TEST_ASSERT_VAL("wrong config1",
693 0 == evsel->attr.config1);
694 TEST_ASSERT_VAL("wrong config2",
695 1 == evsel->attr.config2);
696 return 0;
697}
698
678static int test__checkevent_symbolic_alias(struct perf_evlist *evlist) 699static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
679{ 700{
680 struct perf_evsel *evsel = list_entry(evlist->entries.next, 701 struct perf_evsel *evsel = list_entry(evlist->entries.next,
@@ -856,6 +877,115 @@ static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
856 return test__checkevent_genhw(evlist); 877 return test__checkevent_genhw(evlist);
857} 878}
858 879
880static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
881{
882 struct perf_evsel *evsel = list_entry(evlist->entries.next,
883 struct perf_evsel, node);
884
885 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
886 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
887 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
888 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
889
890 return test__checkevent_breakpoint(evlist);
891}
892
893static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
894{
895 struct perf_evsel *evsel = list_entry(evlist->entries.next,
896 struct perf_evsel, node);
897
898 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
899 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
900 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
901 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
902
903 return test__checkevent_breakpoint_x(evlist);
904}
905
906static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
907{
908 struct perf_evsel *evsel = list_entry(evlist->entries.next,
909 struct perf_evsel, node);
910
911 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
912 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
913 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
914 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
915
916 return test__checkevent_breakpoint_r(evlist);
917}
918
919static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
920{
921 struct perf_evsel *evsel = list_entry(evlist->entries.next,
922 struct perf_evsel, node);
923
924 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
925 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
926 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
927 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
928
929 return test__checkevent_breakpoint_w(evlist);
930}
931
932static int test__checkevent_pmu(struct perf_evlist *evlist)
933{
934
935 struct perf_evsel *evsel = list_entry(evlist->entries.next,
936 struct perf_evsel, node);
937
938 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
939 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
940 TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config);
941 TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1);
942 TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2);
943 TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period);
944
945 return 0;
946}
947
948static int test__checkevent_list(struct perf_evlist *evlist)
949{
950 struct perf_evsel *evsel;
951
952 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
953
954 /* r1 */
955 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
956 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
957 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
958 TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
959 TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
960 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
961 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
962 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
963 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
964
965 /* syscalls:sys_enter_open:k */
966 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
967 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
968 TEST_ASSERT_VAL("wrong sample_type",
969 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
970 evsel->attr.sample_type);
971 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
972 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
973 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
974 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
975 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
976
977 /* 1:1:hp */
978 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
979 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
980 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
981 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
982 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
983 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
984 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
985
986 return 0;
987}
988
859static struct test__event_st { 989static struct test__event_st {
860 const char *name; 990 const char *name;
861 __u32 type; 991 __u32 type;
@@ -870,7 +1000,7 @@ static struct test__event_st {
870 .check = test__checkevent_tracepoint_multi, 1000 .check = test__checkevent_tracepoint_multi,
871 }, 1001 },
872 { 1002 {
873 .name = "r1", 1003 .name = "r1a",
874 .check = test__checkevent_raw, 1004 .check = test__checkevent_raw,
875 }, 1005 },
876 { 1006 {
@@ -882,6 +1012,10 @@ static struct test__event_st {
882 .check = test__checkevent_symbolic_name, 1012 .check = test__checkevent_symbolic_name,
883 }, 1013 },
884 { 1014 {
1015 .name = "cycles/period=100000,config2/",
1016 .check = test__checkevent_symbolic_name_config,
1017 },
1018 {
885 .name = "faults", 1019 .name = "faults",
886 .check = test__checkevent_symbolic_alias, 1020 .check = test__checkevent_symbolic_alias,
887 }, 1021 },
@@ -914,7 +1048,7 @@ static struct test__event_st {
914 .check = test__checkevent_tracepoint_multi_modifier, 1048 .check = test__checkevent_tracepoint_multi_modifier,
915 }, 1049 },
916 { 1050 {
917 .name = "r1:kp", 1051 .name = "r1a:kp",
918 .check = test__checkevent_raw_modifier, 1052 .check = test__checkevent_raw_modifier,
919 }, 1053 },
920 { 1054 {
@@ -933,6 +1067,30 @@ static struct test__event_st {
933 .name = "L1-dcache-load-miss:kp", 1067 .name = "L1-dcache-load-miss:kp",
934 .check = test__checkevent_genhw_modifier, 1068 .check = test__checkevent_genhw_modifier,
935 }, 1069 },
1070 {
1071 .name = "mem:0:u",
1072 .check = test__checkevent_breakpoint_modifier,
1073 },
1074 {
1075 .name = "mem:0:x:k",
1076 .check = test__checkevent_breakpoint_x_modifier,
1077 },
1078 {
1079 .name = "mem:0:r:hp",
1080 .check = test__checkevent_breakpoint_r_modifier,
1081 },
1082 {
1083 .name = "mem:0:w:up",
1084 .check = test__checkevent_breakpoint_w_modifier,
1085 },
1086 {
1087 .name = "cpu/config=10,config1,config2=3,period=1000/u",
1088 .check = test__checkevent_pmu,
1089 },
1090 {
1091 .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
1092 .check = test__checkevent_list,
1093 },
936}; 1094};
937 1095
938#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) 1096#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
@@ -958,10 +1116,9 @@ static int test__parse_events(void)
958 } 1116 }
959 1117
960 ret = e->check(evlist); 1118 ret = e->check(evlist);
1119 perf_evlist__delete(evlist);
961 if (ret) 1120 if (ret)
962 break; 1121 break;
963
964 perf_evlist__delete(evlist);
965 } 1122 }
966 1123
967 return ret; 1124 return ret;
@@ -1008,12 +1165,9 @@ realloc:
1008static int test__PERF_RECORD(void) 1165static int test__PERF_RECORD(void)
1009{ 1166{
1010 struct perf_record_opts opts = { 1167 struct perf_record_opts opts = {
1011 .target_pid = -1,
1012 .target_tid = -1,
1013 .no_delay = true, 1168 .no_delay = true,
1014 .freq = 10, 1169 .freq = 10,
1015 .mmap_pages = 256, 1170 .mmap_pages = 256,
1016 .sample_id_all_avail = true,
1017 }; 1171 };
1018 cpu_set_t *cpu_mask = NULL; 1172 cpu_set_t *cpu_mask = NULL;
1019 size_t cpu_mask_size = 0; 1173 size_t cpu_mask_size = 0;
@@ -1054,7 +1208,7 @@ static int test__PERF_RECORD(void)
1054 * we're monitoring, the one forked there. 1208 * we're monitoring, the one forked there.
1055 */ 1209 */
1056 err = perf_evlist__create_maps(evlist, opts.target_pid, 1210 err = perf_evlist__create_maps(evlist, opts.target_pid,
1057 opts.target_tid, opts.cpu_list); 1211 opts.target_tid, UINT_MAX, opts.cpu_list);
1058 if (err < 0) { 1212 if (err < 0) {
1059 pr_debug("Not enough memory to create thread/cpu maps\n"); 1213 pr_debug("Not enough memory to create thread/cpu maps\n");
1060 goto out_delete_evlist; 1214 goto out_delete_evlist;
@@ -1296,6 +1450,178 @@ out:
1296 return (err < 0 || errs > 0) ? -1 : 0; 1450 return (err < 0 || errs > 0) ? -1 : 0;
1297} 1451}
1298 1452
1453
1454#if defined(__x86_64__) || defined(__i386__)
1455
1456#define barrier() asm volatile("" ::: "memory")
1457
1458static u64 rdpmc(unsigned int counter)
1459{
1460 unsigned int low, high;
1461
1462 asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
1463
1464 return low | ((u64)high) << 32;
1465}
1466
1467static u64 rdtsc(void)
1468{
1469 unsigned int low, high;
1470
1471 asm volatile("rdtsc" : "=a" (low), "=d" (high));
1472
1473 return low | ((u64)high) << 32;
1474}
1475
1476static u64 mmap_read_self(void *addr)
1477{
1478 struct perf_event_mmap_page *pc = addr;
1479 u32 seq, idx, time_mult = 0, time_shift = 0;
1480 u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
1481
1482 do {
1483 seq = pc->lock;
1484 barrier();
1485
1486 enabled = pc->time_enabled;
1487 running = pc->time_running;
1488
1489 if (enabled != running) {
1490 cyc = rdtsc();
1491 time_mult = pc->time_mult;
1492 time_shift = pc->time_shift;
1493 time_offset = pc->time_offset;
1494 }
1495
1496 idx = pc->index;
1497 count = pc->offset;
1498 if (idx)
1499 count += rdpmc(idx - 1);
1500
1501 barrier();
1502 } while (pc->lock != seq);
1503
1504 if (enabled != running) {
1505 u64 quot, rem;
1506
1507 quot = (cyc >> time_shift);
1508 rem = cyc & ((1 << time_shift) - 1);
1509 delta = time_offset + quot * time_mult +
1510 ((rem * time_mult) >> time_shift);
1511
1512 enabled += delta;
1513 if (idx)
1514 running += delta;
1515
1516 quot = count / running;
1517 rem = count % running;
1518 count = quot * enabled + (rem * enabled) / running;
1519 }
1520
1521 return count;
1522}
1523
1524/*
1525 * If the RDPMC instruction faults then signal this back to the test parent task:
1526 */
1527static void segfault_handler(int sig __used, siginfo_t *info __used, void *uc __used)
1528{
1529 exit(-1);
1530}
1531
1532static int __test__rdpmc(void)
1533{
1534 long page_size = sysconf(_SC_PAGE_SIZE);
1535 volatile int tmp = 0;
1536 u64 i, loops = 1000;
1537 int n;
1538 int fd;
1539 void *addr;
1540 struct perf_event_attr attr = {
1541 .type = PERF_TYPE_HARDWARE,
1542 .config = PERF_COUNT_HW_INSTRUCTIONS,
1543 .exclude_kernel = 1,
1544 };
1545 u64 delta_sum = 0;
1546 struct sigaction sa;
1547
1548 sigfillset(&sa.sa_mask);
1549 sa.sa_sigaction = segfault_handler;
1550 sigaction(SIGSEGV, &sa, NULL);
1551
1552 fprintf(stderr, "\n\n");
1553
1554 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
1555 if (fd < 0) {
1556 die("Error: sys_perf_event_open() syscall returned "
1557 "with %d (%s)\n", fd, strerror(errno));
1558 }
1559
1560 addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
1561 if (addr == (void *)(-1)) {
1562 die("Error: mmap() syscall returned "
1563 "with (%s)\n", strerror(errno));
1564 }
1565
1566 for (n = 0; n < 6; n++) {
1567 u64 stamp, now, delta;
1568
1569 stamp = mmap_read_self(addr);
1570
1571 for (i = 0; i < loops; i++)
1572 tmp++;
1573
1574 now = mmap_read_self(addr);
1575 loops *= 10;
1576
1577 delta = now - stamp;
1578 fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta);
1579
1580 delta_sum += delta;
1581 }
1582
1583 munmap(addr, page_size);
1584 close(fd);
1585
1586 fprintf(stderr, " ");
1587
1588 if (!delta_sum)
1589 return -1;
1590
1591 return 0;
1592}
1593
1594static int test__rdpmc(void)
1595{
1596 int status = 0;
1597 int wret = 0;
1598 int ret;
1599 int pid;
1600
1601 pid = fork();
1602 if (pid < 0)
1603 return -1;
1604
1605 if (!pid) {
1606 ret = __test__rdpmc();
1607
1608 exit(ret);
1609 }
1610
1611 wret = waitpid(pid, &status, 0);
1612 if (wret < 0 || status)
1613 return -1;
1614
1615 return 0;
1616}
1617
1618#endif
1619
1620static int test__perf_pmu(void)
1621{
1622 return perf_pmu__test();
1623}
1624
1299static struct test { 1625static struct test {
1300 const char *desc; 1626 const char *desc;
1301 int (*func)(void); 1627 int (*func)(void);
@@ -1320,11 +1646,21 @@ static struct test {
1320 .desc = "parse events tests", 1646 .desc = "parse events tests",
1321 .func = test__parse_events, 1647 .func = test__parse_events,
1322 }, 1648 },
1649#if defined(__x86_64__) || defined(__i386__)
1650 {
1651 .desc = "x86 rdpmc test",
1652 .func = test__rdpmc,
1653 },
1654#endif
1323 { 1655 {
1324 .desc = "Validate PERF_RECORD_* events & perf_sample fields", 1656 .desc = "Validate PERF_RECORD_* events & perf_sample fields",
1325 .func = test__PERF_RECORD, 1657 .func = test__PERF_RECORD,
1326 }, 1658 },
1327 { 1659 {
1660 .desc = "Test perf pmu format parsing",
1661 .func = test__perf_pmu,
1662 },
1663 {
1328 .func = NULL, 1664 .func = NULL,
1329 }, 1665 },
1330}; 1666};
@@ -1412,7 +1748,5 @@ int cmd_test(int argc, const char **argv, const char *prefix __used)
1412 if (symbol__init() < 0) 1748 if (symbol__init() < 0)
1413 return -1; 1749 return -1;
1414 1750
1415 setup_pager();
1416
1417 return __cmd_test(argc, argv); 1751 return __cmd_test(argc, argv);
1418} 1752}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index dd162aa24baa..8ef59f8262bb 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -42,6 +42,7 @@
42#include "util/debug.h" 42#include "util/debug.h"
43 43
44#include <assert.h> 44#include <assert.h>
45#include <elf.h>
45#include <fcntl.h> 46#include <fcntl.h>
46 47
47#include <stdio.h> 48#include <stdio.h>
@@ -59,12 +60,12 @@
59#include <sys/prctl.h> 60#include <sys/prctl.h>
60#include <sys/wait.h> 61#include <sys/wait.h>
61#include <sys/uio.h> 62#include <sys/uio.h>
63#include <sys/utsname.h>
62#include <sys/mman.h> 64#include <sys/mman.h>
63 65
64#include <linux/unistd.h> 66#include <linux/unistd.h>
65#include <linux/types.h> 67#include <linux/types.h>
66 68
67
68void get_term_dimensions(struct winsize *ws) 69void get_term_dimensions(struct winsize *ws)
69{ 70{
70 char *s = getenv("LINES"); 71 char *s = getenv("LINES");
@@ -163,12 +164,40 @@ static void __zero_source_counters(struct hist_entry *he)
163 symbol__annotate_zero_histograms(sym); 164 symbol__annotate_zero_histograms(sym);
164} 165}
165 166
167static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip)
168{
169 struct utsname uts;
170 int err = uname(&uts);
171
172 ui__warning("Out of bounds address found:\n\n"
173 "Addr: %" PRIx64 "\n"
174 "DSO: %s %c\n"
175 "Map: %" PRIx64 "-%" PRIx64 "\n"
176 "Symbol: %" PRIx64 "-%" PRIx64 " %c %s\n"
177 "Arch: %s\n"
178 "Kernel: %s\n"
179 "Tools: %s\n\n"
180 "Not all samples will be on the annotation output.\n\n"
181 "Please report to linux-kernel@vger.kernel.org\n",
182 ip, map->dso->long_name, dso__symtab_origin(map->dso),
183 map->start, map->end, sym->start, sym->end,
184 sym->binding == STB_GLOBAL ? 'g' :
185 sym->binding == STB_LOCAL ? 'l' : 'w', sym->name,
186 err ? "[unknown]" : uts.machine,
187 err ? "[unknown]" : uts.release, perf_version_string);
188 if (use_browser <= 0)
189 sleep(5);
190
191 map->erange_warned = true;
192}
193
166static void perf_top__record_precise_ip(struct perf_top *top, 194static void perf_top__record_precise_ip(struct perf_top *top,
167 struct hist_entry *he, 195 struct hist_entry *he,
168 int counter, u64 ip) 196 int counter, u64 ip)
169{ 197{
170 struct annotation *notes; 198 struct annotation *notes;
171 struct symbol *sym; 199 struct symbol *sym;
200 int err;
172 201
173 if (he == NULL || he->ms.sym == NULL || 202 if (he == NULL || he->ms.sym == NULL ||
174 ((top->sym_filter_entry == NULL || 203 ((top->sym_filter_entry == NULL ||
@@ -190,9 +219,12 @@ static void perf_top__record_precise_ip(struct perf_top *top,
190 } 219 }
191 220
192 ip = he->ms.map->map_ip(he->ms.map, ip); 221 ip = he->ms.map->map_ip(he->ms.map, ip);
193 symbol__inc_addr_samples(sym, he->ms.map, counter, ip); 222 err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip);
194 223
195 pthread_mutex_unlock(&notes->lock); 224 pthread_mutex_unlock(&notes->lock);
225
226 if (err == -ERANGE && !he->ms.map->erange_warned)
227 ui__warn_map_erange(he->ms.map, sym, ip);
196} 228}
197 229
198static void perf_top__show_details(struct perf_top *top) 230static void perf_top__show_details(struct perf_top *top)
@@ -544,10 +576,20 @@ static void perf_top__sort_new_samples(void *arg)
544 576
545static void *display_thread_tui(void *arg) 577static void *display_thread_tui(void *arg)
546{ 578{
579 struct perf_evsel *pos;
547 struct perf_top *top = arg; 580 struct perf_top *top = arg;
548 const char *help = "For a higher level overview, try: perf top --sort comm,dso"; 581 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
549 582
550 perf_top__sort_new_samples(top); 583 perf_top__sort_new_samples(top);
584
585 /*
586 * Initialize the uid_filter_str, in the future the TUI will allow
587 * Zooming in/out UIDs. For now juse use whatever the user passed
588 * via --uid.
589 */
590 list_for_each_entry(pos, &top->evlist->entries, node)
591 pos->hists.uid_filter_str = top->uid_str;
592
551 perf_evlist__tui_browse_hists(top->evlist, help, 593 perf_evlist__tui_browse_hists(top->evlist, help,
552 perf_top__sort_new_samples, 594 perf_top__sort_new_samples,
553 top, top->delay_secs); 595 top, top->delay_secs);
@@ -606,6 +648,7 @@ process_hotkey:
606 648
607/* Tag samples to be skipped. */ 649/* Tag samples to be skipped. */
608static const char *skip_symbols[] = { 650static const char *skip_symbols[] = {
651 "intel_idle",
609 "default_idle", 652 "default_idle",
610 "native_safe_halt", 653 "native_safe_halt",
611 "cpu_idle", 654 "cpu_idle",
@@ -668,6 +711,12 @@ static void perf_event__process_sample(struct perf_tool *tool,
668 return; 711 return;
669 } 712 }
670 713
714 if (!machine) {
715 pr_err("%u unprocessable samples recorded.",
716 top->session->hists.stats.nr_unprocessable_samples++);
717 return;
718 }
719
671 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 720 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
672 top->exact_samples++; 721 top->exact_samples++;
673 722
@@ -857,8 +906,11 @@ static void perf_top__start_counters(struct perf_top *top)
857 attr->mmap = 1; 906 attr->mmap = 1;
858 attr->comm = 1; 907 attr->comm = 1;
859 attr->inherit = top->inherit; 908 attr->inherit = top->inherit;
909fallback_missing_features:
910 if (top->exclude_guest_missing)
911 attr->exclude_guest = attr->exclude_host = 0;
860retry_sample_id: 912retry_sample_id:
861 attr->sample_id_all = top->sample_id_all_avail ? 1 : 0; 913 attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
862try_again: 914try_again:
863 if (perf_evsel__open(counter, top->evlist->cpus, 915 if (perf_evsel__open(counter, top->evlist->cpus,
864 top->evlist->threads, top->group, 916 top->evlist->threads, top->group,
@@ -868,12 +920,20 @@ try_again:
868 if (err == EPERM || err == EACCES) { 920 if (err == EPERM || err == EACCES) {
869 ui__error_paranoid(); 921 ui__error_paranoid();
870 goto out_err; 922 goto out_err;
871 } else if (err == EINVAL && top->sample_id_all_avail) { 923 } else if (err == EINVAL) {
872 /* 924 if (!top->exclude_guest_missing &&
873 * Old kernel, no attr->sample_id_type_all field 925 (attr->exclude_guest || attr->exclude_host)) {
874 */ 926 pr_debug("Old kernel, cannot exclude "
875 top->sample_id_all_avail = false; 927 "guest or host samples.\n");
876 goto retry_sample_id; 928 top->exclude_guest_missing = true;
929 goto fallback_missing_features;
930 } else if (!top->sample_id_all_missing) {
931 /*
932 * Old kernel, no attr->sample_id_type_all field
933 */
934 top->sample_id_all_missing = true;
935 goto retry_sample_id;
936 }
877 } 937 }
878 /* 938 /*
879 * If it's cycles then fall back to hrtimer 939 * If it's cycles then fall back to hrtimer
@@ -956,7 +1016,7 @@ static int __cmd_top(struct perf_top *top)
956 if (ret) 1016 if (ret)
957 goto out_delete; 1017 goto out_delete;
958 1018
959 if (top->target_tid != -1) 1019 if (top->target_tid || top->uid != UINT_MAX)
960 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 1020 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
961 perf_event__process, 1021 perf_event__process,
962 &top->session->host_machine); 1022 &top->session->host_machine);
@@ -1094,10 +1154,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1094 struct perf_top top = { 1154 struct perf_top top = {
1095 .count_filter = 5, 1155 .count_filter = 5,
1096 .delay_secs = 2, 1156 .delay_secs = 2,
1097 .target_pid = -1, 1157 .uid = UINT_MAX,
1098 .target_tid = -1,
1099 .freq = 1000, /* 1 KHz */ 1158 .freq = 1000, /* 1 KHz */
1100 .sample_id_all_avail = true,
1101 .mmap_pages = 128, 1159 .mmap_pages = 128,
1102 .sym_pcnt_filter = 5, 1160 .sym_pcnt_filter = 5,
1103 }; 1161 };
@@ -1108,9 +1166,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1108 parse_events_option), 1166 parse_events_option),
1109 OPT_INTEGER('c', "count", &top.default_interval, 1167 OPT_INTEGER('c', "count", &top.default_interval,
1110 "event period to sample"), 1168 "event period to sample"),
1111 OPT_INTEGER('p', "pid", &top.target_pid, 1169 OPT_STRING('p', "pid", &top.target_pid, "pid",
1112 "profile events on existing process id"), 1170 "profile events on existing process id"),
1113 OPT_INTEGER('t', "tid", &top.target_tid, 1171 OPT_STRING('t', "tid", &top.target_tid, "tid",
1114 "profile events on existing thread id"), 1172 "profile events on existing thread id"),
1115 OPT_BOOLEAN('a', "all-cpus", &top.system_wide, 1173 OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
1116 "system-wide collection from all CPUs"), 1174 "system-wide collection from all CPUs"),
@@ -1169,6 +1227,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1169 "Display raw encoding of assembly instructions (default)"), 1227 "Display raw encoding of assembly instructions (default)"),
1170 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1228 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1171 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1229 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1230 OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
1172 OPT_END() 1231 OPT_END()
1173 }; 1232 };
1174 1233
@@ -1194,18 +1253,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1194 1253
1195 setup_browser(false); 1254 setup_browser(false);
1196 1255
1256 top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
1257 if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
1258 goto out_delete_evlist;
1259
1197 /* CPU and PID are mutually exclusive */ 1260 /* CPU and PID are mutually exclusive */
1198 if (top.target_tid > 0 && top.cpu_list) { 1261 if (top.target_tid && top.cpu_list) {
1199 printf("WARNING: PID switch overriding CPU\n"); 1262 printf("WARNING: PID switch overriding CPU\n");
1200 sleep(1); 1263 sleep(1);
1201 top.cpu_list = NULL; 1264 top.cpu_list = NULL;
1202 } 1265 }
1203 1266
1204 if (top.target_pid != -1) 1267 if (top.target_pid)
1205 top.target_tid = top.target_pid; 1268 top.target_tid = top.target_pid;
1206 1269
1207 if (perf_evlist__create_maps(top.evlist, top.target_pid, 1270 if (perf_evlist__create_maps(top.evlist, top.target_pid,
1208 top.target_tid, top.cpu_list) < 0) 1271 top.target_tid, top.uid, top.cpu_list) < 0)
1209 usage_with_options(top_usage, options); 1272 usage_with_options(top_usage, options);
1210 1273
1211 if (!top.evlist->nr_entries && 1274 if (!top.evlist->nr_entries &&
@@ -1269,6 +1332,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1269 1332
1270 status = __cmd_top(&top); 1333 status = __cmd_top(&top);
1271 1334
1335out_delete_evlist:
1272 perf_evlist__delete(top.evlist); 1336 perf_evlist__delete(top.evlist);
1273 1337
1274 return status; 1338 return status;
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index 6170fd2531b5..d9084e03ce56 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -65,6 +65,21 @@ int main(void)
65endef 65endef
66endif 66endif
67 67
68ifndef NO_GTK2
69define SOURCE_GTK2
70#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
71#include <gtk/gtk.h>
72#pragma GCC diagnostic error \"-Wstrict-prototypes\"
73
74int main(int argc, char *argv[])
75{
76 gtk_init(&argc, &argv);
77
78 return 0;
79}
80endef
81endif
82
68ifndef NO_LIBPERL 83ifndef NO_LIBPERL
69define SOURCE_PERL_EMBED 84define SOURCE_PERL_EMBED
70#include <EXTERN.h> 85#include <EXTERN.h>
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
index 677e59d62a8d..95b6f8b6177a 100644
--- a/tools/perf/perf-archive.sh
+++ b/tools/perf/perf-archive.sh
@@ -29,13 +29,14 @@ if [ ! -s $BUILDIDS ] ; then
29fi 29fi
30 30
31MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX) 31MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
32PERF_BUILDID_LINKDIR=$(readlink -f $PERF_BUILDID_DIR)/
32 33
33cut -d ' ' -f 1 $BUILDIDS | \ 34cut -d ' ' -f 1 $BUILDIDS | \
34while read build_id ; do 35while read build_id ; do
35 linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2} 36 linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2}
36 filename=$(readlink -f $linkname) 37 filename=$(readlink -f $linkname)
37 echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST 38 echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST
38 echo ${filename#$PERF_BUILDID_DIR} >> $MANIFEST 39 echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST
39done 40done
40 41
41tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST 42tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 64f8bee31ced..89e3355ab173 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -10,6 +10,9 @@ void get_term_dimensions(struct winsize *ws);
10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
11#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 11#define cpu_relax() asm volatile("rep; nop" ::: "memory");
12#define CPUINFO_PROC "model name" 12#define CPUINFO_PROC "model name"
13#ifndef __NR_perf_event_open
14# define __NR_perf_event_open 336
15#endif
13#endif 16#endif
14 17
15#if defined(__x86_64__) 18#if defined(__x86_64__)
@@ -17,6 +20,9 @@ void get_term_dimensions(struct winsize *ws);
17#define rmb() asm volatile("lfence" ::: "memory") 20#define rmb() asm volatile("lfence" ::: "memory")
18#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 21#define cpu_relax() asm volatile("rep; nop" ::: "memory");
19#define CPUINFO_PROC "model name" 22#define CPUINFO_PROC "model name"
23#ifndef __NR_perf_event_open
24# define __NR_perf_event_open 298
25#endif
20#endif 26#endif
21 27
22#ifdef __powerpc__ 28#ifdef __powerpc__
@@ -167,7 +173,6 @@ sys_perf_event_open(struct perf_event_attr *attr,
167 pid_t pid, int cpu, int group_fd, 173 pid_t pid, int cpu, int group_fd,
168 unsigned long flags) 174 unsigned long flags)
169{ 175{
170 attr->size = sizeof(*attr);
171 return syscall(__NR_perf_event_open, attr, pid, cpu, 176 return syscall(__NR_perf_event_open, attr, pid, cpu,
172 group_fd, flags); 177 group_fd, flags);
173} 178}
@@ -180,14 +185,32 @@ struct ip_callchain {
180 u64 ips[0]; 185 u64 ips[0];
181}; 186};
182 187
188struct branch_flags {
189 u64 mispred:1;
190 u64 predicted:1;
191 u64 reserved:62;
192};
193
194struct branch_entry {
195 u64 from;
196 u64 to;
197 struct branch_flags flags;
198};
199
200struct branch_stack {
201 u64 nr;
202 struct branch_entry entries[0];
203};
204
183extern bool perf_host, perf_guest; 205extern bool perf_host, perf_guest;
184extern const char perf_version_string[]; 206extern const char perf_version_string[];
185 207
186void pthread__unblock_sigwinch(void); 208void pthread__unblock_sigwinch(void);
187 209
188struct perf_record_opts { 210struct perf_record_opts {
189 pid_t target_pid; 211 const char *target_pid;
190 pid_t target_tid; 212 const char *target_tid;
213 uid_t uid;
191 bool call_graph; 214 bool call_graph;
192 bool group; 215 bool group;
193 bool inherit_stat; 216 bool inherit_stat;
@@ -198,12 +221,14 @@ struct perf_record_opts {
198 bool raw_samples; 221 bool raw_samples;
199 bool sample_address; 222 bool sample_address;
200 bool sample_time; 223 bool sample_time;
201 bool sample_id_all_avail; 224 bool sample_id_all_missing;
225 bool exclude_guest_missing;
202 bool system_wide; 226 bool system_wide;
203 bool period; 227 bool period;
204 unsigned int freq; 228 unsigned int freq;
205 unsigned int mmap_pages; 229 unsigned int mmap_pages;
206 unsigned int user_freq; 230 unsigned int user_freq;
231 int branch_stack;
207 u64 default_interval; 232 u64 default_interval;
208 u64 user_interval; 233 u64 user_interval;
209 const char *cpu_list; 234 const char *cpu_list;
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
index df638c438a9f..b11cca584238 100755
--- a/tools/perf/python/twatch.py
+++ b/tools/perf/python/twatch.py
@@ -19,7 +19,7 @@ def main():
19 cpus = perf.cpu_map() 19 cpus = perf.cpu_map()
20 threads = perf.thread_map() 20 threads = perf.thread_map()
21 evsel = perf.evsel(task = 1, comm = 1, mmap = 0, 21 evsel = perf.evsel(task = 1, comm = 1, mmap = 0,
22 wakeup_events = 1, sample_period = 1, 22 wakeup_events = 1, watermark = 1,
23 sample_id_all = 1, 23 sample_id_all = 1,
24 sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID) 24 sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID)
25 evsel.open(cpus = cpus, threads = threads); 25 evsel.open(cpus = cpus, threads = threads);
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 011ed2676604..08c6d138a655 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -28,8 +28,8 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
28int symbol__alloc_hist(struct symbol *sym) 28int symbol__alloc_hist(struct symbol *sym)
29{ 29{
30 struct annotation *notes = symbol__annotation(sym); 30 struct annotation *notes = symbol__annotation(sym);
31 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + 31 const size_t size = sym->end - sym->start + 1;
32 (sym->end - sym->start) * sizeof(u64)); 32 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
33 33
34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
35 if (notes->src == NULL) 35 if (notes->src == NULL)
@@ -64,8 +64,8 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
64 64
65 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 65 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
66 66
67 if (addr >= sym->end) 67 if (addr < sym->start || addr > sym->end)
68 return 0; 68 return -ERANGE;
69 69
70 offset = addr - sym->start; 70 offset = addr - sym->start;
71 h = annotation__histogram(notes, evidx); 71 h = annotation__histogram(notes, evidx);
@@ -315,7 +315,7 @@ fallback:
315 "Please use:\n\n" 315 "Please use:\n\n"
316 " perf buildid-cache -av vmlinux\n\n" 316 " perf buildid-cache -av vmlinux\n\n"
317 "or:\n\n" 317 "or:\n\n"
318 " --vmlinux vmlinux", 318 " --vmlinux vmlinux\n",
319 sym->name, build_id_msg ?: ""); 319 sym->name, build_id_msg ?: "");
320 goto out_free_filename; 320 goto out_free_filename;
321 } 321 }
@@ -408,7 +408,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
408 if (!notes->src->lines) 408 if (!notes->src->lines)
409 return -1; 409 return -1;
410 410
411 start = map->unmap_ip(map, sym->start); 411 start = map__rip_2objdump(map, sym->start);
412 412
413 for (i = 0; i < len; i++) { 413 for (i = 0; i < len; i++) {
414 char *path = NULL; 414 char *path = NULL;
@@ -561,16 +561,12 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
561{ 561{
562 struct annotation *notes = symbol__annotation(sym); 562 struct annotation *notes = symbol__annotation(sym);
563 struct sym_hist *h = annotation__histogram(notes, evidx); 563 struct sym_hist *h = annotation__histogram(notes, evidx);
564 struct objdump_line *pos; 564 int len = sym->end - sym->start, offset;
565 int len = sym->end - sym->start;
566 565
567 h->sum = 0; 566 h->sum = 0;
568 567 for (offset = 0; offset < len; ++offset) {
569 list_for_each_entry(pos, &notes->src->source, node) { 568 h->addr[offset] = h->addr[offset] * 7 / 8;
570 if (pos->offset != -1 && pos->offset < len) { 569 h->sum += h->addr[offset];
571 h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8;
572 h->sum += h->addr[pos->offset];
573 }
574 } 570 }
575} 571}
576 572
diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
index 5e230acae1e9..0a1adc1111fd 100644
--- a/tools/perf/util/bitmap.c
+++ b/tools/perf/util/bitmap.c
@@ -19,3 +19,13 @@ int __bitmap_weight(const unsigned long *bitmap, int bits)
19 19
20 return w; 20 return w;
21} 21}
22
23void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
24 const unsigned long *bitmap2, int bits)
25{
26 int k;
27 int nr = BITS_TO_LONGS(bits);
28
29 for (k = 0; k < nr; k++)
30 dst[k] = bitmap1[k] | bitmap2[k];
31}
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index fc5e5a09d5b9..8dd224df3e54 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -45,6 +45,18 @@ void setup_browser(bool fallback_to_pager);
45void exit_browser(bool wait_for_ok); 45void exit_browser(bool wait_for_ok);
46#endif 46#endif
47 47
48#ifdef NO_GTK2_SUPPORT
49static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager)
50{
51 if (fallback_to_pager)
52 setup_pager();
53}
54static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {}
55#else
56void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager);
57void perf_gtk_exit_browser(bool wait_for_ok);
58#endif
59
48char *alias_lookup(const char *alias); 60char *alias_lookup(const char *alias);
49int split_cmdline(char *cmdline, const char ***argv); 61int split_cmdline(char *cmdline, const char ***argv);
50 62
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 521c38a79190..11e46da17bbb 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -1,3 +1,4 @@
1#include <linux/kernel.h>
1#include "cache.h" 2#include "cache.h"
2#include "color.h" 3#include "color.h"
3 4
@@ -182,12 +183,12 @@ static int __color_vsnprintf(char *bf, size_t size, const char *color,
182 } 183 }
183 184
184 if (perf_use_color_default && *color) 185 if (perf_use_color_default && *color)
185 r += snprintf(bf, size, "%s", color); 186 r += scnprintf(bf, size, "%s", color);
186 r += vsnprintf(bf + r, size - r, fmt, args); 187 r += vscnprintf(bf + r, size - r, fmt, args);
187 if (perf_use_color_default && *color) 188 if (perf_use_color_default && *color)
188 r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET); 189 r += scnprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
189 if (trail) 190 if (trail)
190 r += snprintf(bf + r, size - r, "%s", trail); 191 r += scnprintf(bf + r, size - r, "%s", trail);
191 return r; 192 return r;
192} 193}
193 194
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 6893eec693ab..adc72f09914d 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -166,6 +166,17 @@ out:
166 return cpus; 166 return cpus;
167} 167}
168 168
169size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
170{
171 int i;
172 size_t printed = fprintf(fp, "%d cpu%s: ",
173 map->nr, map->nr > 1 ? "s" : "");
174 for (i = 0; i < map->nr; ++i)
175 printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
176
177 return printed + fprintf(fp, "\n");
178}
179
169struct cpu_map *cpu_map__dummy_new(void) 180struct cpu_map *cpu_map__dummy_new(void)
170{ 181{
171 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int)); 182 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 072c0a374794..c41518573c6a 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -1,6 +1,8 @@
1#ifndef __PERF_CPUMAP_H 1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H 2#define __PERF_CPUMAP_H
3 3
4#include <stdio.h>
5
4struct cpu_map { 6struct cpu_map {
5 int nr; 7 int nr;
6 int map[]; 8 int map[];
@@ -10,4 +12,6 @@ struct cpu_map *cpu_map__new(const char *cpu_list);
10struct cpu_map *cpu_map__dummy_new(void); 12struct cpu_map *cpu_map__dummy_new(void);
11void cpu_map__delete(struct cpu_map *map); 13void cpu_map__delete(struct cpu_map *map);
12 14
15size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
16
13#endif /* __PERF_CPUMAP_H */ 17#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index 35073621e5de..aada3ac5e891 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * No surprises, and works with signed and unsigned chars. 4 * No surprises, and works with signed and unsigned chars.
5 */ 5 */
6#include "cache.h" 6#include "util.h"
7 7
8enum { 8enum {
9 S = GIT_SPACE, 9 S = GIT_SPACE,
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index ffc35e748e89..dd8b19319c03 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -15,32 +15,6 @@ static const char *debugfs_known_mountpoints[] = {
15 0, 15 0,
16}; 16};
17 17
18/* use this to force a umount */
19void debugfs_force_cleanup(void)
20{
21 debugfs_find_mountpoint();
22 debugfs_premounted = 0;
23 debugfs_umount();
24}
25
26/* construct a full path to a debugfs element */
27int debugfs_make_path(const char *element, char *buffer, int size)
28{
29 int len;
30
31 if (strlen(debugfs_mountpoint) == 0) {
32 buffer[0] = '\0';
33 return -1;
34 }
35
36 len = strlen(debugfs_mountpoint) + strlen(element) + 1;
37 if (len >= size)
38 return len+1;
39
40 snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
41 return 0;
42}
43
44static int debugfs_found; 18static int debugfs_found;
45 19
46/* find the path to the mounted debugfs */ 20/* find the path to the mounted debugfs */
@@ -97,17 +71,6 @@ int debugfs_valid_mountpoint(const char *debugfs)
97 return 0; 71 return 0;
98} 72}
99 73
100
101int debugfs_valid_entry(const char *path)
102{
103 struct stat st;
104
105 if (stat(path, &st))
106 return -errno;
107
108 return 0;
109}
110
111static void debugfs_set_tracing_events_path(const char *mountpoint) 74static void debugfs_set_tracing_events_path(const char *mountpoint)
112{ 75{
113 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", 76 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
@@ -149,107 +112,3 @@ void debugfs_set_path(const char *mountpoint)
149 snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); 112 snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
150 debugfs_set_tracing_events_path(mountpoint); 113 debugfs_set_tracing_events_path(mountpoint);
151} 114}
152
153/* umount the debugfs */
154
155int debugfs_umount(void)
156{
157 char umountcmd[128];
158 int ret;
159
160 /* if it was already mounted, leave it */
161 if (debugfs_premounted)
162 return 0;
163
164 /* make sure it's a valid mount point */
165 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
166 if (ret)
167 return ret;
168
169 snprintf(umountcmd, sizeof(umountcmd),
170 "/bin/umount %s", debugfs_mountpoint);
171 return system(umountcmd);
172}
173
174int debugfs_write(const char *entry, const char *value)
175{
176 char path[PATH_MAX + 1];
177 int ret, count;
178 int fd;
179
180 /* construct the path */
181 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
182
183 /* verify that it exists */
184 ret = debugfs_valid_entry(path);
185 if (ret)
186 return ret;
187
188 /* get how many chars we're going to write */
189 count = strlen(value);
190
191 /* open the debugfs entry */
192 fd = open(path, O_RDWR);
193 if (fd < 0)
194 return -errno;
195
196 while (count > 0) {
197 /* write it */
198 ret = write(fd, value, count);
199 if (ret <= 0) {
200 if (ret == EAGAIN)
201 continue;
202 close(fd);
203 return -errno;
204 }
205 count -= ret;
206 }
207
208 /* close it */
209 close(fd);
210
211 /* return success */
212 return 0;
213}
214
215/*
216 * read a debugfs entry
217 * returns the number of chars read or a negative errno
218 */
219int debugfs_read(const char *entry, char *buffer, size_t size)
220{
221 char path[PATH_MAX + 1];
222 int ret;
223 int fd;
224
225 /* construct the path */
226 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
227
228 /* verify that it exists */
229 ret = debugfs_valid_entry(path);
230 if (ret)
231 return ret;
232
233 /* open the debugfs entry */
234 fd = open(path, O_RDONLY);
235 if (fd < 0)
236 return -errno;
237
238 do {
239 /* read it */
240 ret = read(fd, buffer, size);
241 if (ret == 0) {
242 close(fd);
243 return EOF;
244 }
245 } while (ret < 0 && errno == EAGAIN);
246
247 /* close it */
248 close(fd);
249
250 /* make *sure* there's a null character at the end */
251 buffer[ret] = '\0';
252
253 /* return the number of chars read */
254 return ret;
255}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 4a878f735eb0..68f3e87ec57f 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -3,14 +3,8 @@
3 3
4const char *debugfs_find_mountpoint(void); 4const char *debugfs_find_mountpoint(void);
5int debugfs_valid_mountpoint(const char *debugfs); 5int debugfs_valid_mountpoint(const char *debugfs);
6int debugfs_valid_entry(const char *path);
7char *debugfs_mount(const char *mountpoint); 6char *debugfs_mount(const char *mountpoint);
8int debugfs_umount(void);
9void debugfs_set_path(const char *mountpoint); 7void debugfs_set_path(const char *mountpoint);
10int debugfs_write(const char *entry, const char *value);
11int debugfs_read(const char *entry, char *buffer, size_t size);
12void debugfs_force_cleanup(void);
13int debugfs_make_path(const char *element, char *buffer, int size);
14 8
15extern char debugfs_mountpoint[]; 9extern char debugfs_mountpoint[];
16extern char tracing_events_path[]; 10extern char tracing_events_path[];
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index cbdeaad9c5e5..1b197280c621 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -81,6 +81,7 @@ struct perf_sample {
81 u32 raw_size; 81 u32 raw_size;
82 void *raw_data; 82 void *raw_data;
83 struct ip_callchain *callchain; 83 struct ip_callchain *callchain;
84 struct branch_stack *branch_stack;
84}; 85};
85 86
86#define BUILD_ID_SIZE 20 87#define BUILD_ID_SIZE 20
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ea32a061f1c8..1986d8051bd1 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -51,13 +51,15 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
51void perf_evlist__config_attrs(struct perf_evlist *evlist, 51void perf_evlist__config_attrs(struct perf_evlist *evlist,
52 struct perf_record_opts *opts) 52 struct perf_record_opts *opts)
53{ 53{
54 struct perf_evsel *evsel; 54 struct perf_evsel *evsel, *first;
55 55
56 if (evlist->cpus->map[0] < 0) 56 if (evlist->cpus->map[0] < 0)
57 opts->no_inherit = true; 57 opts->no_inherit = true;
58 58
59 first = list_entry(evlist->entries.next, struct perf_evsel, node);
60
59 list_for_each_entry(evsel, &evlist->entries, node) { 61 list_for_each_entry(evsel, &evlist->entries, node) {
60 perf_evsel__config(evsel, opts); 62 perf_evsel__config(evsel, opts, first);
61 63
62 if (evlist->nr_entries > 1) 64 if (evlist->nr_entries > 1)
63 evsel->attr.sample_type |= PERF_SAMPLE_ID; 65 evsel->attr.sample_type |= PERF_SAMPLE_ID;
@@ -97,9 +99,9 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
97 ++evlist->nr_entries; 99 ++evlist->nr_entries;
98} 100}
99 101
100static void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 102void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
101 struct list_head *list, 103 struct list_head *list,
102 int nr_entries) 104 int nr_entries)
103{ 105{
104 list_splice_tail(list, &evlist->entries); 106 list_splice_tail(list, &evlist->entries);
105 evlist->nr_entries += nr_entries; 107 evlist->nr_entries += nr_entries;
@@ -597,15 +599,15 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
597 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 599 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
598} 600}
599 601
600int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, 602int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
601 pid_t target_tid, const char *cpu_list) 603 const char *target_tid, uid_t uid, const char *cpu_list)
602{ 604{
603 evlist->threads = thread_map__new(target_pid, target_tid); 605 evlist->threads = thread_map__new_str(target_pid, target_tid, uid);
604 606
605 if (evlist->threads == NULL) 607 if (evlist->threads == NULL)
606 return -1; 608 return -1;
607 609
608 if (cpu_list == NULL && target_tid != -1) 610 if (uid != UINT_MAX || (cpu_list == NULL && target_tid))
609 evlist->cpus = cpu_map__dummy_new(); 611 evlist->cpus = cpu_map__dummy_new();
610 else 612 else
611 evlist->cpus = cpu_map__new(cpu_list); 613 evlist->cpus = cpu_map__new(cpu_list);
@@ -765,6 +767,7 @@ out_err:
765 list_for_each_entry_reverse(evsel, &evlist->entries, node) 767 list_for_each_entry_reverse(evsel, &evlist->entries, node)
766 perf_evsel__close(evsel, ncpus, nthreads); 768 perf_evsel__close(evsel, ncpus, nthreads);
767 769
770 errno = -err;
768 return err; 771 return err;
769} 772}
770 773
@@ -824,7 +827,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
824 exit(-1); 827 exit(-1);
825 } 828 }
826 829
827 if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) 830 if (!opts->system_wide && !opts->target_tid && !opts->target_pid)
828 evlist->threads->map[0] = evlist->workload.pid; 831 evlist->threads->map[0] = evlist->workload.pid;
829 832
830 close(child_ready_pipe[1]); 833 close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 8922aeed0467..21f1c9e57f13 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
106 evlist->threads = threads; 106 evlist->threads = threads;
107} 107}
108 108
109int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, 109int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
110 pid_t target_tid, const char *cpu_list); 110 const char *tid, uid_t uid, const char *cpu_list);
111void perf_evlist__delete_maps(struct perf_evlist *evlist); 111void perf_evlist__delete_maps(struct perf_evlist *evlist);
112int perf_evlist__set_filters(struct perf_evlist *evlist); 112int perf_evlist__set_filters(struct perf_evlist *evlist);
113 113
@@ -117,4 +117,9 @@ u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
117 117
118bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); 118bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
119bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); 119bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
120
121void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
122 struct list_head *list,
123 int nr_entries);
124
120#endif /* __PERF_EVLIST_H */ 125#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 7132ee834e0e..8c13dbcb84b9 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -34,7 +34,7 @@ int __perf_evsel__sample_size(u64 sample_type)
34 return size; 34 return size;
35} 35}
36 36
37static void hists__init(struct hists *hists) 37void hists__init(struct hists *hists)
38{ 38{
39 memset(hists, 0, sizeof(*hists)); 39 memset(hists, 0, sizeof(*hists));
40 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; 40 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
@@ -63,12 +63,13 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
63 return evsel; 63 return evsel;
64} 64}
65 65
66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) 66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
67 struct perf_evsel *first)
67{ 68{
68 struct perf_event_attr *attr = &evsel->attr; 69 struct perf_event_attr *attr = &evsel->attr;
69 int track = !evsel->idx; /* only the first counter needs these */ 70 int track = !evsel->idx; /* only the first counter needs these */
70 71
71 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; 72 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
72 attr->inherit = !opts->no_inherit; 73 attr->inherit = !opts->no_inherit;
73 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 74 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
74 PERF_FORMAT_TOTAL_TIME_RUNNING | 75 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -111,7 +112,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
111 if (opts->period) 112 if (opts->period)
112 attr->sample_type |= PERF_SAMPLE_PERIOD; 113 attr->sample_type |= PERF_SAMPLE_PERIOD;
113 114
114 if (opts->sample_id_all_avail && 115 if (!opts->sample_id_all_missing &&
115 (opts->sample_time || opts->system_wide || 116 (opts->sample_time || opts->system_wide ||
116 !opts->no_inherit || opts->cpu_list)) 117 !opts->no_inherit || opts->cpu_list))
117 attr->sample_type |= PERF_SAMPLE_TIME; 118 attr->sample_type |= PERF_SAMPLE_TIME;
@@ -126,11 +127,16 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
126 attr->watermark = 0; 127 attr->watermark = 0;
127 attr->wakeup_events = 1; 128 attr->wakeup_events = 1;
128 } 129 }
130 if (opts->branch_stack) {
131 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK;
132 attr->branch_sample_type = opts->branch_stack;
133 }
129 134
130 attr->mmap = track; 135 attr->mmap = track;
131 attr->comm = track; 136 attr->comm = track;
132 137
133 if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) { 138 if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
139 (!opts->group || evsel == first)) {
134 attr->disabled = 1; 140 attr->disabled = 1;
135 attr->enable_on_exec = 1; 141 attr->enable_on_exec = 1;
136 } 142 }
@@ -536,7 +542,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
536 } 542 }
537 543
538 if (type & PERF_SAMPLE_READ) { 544 if (type & PERF_SAMPLE_READ) {
539 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n"); 545 fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n");
540 return -1; 546 return -1;
541 } 547 }
542 548
@@ -574,8 +580,20 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
574 return -EFAULT; 580 return -EFAULT;
575 581
576 data->raw_data = (void *) pdata; 582 data->raw_data = (void *) pdata;
583
584 array = (void *)array + data->raw_size + sizeof(u32);
577 } 585 }
578 586
587 if (type & PERF_SAMPLE_BRANCH_STACK) {
588 u64 sz;
589
590 data->branch_stack = (struct branch_stack *)array;
591 array++; /* nr */
592
593 sz = data->branch_stack->nr * sizeof(struct branch_entry);
594 sz /= sizeof(u64);
595 array += sz;
596 }
579 return 0; 597 return 0;
580} 598}
581 599
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 326b8e4d5035..3d6b3e4cb66b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -80,7 +80,8 @@ void perf_evsel__exit(struct perf_evsel *evsel);
80void perf_evsel__delete(struct perf_evsel *evsel); 80void perf_evsel__delete(struct perf_evsel *evsel);
81 81
82void perf_evsel__config(struct perf_evsel *evsel, 82void perf_evsel__config(struct perf_evsel *evsel,
83 struct perf_record_opts *opts); 83 struct perf_record_opts *opts,
84 struct perf_evsel *first);
84 85
85int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 86int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
86int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 87int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
@@ -169,4 +170,6 @@ static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
169 return __perf_evsel__sample_size(evsel->attr.sample_type); 170 return __perf_evsel__sample_size(evsel->attr.sample_type);
170} 171}
171 172
173void hists__init(struct hists *hists);
174
172#endif /* __PERF_EVSEL_H */ 175#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/util/gtk/browser.c
new file mode 100644
index 000000000000..258352a2356c
--- /dev/null
+++ b/tools/perf/util/gtk/browser.c
@@ -0,0 +1,189 @@
1#include "../evlist.h"
2#include "../cache.h"
3#include "../evsel.h"
4#include "../sort.h"
5#include "../hist.h"
6#include "gtk.h"
7
8#include <signal.h>
9
10#define MAX_COLUMNS 32
11
12void perf_gtk_setup_browser(int argc, const char *argv[],
13 bool fallback_to_pager __used)
14{
15 gtk_init(&argc, (char ***)&argv);
16}
17
18void perf_gtk_exit_browser(bool wait_for_ok __used)
19{
20 gtk_main_quit();
21}
22
23static void perf_gtk_signal(int sig)
24{
25 psignal(sig, "perf");
26 gtk_main_quit();
27}
28
29static void perf_gtk_resize_window(GtkWidget *window)
30{
31 GdkRectangle rect;
32 GdkScreen *screen;
33 int monitor;
34 int height;
35 int width;
36
37 screen = gtk_widget_get_screen(window);
38
39 monitor = gdk_screen_get_monitor_at_window(screen, window->window);
40
41 gdk_screen_get_monitor_geometry(screen, monitor, &rect);
42
43 width = rect.width * 3 / 4;
44 height = rect.height * 3 / 4;
45
46 gtk_window_resize(GTK_WINDOW(window), width, height);
47}
48
49static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists)
50{
51 GType col_types[MAX_COLUMNS];
52 GtkCellRenderer *renderer;
53 struct sort_entry *se;
54 GtkListStore *store;
55 struct rb_node *nd;
56 u64 total_period;
57 GtkWidget *view;
58 int col_idx;
59 int nr_cols;
60
61 nr_cols = 0;
62
63 /* The percentage column */
64 col_types[nr_cols++] = G_TYPE_STRING;
65
66 list_for_each_entry(se, &hist_entry__sort_list, list) {
67 if (se->elide)
68 continue;
69
70 col_types[nr_cols++] = G_TYPE_STRING;
71 }
72
73 store = gtk_list_store_newv(nr_cols, col_types);
74
75 view = gtk_tree_view_new();
76
77 renderer = gtk_cell_renderer_text_new();
78
79 col_idx = 0;
80
81 /* The percentage column */
82 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
83 -1, "Overhead (%)",
84 renderer, "text",
85 col_idx++, NULL);
86
87 list_for_each_entry(se, &hist_entry__sort_list, list) {
88 if (se->elide)
89 continue;
90
91 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
92 -1, se->se_header,
93 renderer, "text",
94 col_idx++, NULL);
95 }
96
97 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
98
99 g_object_unref(GTK_TREE_MODEL(store));
100
101 total_period = hists->stats.total_period;
102
103 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
104 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
105 GtkTreeIter iter;
106 double percent;
107 char s[512];
108
109 if (h->filtered)
110 continue;
111
112 gtk_list_store_append(store, &iter);
113
114 col_idx = 0;
115
116 percent = (h->period * 100.0) / total_period;
117
118 snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
119
120 gtk_list_store_set(store, &iter, col_idx++, s, -1);
121
122 list_for_each_entry(se, &hist_entry__sort_list, list) {
123 if (se->elide)
124 continue;
125
126 se->se_snprintf(h, s, ARRAY_SIZE(s),
127 hists__col_len(hists, se->se_width_idx));
128
129 gtk_list_store_set(store, &iter, col_idx++, s, -1);
130 }
131 }
132
133 gtk_container_add(GTK_CONTAINER(window), view);
134}
135
136int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
137 const char *help __used,
138 void (*timer) (void *arg)__used,
139 void *arg __used, int delay_secs __used)
140{
141 struct perf_evsel *pos;
142 GtkWidget *notebook;
143 GtkWidget *window;
144
145 signal(SIGSEGV, perf_gtk_signal);
146 signal(SIGFPE, perf_gtk_signal);
147 signal(SIGINT, perf_gtk_signal);
148 signal(SIGQUIT, perf_gtk_signal);
149 signal(SIGTERM, perf_gtk_signal);
150
151 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
152
153 gtk_window_set_title(GTK_WINDOW(window), "perf report");
154
155 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
156
157 notebook = gtk_notebook_new();
158
159 list_for_each_entry(pos, &evlist->entries, node) {
160 struct hists *hists = &pos->hists;
161 const char *evname = event_name(pos);
162 GtkWidget *scrolled_window;
163 GtkWidget *tab_label;
164
165 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
166
167 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
168 GTK_POLICY_AUTOMATIC,
169 GTK_POLICY_AUTOMATIC);
170
171 perf_gtk_show_hists(scrolled_window, hists);
172
173 tab_label = gtk_label_new(evname);
174
175 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
176 }
177
178 gtk_container_add(GTK_CONTAINER(window), notebook);
179
180 gtk_widget_show_all(window);
181
182 perf_gtk_resize_window(window);
183
184 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
185
186 gtk_main();
187
188 return 0;
189}
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/util/gtk/gtk.h
new file mode 100644
index 000000000000..75177ee04032
--- /dev/null
+++ b/tools/perf/util/gtk/gtk.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_GTK_H_
2#define _PERF_GTK_H_ 1
3
4#pragma GCC diagnostic ignored "-Wstrict-prototypes"
5#include <gtk/gtk.h>
6#pragma GCC diagnostic error "-Wstrict-prototypes"
7
8#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index ecd7f4dd7eea..4c7c2d73251f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -63,9 +63,20 @@ char *perf_header__find_event(u64 id)
63 return NULL; 63 return NULL;
64} 64}
65 65
66static const char *__perf_magic = "PERFFILE"; 66/*
67 * magic2 = "PERFILE2"
68 * must be a numerical value to let the endianness
69 * determine the memory layout. That way we are able
70 * to detect endianness when reading the perf.data file
71 * back.
72 *
73 * we check for legacy (PERFFILE) format.
74 */
75static const char *__perf_magic1 = "PERFFILE";
76static const u64 __perf_magic2 = 0x32454c4946524550ULL;
77static const u64 __perf_magic2_sw = 0x50455246494c4532ULL;
67 78
68#define PERF_MAGIC (*(u64 *)__perf_magic) 79#define PERF_MAGIC __perf_magic2
69 80
70struct perf_file_attr { 81struct perf_file_attr {
71 struct perf_event_attr attr; 82 struct perf_event_attr attr;
@@ -280,7 +291,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
280 if (realname == NULL || filename == NULL || linkname == NULL) 291 if (realname == NULL || filename == NULL || linkname == NULL)
281 goto out_free; 292 goto out_free;
282 293
283 len = snprintf(filename, size, "%s%s%s", 294 len = scnprintf(filename, size, "%s%s%s",
284 debugdir, is_kallsyms ? "/" : "", realname); 295 debugdir, is_kallsyms ? "/" : "", realname);
285 if (mkdir_p(filename, 0755)) 296 if (mkdir_p(filename, 0755))
286 goto out_free; 297 goto out_free;
@@ -295,7 +306,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
295 goto out_free; 306 goto out_free;
296 } 307 }
297 308
298 len = snprintf(linkname, size, "%s/.build-id/%.2s", 309 len = scnprintf(linkname, size, "%s/.build-id/%.2s",
299 debugdir, sbuild_id); 310 debugdir, sbuild_id);
300 311
301 if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) 312 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
@@ -1012,6 +1023,12 @@ write_it:
1012 return do_write_string(fd, buffer); 1023 return do_write_string(fd, buffer);
1013} 1024}
1014 1025
1026static int write_branch_stack(int fd __used, struct perf_header *h __used,
1027 struct perf_evlist *evlist __used)
1028{
1029 return 0;
1030}
1031
1015static void print_hostname(struct perf_header *ph, int fd, FILE *fp) 1032static void print_hostname(struct perf_header *ph, int fd, FILE *fp)
1016{ 1033{
1017 char *str = do_read_string(fd, ph); 1034 char *str = do_read_string(fd, ph);
@@ -1133,8 +1150,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1133 uint64_t id; 1150 uint64_t id;
1134 void *buf = NULL; 1151 void *buf = NULL;
1135 char *str; 1152 char *str;
1136 u32 nre, sz, nr, i, j, msz; 1153 u32 nre, sz, nr, i, j;
1137 int ret; 1154 ssize_t ret;
1155 size_t msz;
1138 1156
1139 /* number of events */ 1157 /* number of events */
1140 ret = read(fd, &nre, sizeof(nre)); 1158 ret = read(fd, &nre, sizeof(nre));
@@ -1151,15 +1169,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1151 if (ph->needs_swap) 1169 if (ph->needs_swap)
1152 sz = bswap_32(sz); 1170 sz = bswap_32(sz);
1153 1171
1154 /*
1155 * ensure it is at least to our ABI rev
1156 */
1157 if (sz < (u32)sizeof(attr))
1158 goto error;
1159
1160 memset(&attr, 0, sizeof(attr)); 1172 memset(&attr, 0, sizeof(attr));
1161 1173
1162 /* read entire region to sync up to next field */ 1174 /* buffer to hold on file attr struct */
1163 buf = malloc(sz); 1175 buf = malloc(sz);
1164 if (!buf) 1176 if (!buf)
1165 goto error; 1177 goto error;
@@ -1170,6 +1182,10 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1170 1182
1171 for (i = 0 ; i < nre; i++) { 1183 for (i = 0 ; i < nre; i++) {
1172 1184
1185 /*
1186 * must read entire on-file attr struct to
1187 * sync up with layout.
1188 */
1173 ret = read(fd, buf, sz); 1189 ret = read(fd, buf, sz);
1174 if (ret != (ssize_t)sz) 1190 if (ret != (ssize_t)sz)
1175 goto error; 1191 goto error;
@@ -1305,25 +1321,204 @@ static void print_cpuid(struct perf_header *ph, int fd, FILE *fp)
1305 free(str); 1321 free(str);
1306} 1322}
1307 1323
1324static void print_branch_stack(struct perf_header *ph __used, int fd __used,
1325 FILE *fp)
1326{
1327 fprintf(fp, "# contains samples with branch stack\n");
1328}
1329
1330static int __event_process_build_id(struct build_id_event *bev,
1331 char *filename,
1332 struct perf_session *session)
1333{
1334 int err = -1;
1335 struct list_head *head;
1336 struct machine *machine;
1337 u16 misc;
1338 struct dso *dso;
1339 enum dso_kernel_type dso_type;
1340
1341 machine = perf_session__findnew_machine(session, bev->pid);
1342 if (!machine)
1343 goto out;
1344
1345 misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1346
1347 switch (misc) {
1348 case PERF_RECORD_MISC_KERNEL:
1349 dso_type = DSO_TYPE_KERNEL;
1350 head = &machine->kernel_dsos;
1351 break;
1352 case PERF_RECORD_MISC_GUEST_KERNEL:
1353 dso_type = DSO_TYPE_GUEST_KERNEL;
1354 head = &machine->kernel_dsos;
1355 break;
1356 case PERF_RECORD_MISC_USER:
1357 case PERF_RECORD_MISC_GUEST_USER:
1358 dso_type = DSO_TYPE_USER;
1359 head = &machine->user_dsos;
1360 break;
1361 default:
1362 goto out;
1363 }
1364
1365 dso = __dsos__findnew(head, filename);
1366 if (dso != NULL) {
1367 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1368
1369 dso__set_build_id(dso, &bev->build_id);
1370
1371 if (filename[0] == '[')
1372 dso->kernel = dso_type;
1373
1374 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
1375 sbuild_id);
1376 pr_debug("build id event received for %s: %s\n",
1377 dso->long_name, sbuild_id);
1378 }
1379
1380 err = 0;
1381out:
1382 return err;
1383}
1384
1385static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1386 int input, u64 offset, u64 size)
1387{
1388 struct perf_session *session = container_of(header, struct perf_session, header);
1389 struct {
1390 struct perf_event_header header;
1391 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
1392 char filename[0];
1393 } old_bev;
1394 struct build_id_event bev;
1395 char filename[PATH_MAX];
1396 u64 limit = offset + size;
1397
1398 while (offset < limit) {
1399 ssize_t len;
1400
1401 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
1402 return -1;
1403
1404 if (header->needs_swap)
1405 perf_event_header__bswap(&old_bev.header);
1406
1407 len = old_bev.header.size - sizeof(old_bev);
1408 if (read(input, filename, len) != len)
1409 return -1;
1410
1411 bev.header = old_bev.header;
1412
1413 /*
1414 * As the pid is the missing value, we need to fill
1415 * it properly. The header.misc value give us nice hint.
1416 */
1417 bev.pid = HOST_KERNEL_ID;
1418 if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
1419 bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
1420 bev.pid = DEFAULT_GUEST_KERNEL_ID;
1421
1422 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
1423 __event_process_build_id(&bev, filename, session);
1424
1425 offset += bev.header.size;
1426 }
1427
1428 return 0;
1429}
1430
1431static int perf_header__read_build_ids(struct perf_header *header,
1432 int input, u64 offset, u64 size)
1433{
1434 struct perf_session *session = container_of(header, struct perf_session, header);
1435 struct build_id_event bev;
1436 char filename[PATH_MAX];
1437 u64 limit = offset + size, orig_offset = offset;
1438 int err = -1;
1439
1440 while (offset < limit) {
1441 ssize_t len;
1442
1443 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
1444 goto out;
1445
1446 if (header->needs_swap)
1447 perf_event_header__bswap(&bev.header);
1448
1449 len = bev.header.size - sizeof(bev);
1450 if (read(input, filename, len) != len)
1451 goto out;
1452 /*
1453 * The a1645ce1 changeset:
1454 *
1455 * "perf: 'perf kvm' tool for monitoring guest performance from host"
1456 *
1457 * Added a field to struct build_id_event that broke the file
1458 * format.
1459 *
1460 * Since the kernel build-id is the first entry, process the
1461 * table using the old format if the well known
1462 * '[kernel.kallsyms]' string for the kernel build-id has the
1463 * first 4 characters chopped off (where the pid_t sits).
1464 */
1465 if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
1466 if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
1467 return -1;
1468 return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
1469 }
1470
1471 __event_process_build_id(&bev, filename, session);
1472
1473 offset += bev.header.size;
1474 }
1475 err = 0;
1476out:
1477 return err;
1478}
1479
1480static int process_trace_info(struct perf_file_section *section __unused,
1481 struct perf_header *ph __unused,
1482 int feat __unused, int fd)
1483{
1484 trace_report(fd, false);
1485 return 0;
1486}
1487
1488static int process_build_id(struct perf_file_section *section,
1489 struct perf_header *ph,
1490 int feat __unused, int fd)
1491{
1492 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
1493 pr_debug("Failed to read buildids, continuing...\n");
1494 return 0;
1495}
1496
1308struct feature_ops { 1497struct feature_ops {
1309 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 1498 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1310 void (*print)(struct perf_header *h, int fd, FILE *fp); 1499 void (*print)(struct perf_header *h, int fd, FILE *fp);
1500 int (*process)(struct perf_file_section *section,
1501 struct perf_header *h, int feat, int fd);
1311 const char *name; 1502 const char *name;
1312 bool full_only; 1503 bool full_only;
1313}; 1504};
1314 1505
1315#define FEAT_OPA(n, func) \ 1506#define FEAT_OPA(n, func) \
1316 [n] = { .name = #n, .write = write_##func, .print = print_##func } 1507 [n] = { .name = #n, .write = write_##func, .print = print_##func }
1508#define FEAT_OPP(n, func) \
1509 [n] = { .name = #n, .write = write_##func, .print = print_##func, \
1510 .process = process_##func }
1317#define FEAT_OPF(n, func) \ 1511#define FEAT_OPF(n, func) \
1318 [n] = { .name = #n, .write = write_##func, .print = print_##func, .full_only = true } 1512 [n] = { .name = #n, .write = write_##func, .print = print_##func, \
1513 .full_only = true }
1319 1514
1320/* feature_ops not implemented: */ 1515/* feature_ops not implemented: */
1321#define print_trace_info NULL 1516#define print_trace_info NULL
1322#define print_build_id NULL 1517#define print_build_id NULL
1323 1518
1324static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { 1519static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1325 FEAT_OPA(HEADER_TRACE_INFO, trace_info), 1520 FEAT_OPP(HEADER_TRACE_INFO, trace_info),
1326 FEAT_OPA(HEADER_BUILD_ID, build_id), 1521 FEAT_OPP(HEADER_BUILD_ID, build_id),
1327 FEAT_OPA(HEADER_HOSTNAME, hostname), 1522 FEAT_OPA(HEADER_HOSTNAME, hostname),
1328 FEAT_OPA(HEADER_OSRELEASE, osrelease), 1523 FEAT_OPA(HEADER_OSRELEASE, osrelease),
1329 FEAT_OPA(HEADER_VERSION, version), 1524 FEAT_OPA(HEADER_VERSION, version),
@@ -1336,6 +1531,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1336 FEAT_OPA(HEADER_CMDLINE, cmdline), 1531 FEAT_OPA(HEADER_CMDLINE, cmdline),
1337 FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology), 1532 FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
1338 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), 1533 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
1534 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
1339}; 1535};
1340 1536
1341struct header_print_data { 1537struct header_print_data {
@@ -1620,24 +1816,128 @@ out_free:
1620 return err; 1816 return err;
1621} 1817}
1622 1818
1819static const int attr_file_abi_sizes[] = {
1820 [0] = PERF_ATTR_SIZE_VER0,
1821 [1] = PERF_ATTR_SIZE_VER1,
1822 0,
1823};
1824
1825/*
1826 * In the legacy file format, the magic number is not used to encode endianness.
1827 * hdr_sz was used to encode endianness. But given that hdr_sz can vary based
1828 * on ABI revisions, we need to try all combinations for all endianness to
1829 * detect the endianness.
1830 */
1831static int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph)
1832{
1833 uint64_t ref_size, attr_size;
1834 int i;
1835
1836 for (i = 0 ; attr_file_abi_sizes[i]; i++) {
1837 ref_size = attr_file_abi_sizes[i]
1838 + sizeof(struct perf_file_section);
1839 if (hdr_sz != ref_size) {
1840 attr_size = bswap_64(hdr_sz);
1841 if (attr_size != ref_size)
1842 continue;
1843
1844 ph->needs_swap = true;
1845 }
1846 pr_debug("ABI%d perf.data file detected, need_swap=%d\n",
1847 i,
1848 ph->needs_swap);
1849 return 0;
1850 }
1851 /* could not determine endianness */
1852 return -1;
1853}
1854
1855#define PERF_PIPE_HDR_VER0 16
1856
1857static const size_t attr_pipe_abi_sizes[] = {
1858 [0] = PERF_PIPE_HDR_VER0,
1859 0,
1860};
1861
1862/*
1863 * In the legacy pipe format, there is an implicit assumption that endiannesss
1864 * between host recording the samples, and host parsing the samples is the
1865 * same. This is not always the case given that the pipe output may always be
1866 * redirected into a file and analyzed on a different machine with possibly a
1867 * different endianness and perf_event ABI revsions in the perf tool itself.
1868 */
1869static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
1870{
1871 u64 attr_size;
1872 int i;
1873
1874 for (i = 0 ; attr_pipe_abi_sizes[i]; i++) {
1875 if (hdr_sz != attr_pipe_abi_sizes[i]) {
1876 attr_size = bswap_64(hdr_sz);
1877 if (attr_size != hdr_sz)
1878 continue;
1879
1880 ph->needs_swap = true;
1881 }
1882 pr_debug("Pipe ABI%d perf.data file detected\n", i);
1883 return 0;
1884 }
1885 return -1;
1886}
1887
1888static int check_magic_endian(u64 magic, uint64_t hdr_sz,
1889 bool is_pipe, struct perf_header *ph)
1890{
1891 int ret;
1892
1893 /* check for legacy format */
1894 ret = memcmp(&magic, __perf_magic1, sizeof(magic));
1895 if (ret == 0) {
1896 pr_debug("legacy perf.data format\n");
1897 if (is_pipe)
1898 return try_all_pipe_abis(hdr_sz, ph);
1899
1900 return try_all_file_abis(hdr_sz, ph);
1901 }
1902 /*
1903 * the new magic number serves two purposes:
1904 * - unique number to identify actual perf.data files
1905 * - encode endianness of file
1906 */
1907
1908 /* check magic number with one endianness */
1909 if (magic == __perf_magic2)
1910 return 0;
1911
1912 /* check magic number with opposite endianness */
1913 if (magic != __perf_magic2_sw)
1914 return -1;
1915
1916 ph->needs_swap = true;
1917
1918 return 0;
1919}
1920
1623int perf_file_header__read(struct perf_file_header *header, 1921int perf_file_header__read(struct perf_file_header *header,
1624 struct perf_header *ph, int fd) 1922 struct perf_header *ph, int fd)
1625{ 1923{
1924 int ret;
1925
1626 lseek(fd, 0, SEEK_SET); 1926 lseek(fd, 0, SEEK_SET);
1627 1927
1628 if (readn(fd, header, sizeof(*header)) <= 0 || 1928 ret = readn(fd, header, sizeof(*header));
1629 memcmp(&header->magic, __perf_magic, sizeof(header->magic))) 1929 if (ret <= 0)
1630 return -1; 1930 return -1;
1631 1931
1632 if (header->attr_size != sizeof(struct perf_file_attr)) { 1932 if (check_magic_endian(header->magic,
1633 u64 attr_size = bswap_64(header->attr_size); 1933 header->attr_size, false, ph) < 0) {
1634 1934 pr_debug("magic/endian check failed\n");
1635 if (attr_size != sizeof(struct perf_file_attr)) 1935 return -1;
1636 return -1; 1936 }
1637 1937
1938 if (ph->needs_swap) {
1638 mem_bswap_64(header, offsetof(struct perf_file_header, 1939 mem_bswap_64(header, offsetof(struct perf_file_header,
1639 adds_features)); 1940 adds_features));
1640 ph->needs_swap = true;
1641 } 1941 }
1642 1942
1643 if (header->size != sizeof(*header)) { 1943 if (header->size != sizeof(*header)) {
@@ -1689,156 +1989,6 @@ int perf_file_header__read(struct perf_file_header *header,
1689 return 0; 1989 return 0;
1690} 1990}
1691 1991
1692static int __event_process_build_id(struct build_id_event *bev,
1693 char *filename,
1694 struct perf_session *session)
1695{
1696 int err = -1;
1697 struct list_head *head;
1698 struct machine *machine;
1699 u16 misc;
1700 struct dso *dso;
1701 enum dso_kernel_type dso_type;
1702
1703 machine = perf_session__findnew_machine(session, bev->pid);
1704 if (!machine)
1705 goto out;
1706
1707 misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1708
1709 switch (misc) {
1710 case PERF_RECORD_MISC_KERNEL:
1711 dso_type = DSO_TYPE_KERNEL;
1712 head = &machine->kernel_dsos;
1713 break;
1714 case PERF_RECORD_MISC_GUEST_KERNEL:
1715 dso_type = DSO_TYPE_GUEST_KERNEL;
1716 head = &machine->kernel_dsos;
1717 break;
1718 case PERF_RECORD_MISC_USER:
1719 case PERF_RECORD_MISC_GUEST_USER:
1720 dso_type = DSO_TYPE_USER;
1721 head = &machine->user_dsos;
1722 break;
1723 default:
1724 goto out;
1725 }
1726
1727 dso = __dsos__findnew(head, filename);
1728 if (dso != NULL) {
1729 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1730
1731 dso__set_build_id(dso, &bev->build_id);
1732
1733 if (filename[0] == '[')
1734 dso->kernel = dso_type;
1735
1736 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
1737 sbuild_id);
1738 pr_debug("build id event received for %s: %s\n",
1739 dso->long_name, sbuild_id);
1740 }
1741
1742 err = 0;
1743out:
1744 return err;
1745}
1746
1747static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1748 int input, u64 offset, u64 size)
1749{
1750 struct perf_session *session = container_of(header, struct perf_session, header);
1751 struct {
1752 struct perf_event_header header;
1753 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
1754 char filename[0];
1755 } old_bev;
1756 struct build_id_event bev;
1757 char filename[PATH_MAX];
1758 u64 limit = offset + size;
1759
1760 while (offset < limit) {
1761 ssize_t len;
1762
1763 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
1764 return -1;
1765
1766 if (header->needs_swap)
1767 perf_event_header__bswap(&old_bev.header);
1768
1769 len = old_bev.header.size - sizeof(old_bev);
1770 if (read(input, filename, len) != len)
1771 return -1;
1772
1773 bev.header = old_bev.header;
1774
1775 /*
1776 * As the pid is the missing value, we need to fill
1777 * it properly. The header.misc value give us nice hint.
1778 */
1779 bev.pid = HOST_KERNEL_ID;
1780 if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
1781 bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
1782 bev.pid = DEFAULT_GUEST_KERNEL_ID;
1783
1784 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
1785 __event_process_build_id(&bev, filename, session);
1786
1787 offset += bev.header.size;
1788 }
1789
1790 return 0;
1791}
1792
1793static int perf_header__read_build_ids(struct perf_header *header,
1794 int input, u64 offset, u64 size)
1795{
1796 struct perf_session *session = container_of(header, struct perf_session, header);
1797 struct build_id_event bev;
1798 char filename[PATH_MAX];
1799 u64 limit = offset + size, orig_offset = offset;
1800 int err = -1;
1801
1802 while (offset < limit) {
1803 ssize_t len;
1804
1805 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
1806 goto out;
1807
1808 if (header->needs_swap)
1809 perf_event_header__bswap(&bev.header);
1810
1811 len = bev.header.size - sizeof(bev);
1812 if (read(input, filename, len) != len)
1813 goto out;
1814 /*
1815 * The a1645ce1 changeset:
1816 *
1817 * "perf: 'perf kvm' tool for monitoring guest performance from host"
1818 *
1819 * Added a field to struct build_id_event that broke the file
1820 * format.
1821 *
1822 * Since the kernel build-id is the first entry, process the
1823 * table using the old format if the well known
1824 * '[kernel.kallsyms]' string for the kernel build-id has the
1825 * first 4 characters chopped off (where the pid_t sits).
1826 */
1827 if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
1828 if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
1829 return -1;
1830 return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
1831 }
1832
1833 __event_process_build_id(&bev, filename, session);
1834
1835 offset += bev.header.size;
1836 }
1837 err = 0;
1838out:
1839 return err;
1840}
1841
1842static int perf_file_section__process(struct perf_file_section *section, 1992static int perf_file_section__process(struct perf_file_section *section,
1843 struct perf_header *ph, 1993 struct perf_header *ph,
1844 int feat, int fd, void *data __used) 1994 int feat, int fd, void *data __used)
@@ -1854,40 +2004,32 @@ static int perf_file_section__process(struct perf_file_section *section,
1854 return 0; 2004 return 0;
1855 } 2005 }
1856 2006
1857 switch (feat) { 2007 if (!feat_ops[feat].process)
1858 case HEADER_TRACE_INFO: 2008 return 0;
1859 trace_report(fd, false);
1860 break;
1861 case HEADER_BUILD_ID:
1862 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
1863 pr_debug("Failed to read buildids, continuing...\n");
1864 break;
1865 default:
1866 break;
1867 }
1868 2009
1869 return 0; 2010 return feat_ops[feat].process(section, ph, feat, fd);
1870} 2011}
1871 2012
1872static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, 2013static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
1873 struct perf_header *ph, int fd, 2014 struct perf_header *ph, int fd,
1874 bool repipe) 2015 bool repipe)
1875{ 2016{
1876 if (readn(fd, header, sizeof(*header)) <= 0 || 2017 int ret;
1877 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
1878 return -1;
1879 2018
1880 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) 2019 ret = readn(fd, header, sizeof(*header));
2020 if (ret <= 0)
1881 return -1; 2021 return -1;
1882 2022
1883 if (header->size != sizeof(*header)) { 2023 if (check_magic_endian(header->magic, header->size, true, ph) < 0) {
1884 u64 size = bswap_64(header->size); 2024 pr_debug("endian/magic failed\n");
2025 return -1;
2026 }
1885 2027
1886 if (size != sizeof(*header)) 2028 if (ph->needs_swap)
1887 return -1; 2029 header->size = bswap_64(header->size);
1888 2030
1889 ph->needs_swap = true; 2031 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
1890 } 2032 return -1;
1891 2033
1892 return 0; 2034 return 0;
1893} 2035}
@@ -1908,6 +2050,52 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
1908 return 0; 2050 return 0;
1909} 2051}
1910 2052
2053static int read_attr(int fd, struct perf_header *ph,
2054 struct perf_file_attr *f_attr)
2055{
2056 struct perf_event_attr *attr = &f_attr->attr;
2057 size_t sz, left;
2058 size_t our_sz = sizeof(f_attr->attr);
2059 int ret;
2060
2061 memset(f_attr, 0, sizeof(*f_attr));
2062
2063 /* read minimal guaranteed structure */
2064 ret = readn(fd, attr, PERF_ATTR_SIZE_VER0);
2065 if (ret <= 0) {
2066 pr_debug("cannot read %d bytes of header attr\n",
2067 PERF_ATTR_SIZE_VER0);
2068 return -1;
2069 }
2070
2071 /* on file perf_event_attr size */
2072 sz = attr->size;
2073
2074 if (ph->needs_swap)
2075 sz = bswap_32(sz);
2076
2077 if (sz == 0) {
2078 /* assume ABI0 */
2079 sz = PERF_ATTR_SIZE_VER0;
2080 } else if (sz > our_sz) {
2081 pr_debug("file uses a more recent and unsupported ABI"
2082 " (%zu bytes extra)\n", sz - our_sz);
2083 return -1;
2084 }
2085 /* what we have not yet read and that we know about */
2086 left = sz - PERF_ATTR_SIZE_VER0;
2087 if (left) {
2088 void *ptr = attr;
2089 ptr += PERF_ATTR_SIZE_VER0;
2090
2091 ret = readn(fd, ptr, left);
2092 }
2093 /* read perf_file_section, ids are read in caller */
2094 ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids));
2095
2096 return ret <= 0 ? -1 : 0;
2097}
2098
1911int perf_session__read_header(struct perf_session *session, int fd) 2099int perf_session__read_header(struct perf_session *session, int fd)
1912{ 2100{
1913 struct perf_header *header = &session->header; 2101 struct perf_header *header = &session->header;
@@ -1923,19 +2111,17 @@ int perf_session__read_header(struct perf_session *session, int fd)
1923 if (session->fd_pipe) 2111 if (session->fd_pipe)
1924 return perf_header__read_pipe(session, fd); 2112 return perf_header__read_pipe(session, fd);
1925 2113
1926 if (perf_file_header__read(&f_header, header, fd) < 0) { 2114 if (perf_file_header__read(&f_header, header, fd) < 0)
1927 pr_debug("incompatible file format\n");
1928 return -EINVAL; 2115 return -EINVAL;
1929 }
1930 2116
1931 nr_attrs = f_header.attrs.size / sizeof(f_attr); 2117 nr_attrs = f_header.attrs.size / f_header.attr_size;
1932 lseek(fd, f_header.attrs.offset, SEEK_SET); 2118 lseek(fd, f_header.attrs.offset, SEEK_SET);
1933 2119
1934 for (i = 0; i < nr_attrs; i++) { 2120 for (i = 0; i < nr_attrs; i++) {
1935 struct perf_evsel *evsel; 2121 struct perf_evsel *evsel;
1936 off_t tmp; 2122 off_t tmp;
1937 2123
1938 if (readn(fd, &f_attr, sizeof(f_attr)) <= 0) 2124 if (read_attr(fd, header, &f_attr) < 0)
1939 goto out_errno; 2125 goto out_errno;
1940 2126
1941 if (header->needs_swap) 2127 if (header->needs_swap)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index ac4ec956024e..21a6be09c129 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -11,6 +11,7 @@
11 11
12enum { 12enum {
13 HEADER_RESERVED = 0, /* always cleared */ 13 HEADER_RESERVED = 0, /* always cleared */
14 HEADER_FIRST_FEATURE = 1,
14 HEADER_TRACE_INFO = 1, 15 HEADER_TRACE_INFO = 1,
15 HEADER_BUILD_ID, 16 HEADER_BUILD_ID,
16 17
@@ -26,7 +27,7 @@ enum {
26 HEADER_EVENT_DESC, 27 HEADER_EVENT_DESC,
27 HEADER_CPU_TOPOLOGY, 28 HEADER_CPU_TOPOLOGY,
28 HEADER_NUMA_TOPOLOGY, 29 HEADER_NUMA_TOPOLOGY,
29 30 HEADER_BRANCH_STACK,
30 HEADER_LAST_FEATURE, 31 HEADER_LAST_FEATURE,
31 HEADER_FEAT_BITS = 256, 32 HEADER_FEAT_BITS = 256,
32}; 33};
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 6f505d1abac7..9f6d630d5316 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -10,11 +10,14 @@ static bool hists__filter_entry_by_dso(struct hists *hists,
10 struct hist_entry *he); 10 struct hist_entry *he);
11static bool hists__filter_entry_by_thread(struct hists *hists, 11static bool hists__filter_entry_by_thread(struct hists *hists,
12 struct hist_entry *he); 12 struct hist_entry *he);
13static bool hists__filter_entry_by_symbol(struct hists *hists,
14 struct hist_entry *he);
13 15
14enum hist_filter { 16enum hist_filter {
15 HIST_FILTER__DSO, 17 HIST_FILTER__DSO,
16 HIST_FILTER__THREAD, 18 HIST_FILTER__THREAD,
17 HIST_FILTER__PARENT, 19 HIST_FILTER__PARENT,
20 HIST_FILTER__SYMBOL,
18}; 21};
19 22
20struct callchain_param callchain_param = { 23struct callchain_param callchain_param = {
@@ -50,21 +53,25 @@ static void hists__reset_col_len(struct hists *hists)
50 hists__set_col_len(hists, col, 0); 53 hists__set_col_len(hists, col, 0);
51} 54}
52 55
56static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
57{
58 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
59
60 if (hists__col_len(hists, dso) < unresolved_col_width &&
61 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
62 !symbol_conf.dso_list)
63 hists__set_col_len(hists, dso, unresolved_col_width);
64}
65
53static void hists__calc_col_len(struct hists *hists, struct hist_entry *h) 66static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
54{ 67{
68 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
55 u16 len; 69 u16 len;
56 70
57 if (h->ms.sym) 71 if (h->ms.sym)
58 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen); 72 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
59 else { 73 else
60 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 74 hists__set_unres_dso_col_len(hists, HISTC_DSO);
61
62 if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
63 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
64 !symbol_conf.dso_list)
65 hists__set_col_len(hists, HISTC_DSO,
66 unresolved_col_width);
67 }
68 75
69 len = thread__comm_len(h->thread); 76 len = thread__comm_len(h->thread);
70 if (hists__new_col_len(hists, HISTC_COMM, len)) 77 if (hists__new_col_len(hists, HISTC_COMM, len))
@@ -74,6 +81,37 @@ static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
74 len = dso__name_len(h->ms.map->dso); 81 len = dso__name_len(h->ms.map->dso);
75 hists__new_col_len(hists, HISTC_DSO, len); 82 hists__new_col_len(hists, HISTC_DSO, len);
76 } 83 }
84
85 if (h->branch_info) {
86 int symlen;
87 /*
88 * +4 accounts for '[x] ' priv level info
89 * +2 account of 0x prefix on raw addresses
90 */
91 if (h->branch_info->from.sym) {
92 symlen = (int)h->branch_info->from.sym->namelen + 4;
93 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
94
95 symlen = dso__name_len(h->branch_info->from.map->dso);
96 hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
97 } else {
98 symlen = unresolved_col_width + 4 + 2;
99 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
100 hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
101 }
102
103 if (h->branch_info->to.sym) {
104 symlen = (int)h->branch_info->to.sym->namelen + 4;
105 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
106
107 symlen = dso__name_len(h->branch_info->to.map->dso);
108 hists__new_col_len(hists, HISTC_DSO_TO, symlen);
109 } else {
110 symlen = unresolved_col_width + 4 + 2;
111 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
112 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
113 }
114 }
77} 115}
78 116
79static void hist_entry__add_cpumode_period(struct hist_entry *he, 117static void hist_entry__add_cpumode_period(struct hist_entry *he,
@@ -195,26 +233,14 @@ static u8 symbol__parent_filter(const struct symbol *parent)
195 return 0; 233 return 0;
196} 234}
197 235
198struct hist_entry *__hists__add_entry(struct hists *hists, 236static struct hist_entry *add_hist_entry(struct hists *hists,
237 struct hist_entry *entry,
199 struct addr_location *al, 238 struct addr_location *al,
200 struct symbol *sym_parent, u64 period) 239 u64 period)
201{ 240{
202 struct rb_node **p; 241 struct rb_node **p;
203 struct rb_node *parent = NULL; 242 struct rb_node *parent = NULL;
204 struct hist_entry *he; 243 struct hist_entry *he;
205 struct hist_entry entry = {
206 .thread = al->thread,
207 .ms = {
208 .map = al->map,
209 .sym = al->sym,
210 },
211 .cpu = al->cpu,
212 .ip = al->addr,
213 .level = al->level,
214 .period = period,
215 .parent = sym_parent,
216 .filtered = symbol__parent_filter(sym_parent),
217 };
218 int cmp; 244 int cmp;
219 245
220 pthread_mutex_lock(&hists->lock); 246 pthread_mutex_lock(&hists->lock);
@@ -225,11 +251,23 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
225 parent = *p; 251 parent = *p;
226 he = rb_entry(parent, struct hist_entry, rb_node_in); 252 he = rb_entry(parent, struct hist_entry, rb_node_in);
227 253
228 cmp = hist_entry__cmp(&entry, he); 254 cmp = hist_entry__cmp(entry, he);
229 255
230 if (!cmp) { 256 if (!cmp) {
231 he->period += period; 257 he->period += period;
232 ++he->nr_events; 258 ++he->nr_events;
259
260 /* If the map of an existing hist_entry has
261 * become out-of-date due to an exec() or
262 * similar, update it. Otherwise we will
263 * mis-adjust symbol addresses when computing
264 * the history counter to increment.
265 */
266 if (he->ms.map != entry->ms.map) {
267 he->ms.map = entry->ms.map;
268 if (he->ms.map)
269 he->ms.map->referenced = true;
270 }
233 goto out; 271 goto out;
234 } 272 }
235 273
@@ -239,7 +277,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
239 p = &(*p)->rb_right; 277 p = &(*p)->rb_right;
240 } 278 }
241 279
242 he = hist_entry__new(&entry); 280 he = hist_entry__new(entry);
243 if (!he) 281 if (!he)
244 goto out_unlock; 282 goto out_unlock;
245 283
@@ -252,6 +290,51 @@ out_unlock:
252 return he; 290 return he;
253} 291}
254 292
293struct hist_entry *__hists__add_branch_entry(struct hists *self,
294 struct addr_location *al,
295 struct symbol *sym_parent,
296 struct branch_info *bi,
297 u64 period)
298{
299 struct hist_entry entry = {
300 .thread = al->thread,
301 .ms = {
302 .map = bi->to.map,
303 .sym = bi->to.sym,
304 },
305 .cpu = al->cpu,
306 .ip = bi->to.addr,
307 .level = al->level,
308 .period = period,
309 .parent = sym_parent,
310 .filtered = symbol__parent_filter(sym_parent),
311 .branch_info = bi,
312 };
313
314 return add_hist_entry(self, &entry, al, period);
315}
316
317struct hist_entry *__hists__add_entry(struct hists *self,
318 struct addr_location *al,
319 struct symbol *sym_parent, u64 period)
320{
321 struct hist_entry entry = {
322 .thread = al->thread,
323 .ms = {
324 .map = al->map,
325 .sym = al->sym,
326 },
327 .cpu = al->cpu,
328 .ip = al->addr,
329 .level = al->level,
330 .period = period,
331 .parent = sym_parent,
332 .filtered = symbol__parent_filter(sym_parent),
333 };
334
335 return add_hist_entry(self, &entry, al, period);
336}
337
255int64_t 338int64_t
256hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 339hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
257{ 340{
@@ -352,6 +435,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
352{ 435{
353 hists__filter_entry_by_dso(hists, he); 436 hists__filter_entry_by_dso(hists, he);
354 hists__filter_entry_by_thread(hists, he); 437 hists__filter_entry_by_thread(hists, he);
438 hists__filter_entry_by_symbol(hists, he);
355} 439}
356 440
357static void __hists__collapse_resort(struct hists *hists, bool threaded) 441static void __hists__collapse_resort(struct hists *hists, bool threaded)
@@ -535,7 +619,7 @@ static void init_rem_hits(void)
535 rem_hits.ms.sym = rem_sq_bracket; 619 rem_hits.ms.sym = rem_sq_bracket;
536} 620}
537 621
538static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 622static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
539 u64 total_samples, int depth, 623 u64 total_samples, int depth,
540 int depth_mask, int left_margin) 624 int depth_mask, int left_margin)
541{ 625{
@@ -543,21 +627,16 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
543 struct callchain_node *child; 627 struct callchain_node *child;
544 struct callchain_list *chain; 628 struct callchain_list *chain;
545 int new_depth_mask = depth_mask; 629 int new_depth_mask = depth_mask;
546 u64 new_total;
547 u64 remaining; 630 u64 remaining;
548 size_t ret = 0; 631 size_t ret = 0;
549 int i; 632 int i;
550 uint entries_printed = 0; 633 uint entries_printed = 0;
551 634
552 if (callchain_param.mode == CHAIN_GRAPH_REL) 635 remaining = total_samples;
553 new_total = self->children_hit;
554 else
555 new_total = total_samples;
556 636
557 remaining = new_total; 637 node = rb_first(root);
558
559 node = rb_first(&self->rb_root);
560 while (node) { 638 while (node) {
639 u64 new_total;
561 u64 cumul; 640 u64 cumul;
562 641
563 child = rb_entry(node, struct callchain_node, rb_node); 642 child = rb_entry(node, struct callchain_node, rb_node);
@@ -585,11 +664,17 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
585 list_for_each_entry(chain, &child->val, list) { 664 list_for_each_entry(chain, &child->val, list) {
586 ret += ipchain__fprintf_graph(fp, chain, depth, 665 ret += ipchain__fprintf_graph(fp, chain, depth,
587 new_depth_mask, i++, 666 new_depth_mask, i++,
588 new_total, 667 total_samples,
589 cumul, 668 cumul,
590 left_margin); 669 left_margin);
591 } 670 }
592 ret += __callchain__fprintf_graph(fp, child, new_total, 671
672 if (callchain_param.mode == CHAIN_GRAPH_REL)
673 new_total = child->children_hit;
674 else
675 new_total = total_samples;
676
677 ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
593 depth + 1, 678 depth + 1,
594 new_depth_mask | (1 << depth), 679 new_depth_mask | (1 << depth),
595 left_margin); 680 left_margin);
@@ -599,61 +684,75 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
599 } 684 }
600 685
601 if (callchain_param.mode == CHAIN_GRAPH_REL && 686 if (callchain_param.mode == CHAIN_GRAPH_REL &&
602 remaining && remaining != new_total) { 687 remaining && remaining != total_samples) {
603 688
604 if (!rem_sq_bracket) 689 if (!rem_sq_bracket)
605 return ret; 690 return ret;
606 691
607 new_depth_mask &= ~(1 << (depth - 1)); 692 new_depth_mask &= ~(1 << (depth - 1));
608
609 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 693 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
610 new_depth_mask, 0, new_total, 694 new_depth_mask, 0, total_samples,
611 remaining, left_margin); 695 remaining, left_margin);
612 } 696 }
613 697
614 return ret; 698 return ret;
615} 699}
616 700
617static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 701static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
618 u64 total_samples, int left_margin) 702 u64 total_samples, int left_margin)
619{ 703{
704 struct callchain_node *cnode;
620 struct callchain_list *chain; 705 struct callchain_list *chain;
706 u32 entries_printed = 0;
621 bool printed = false; 707 bool printed = false;
708 struct rb_node *node;
622 int i = 0; 709 int i = 0;
623 int ret = 0; 710 int ret;
624 u32 entries_printed = 0;
625
626 list_for_each_entry(chain, &self->val, list) {
627 if (!i++ && sort__first_dimension == SORT_SYM)
628 continue;
629
630 if (!printed) {
631 ret += callchain__fprintf_left_margin(fp, left_margin);
632 ret += fprintf(fp, "|\n");
633 ret += callchain__fprintf_left_margin(fp, left_margin);
634 ret += fprintf(fp, "---");
635
636 left_margin += 3;
637 printed = true;
638 } else
639 ret += callchain__fprintf_left_margin(fp, left_margin);
640 711
641 if (chain->ms.sym) 712 /*
642 ret += fprintf(fp, " %s\n", chain->ms.sym->name); 713 * If have one single callchain root, don't bother printing
643 else 714 * its percentage (100 % in fractal mode and the same percentage
644 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 715 * than the hist in graph mode). This also avoid one level of column.
716 */
717 node = rb_first(root);
718 if (node && !rb_next(node)) {
719 cnode = rb_entry(node, struct callchain_node, rb_node);
720 list_for_each_entry(chain, &cnode->val, list) {
721 /*
722 * If we sort by symbol, the first entry is the same than
723 * the symbol. No need to print it otherwise it appears as
724 * displayed twice.
725 */
726 if (!i++ && sort__first_dimension == SORT_SYM)
727 continue;
728 if (!printed) {
729 ret += callchain__fprintf_left_margin(fp, left_margin);
730 ret += fprintf(fp, "|\n");
731 ret += callchain__fprintf_left_margin(fp, left_margin);
732 ret += fprintf(fp, "---");
733 left_margin += 3;
734 printed = true;
735 } else
736 ret += callchain__fprintf_left_margin(fp, left_margin);
737
738 if (chain->ms.sym)
739 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
740 else
741 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
645 742
646 if (++entries_printed == callchain_param.print_limit) 743 if (++entries_printed == callchain_param.print_limit)
647 break; 744 break;
745 }
746 root = &cnode->rb_root;
648 } 747 }
649 748
650 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); 749 return __callchain__fprintf_graph(fp, root, total_samples,
651 750 1, 1, left_margin);
652 return ret;
653} 751}
654 752
655static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self, 753static size_t __callchain__fprintf_flat(FILE *fp,
656 u64 total_samples) 754 struct callchain_node *self,
755 u64 total_samples)
657{ 756{
658 struct callchain_list *chain; 757 struct callchain_list *chain;
659 size_t ret = 0; 758 size_t ret = 0;
@@ -661,7 +760,7 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
661 if (!self) 760 if (!self)
662 return 0; 761 return 0;
663 762
664 ret += callchain__fprintf_flat(fp, self->parent, total_samples); 763 ret += __callchain__fprintf_flat(fp, self->parent, total_samples);
665 764
666 765
667 list_for_each_entry(chain, &self->val, list) { 766 list_for_each_entry(chain, &self->val, list) {
@@ -677,44 +776,58 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
677 return ret; 776 return ret;
678} 777}
679 778
680static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 779static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self,
681 u64 total_samples, int left_margin, 780 u64 total_samples)
682 FILE *fp)
683{ 781{
684 struct rb_node *rb_node;
685 struct callchain_node *chain;
686 size_t ret = 0; 782 size_t ret = 0;
687 u32 entries_printed = 0; 783 u32 entries_printed = 0;
784 struct rb_node *rb_node;
785 struct callchain_node *chain;
688 786
689 rb_node = rb_first(&he->sorted_chain); 787 rb_node = rb_first(self);
690 while (rb_node) { 788 while (rb_node) {
691 double percent; 789 double percent;
692 790
693 chain = rb_entry(rb_node, struct callchain_node, rb_node); 791 chain = rb_entry(rb_node, struct callchain_node, rb_node);
694 percent = chain->hit * 100.0 / total_samples; 792 percent = chain->hit * 100.0 / total_samples;
695 switch (callchain_param.mode) { 793
696 case CHAIN_FLAT: 794 ret = percent_color_fprintf(fp, " %6.2f%%\n", percent);
697 ret += percent_color_fprintf(fp, " %6.2f%%\n", 795 ret += __callchain__fprintf_flat(fp, chain, total_samples);
698 percent);
699 ret += callchain__fprintf_flat(fp, chain, total_samples);
700 break;
701 case CHAIN_GRAPH_ABS: /* Falldown */
702 case CHAIN_GRAPH_REL:
703 ret += callchain__fprintf_graph(fp, chain, total_samples,
704 left_margin);
705 case CHAIN_NONE:
706 default:
707 break;
708 }
709 ret += fprintf(fp, "\n"); 796 ret += fprintf(fp, "\n");
710 if (++entries_printed == callchain_param.print_limit) 797 if (++entries_printed == callchain_param.print_limit)
711 break; 798 break;
799
712 rb_node = rb_next(rb_node); 800 rb_node = rb_next(rb_node);
713 } 801 }
714 802
715 return ret; 803 return ret;
716} 804}
717 805
806static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
807 u64 total_samples, int left_margin,
808 FILE *fp)
809{
810 switch (callchain_param.mode) {
811 case CHAIN_GRAPH_REL:
812 return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
813 left_margin);
814 break;
815 case CHAIN_GRAPH_ABS:
816 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
817 left_margin);
818 break;
819 case CHAIN_FLAT:
820 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
821 break;
822 case CHAIN_NONE:
823 break;
824 default:
825 pr_err("Bad callchain mode\n");
826 }
827
828 return 0;
829}
830
718void hists__output_recalc_col_len(struct hists *hists, int max_rows) 831void hists__output_recalc_col_len(struct hists *hists, int max_rows)
719{ 832{
720 struct rb_node *next = rb_first(&hists->entries); 833 struct rb_node *next = rb_first(&hists->entries);
@@ -768,7 +881,7 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
768 sep ? "%.2f" : " %6.2f%%", 881 sep ? "%.2f" : " %6.2f%%",
769 (period * 100.0) / total); 882 (period * 100.0) / total);
770 else 883 else
771 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%", 884 ret = scnprintf(s, size, sep ? "%.2f" : " %6.2f%%",
772 (period * 100.0) / total); 885 (period * 100.0) / total);
773 if (symbol_conf.show_cpu_utilization) { 886 if (symbol_conf.show_cpu_utilization) {
774 ret += percent_color_snprintf(s + ret, size - ret, 887 ret += percent_color_snprintf(s + ret, size - ret,
@@ -791,20 +904,20 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
791 } 904 }
792 } 905 }
793 } else 906 } else
794 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period); 907 ret = scnprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
795 908
796 if (symbol_conf.show_nr_samples) { 909 if (symbol_conf.show_nr_samples) {
797 if (sep) 910 if (sep)
798 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events); 911 ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
799 else 912 else
800 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events); 913 ret += scnprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
801 } 914 }
802 915
803 if (symbol_conf.show_total_period) { 916 if (symbol_conf.show_total_period) {
804 if (sep) 917 if (sep)
805 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period); 918 ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
806 else 919 else
807 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period); 920 ret += scnprintf(s + ret, size - ret, " %12" PRIu64, period);
808 } 921 }
809 922
810 if (pair_hists) { 923 if (pair_hists) {
@@ -819,25 +932,25 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
819 diff = new_percent - old_percent; 932 diff = new_percent - old_percent;
820 933
821 if (fabs(diff) >= 0.01) 934 if (fabs(diff) >= 0.01)
822 snprintf(bf, sizeof(bf), "%+4.2F%%", diff); 935 scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
823 else 936 else
824 snprintf(bf, sizeof(bf), " "); 937 scnprintf(bf, sizeof(bf), " ");
825 938
826 if (sep) 939 if (sep)
827 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf); 940 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
828 else 941 else
829 ret += snprintf(s + ret, size - ret, "%11.11s", bf); 942 ret += scnprintf(s + ret, size - ret, "%11.11s", bf);
830 943
831 if (show_displacement) { 944 if (show_displacement) {
832 if (displacement) 945 if (displacement)
833 snprintf(bf, sizeof(bf), "%+4ld", displacement); 946 scnprintf(bf, sizeof(bf), "%+4ld", displacement);
834 else 947 else
835 snprintf(bf, sizeof(bf), " "); 948 scnprintf(bf, sizeof(bf), " ");
836 949
837 if (sep) 950 if (sep)
838 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf); 951 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
839 else 952 else
840 ret += snprintf(s + ret, size - ret, "%6.6s", bf); 953 ret += scnprintf(s + ret, size - ret, "%6.6s", bf);
841 } 954 }
842 } 955 }
843 956
@@ -855,7 +968,7 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
855 if (se->elide) 968 if (se->elide)
856 continue; 969 continue;
857 970
858 ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); 971 ret += scnprintf(s + ret, size - ret, "%s", sep ?: " ");
859 ret += se->se_snprintf(he, s + ret, size - ret, 972 ret += se->se_snprintf(he, s + ret, size - ret,
860 hists__col_len(hists, se->se_width_idx)); 973 hists__col_len(hists, se->se_width_idx));
861 } 974 }
@@ -1179,6 +1292,37 @@ void hists__filter_by_thread(struct hists *hists)
1179 } 1292 }
1180} 1293}
1181 1294
1295static bool hists__filter_entry_by_symbol(struct hists *hists,
1296 struct hist_entry *he)
1297{
1298 if (hists->symbol_filter_str != NULL &&
1299 (!he->ms.sym || strstr(he->ms.sym->name,
1300 hists->symbol_filter_str) == NULL)) {
1301 he->filtered |= (1 << HIST_FILTER__SYMBOL);
1302 return true;
1303 }
1304
1305 return false;
1306}
1307
1308void hists__filter_by_symbol(struct hists *hists)
1309{
1310 struct rb_node *nd;
1311
1312 hists->nr_entries = hists->stats.total_period = 0;
1313 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1314 hists__reset_col_len(hists);
1315
1316 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1317 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1318
1319 if (hists__filter_entry_by_symbol(hists, h))
1320 continue;
1321
1322 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL);
1323 }
1324}
1325
1182int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) 1326int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
1183{ 1327{
1184 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); 1328 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index f55f0a8d1f81..2cae9df40e04 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -32,6 +32,7 @@ struct events_stats {
32 u32 nr_unknown_events; 32 u32 nr_unknown_events;
33 u32 nr_invalid_chains; 33 u32 nr_invalid_chains;
34 u32 nr_unknown_id; 34 u32 nr_unknown_id;
35 u32 nr_unprocessable_samples;
35}; 36};
36 37
37enum hist_column { 38enum hist_column {
@@ -41,6 +42,11 @@ enum hist_column {
41 HISTC_COMM, 42 HISTC_COMM,
42 HISTC_PARENT, 43 HISTC_PARENT,
43 HISTC_CPU, 44 HISTC_CPU,
45 HISTC_MISPREDICT,
46 HISTC_SYMBOL_FROM,
47 HISTC_SYMBOL_TO,
48 HISTC_DSO_FROM,
49 HISTC_DSO_TO,
44 HISTC_NR_COLS, /* Last entry */ 50 HISTC_NR_COLS, /* Last entry */
45}; 51};
46 52
@@ -55,6 +61,8 @@ struct hists {
55 u64 nr_entries; 61 u64 nr_entries;
56 const struct thread *thread_filter; 62 const struct thread *thread_filter;
57 const struct dso *dso_filter; 63 const struct dso *dso_filter;
64 const char *uid_filter_str;
65 const char *symbol_filter_str;
58 pthread_mutex_t lock; 66 pthread_mutex_t lock;
59 struct events_stats stats; 67 struct events_stats stats;
60 u64 event_stream; 68 u64 event_stream;
@@ -72,6 +80,12 @@ int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
72 struct hists *hists); 80 struct hists *hists);
73void hist_entry__free(struct hist_entry *); 81void hist_entry__free(struct hist_entry *);
74 82
83struct hist_entry *__hists__add_branch_entry(struct hists *self,
84 struct addr_location *al,
85 struct symbol *sym_parent,
86 struct branch_info *bi,
87 u64 period);
88
75void hists__output_resort(struct hists *self); 89void hists__output_resort(struct hists *self);
76void hists__output_resort_threaded(struct hists *hists); 90void hists__output_resort_threaded(struct hists *hists);
77void hists__collapse_resort(struct hists *self); 91void hists__collapse_resort(struct hists *self);
@@ -94,6 +108,7 @@ int hist_entry__annotate(struct hist_entry *self, size_t privsize);
94 108
95void hists__filter_by_dso(struct hists *hists); 109void hists__filter_by_dso(struct hists *hists);
96void hists__filter_by_thread(struct hists *hists); 110void hists__filter_by_thread(struct hists *hists);
111void hists__filter_by_symbol(struct hists *hists);
97 112
98u16 hists__col_len(struct hists *self, enum hist_column col); 113u16 hists__col_len(struct hists *self, enum hist_column col);
99void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 114void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
@@ -132,6 +147,23 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
132 int refresh); 147 int refresh);
133#endif 148#endif
134 149
150#ifdef NO_GTK2_SUPPORT
151static inline
152int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __used,
153 const char *help __used,
154 void(*timer)(void *arg) __used,
155 void *arg __used,
156 int refresh __used)
157{
158 return 0;
159}
160
161#else
162int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
163 void(*timer)(void *arg), void *arg,
164 int refresh);
165#endif
166
135unsigned int hists__sort_list_width(struct hists *self); 167unsigned int hists__sort_list_width(struct hists *self);
136 168
137#endif /* __PERF_HIST_H */ 169#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/dwarf2.h b/tools/perf/util/include/asm/dwarf2.h
index bb4198e7837a..afe38199e922 100644
--- a/tools/perf/util/include/asm/dwarf2.h
+++ b/tools/perf/util/include/asm/dwarf2.h
@@ -2,10 +2,12 @@
2#ifndef PERF_DWARF2_H 2#ifndef PERF_DWARF2_H
3#define PERF_DWARF2_H 3#define PERF_DWARF2_H
4 4
5/* dwarf2.h ... dummy header file for including arch/x86/lib/memcpy_64.S */ 5/* dwarf2.h ... dummy header file for including arch/x86/lib/mem{cpy,set}_64.S */
6 6
7#define CFI_STARTPROC 7#define CFI_STARTPROC
8#define CFI_ENDPROC 8#define CFI_ENDPROC
9#define CFI_REMEMBER_STATE
10#define CFI_RESTORE_STATE
9 11
10#endif /* PERF_DWARF2_H */ 12#endif /* PERF_DWARF2_H */
11 13
diff --git a/tools/perf/util/include/asm/unistd_32.h b/tools/perf/util/include/asm/unistd_32.h
new file mode 100644
index 000000000000..8b137891791f
--- /dev/null
+++ b/tools/perf/util/include/asm/unistd_32.h
@@ -0,0 +1 @@
diff --git a/tools/perf/util/include/asm/unistd_64.h b/tools/perf/util/include/asm/unistd_64.h
new file mode 100644
index 000000000000..8b137891791f
--- /dev/null
+++ b/tools/perf/util/include/asm/unistd_64.h
@@ -0,0 +1 @@
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index eda4416efa0a..bb162e40c76c 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -5,6 +5,8 @@
5#include <linux/bitops.h> 5#include <linux/bitops.h>
6 6
7int __bitmap_weight(const unsigned long *bitmap, int bits); 7int __bitmap_weight(const unsigned long *bitmap, int bits);
8void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
9 const unsigned long *bitmap2, int bits);
8 10
9#define BITMAP_LAST_WORD_MASK(nbits) \ 11#define BITMAP_LAST_WORD_MASK(nbits) \
10( \ 12( \
@@ -32,4 +34,13 @@ static inline int bitmap_weight(const unsigned long *src, int nbits)
32 return __bitmap_weight(src, nbits); 34 return __bitmap_weight(src, nbits);
33} 35}
34 36
37static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
38 const unsigned long *src2, int nbits)
39{
40 if (small_const_nbits(nbits))
41 *dst = *src1 | *src2;
42 else
43 __bitmap_or(dst, src1, src2, nbits);
44}
45
35#endif /* _PERF_BITOPS_H */ 46#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index 62cdee78db7b..f1584833bd22 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -15,7 +15,7 @@
15 (bit) = find_next_bit((addr), (size), (bit) + 1)) 15 (bit) = find_next_bit((addr), (size), (bit) + 1))
16 16
17/* same as for_each_set_bit() but use bit as value to start with */ 17/* same as for_each_set_bit() but use bit as value to start with */
18#define for_each_set_bit_cont(bit, addr, size) \ 18#define for_each_set_bit_from(bit, addr, size) \
19 for ((bit) = find_next_bit((addr), (size), (bit)); \ 19 for ((bit) = find_next_bit((addr), (size), (bit)); \
20 (bit) < (size); \ 20 (bit) < (size); \
21 (bit) = find_next_bit((addr), (size), (bit) + 1)) 21 (bit) = find_next_bit((addr), (size), (bit) + 1))
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/export.h
index b43e2dc21e04..b43e2dc21e04 100644
--- a/tools/perf/util/include/linux/module.h
+++ b/tools/perf/util/include/linux/export.h
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 316aa0ab7122..35ae56864e4f 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -38,6 +38,7 @@ void map__init(struct map *self, enum map_type type,
38 RB_CLEAR_NODE(&self->rb_node); 38 RB_CLEAR_NODE(&self->rb_node);
39 self->groups = NULL; 39 self->groups = NULL;
40 self->referenced = false; 40 self->referenced = false;
41 self->erange_warned = false;
41} 42}
42 43
43struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 44struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
@@ -212,6 +213,21 @@ size_t map__fprintf(struct map *self, FILE *fp)
212 self->start, self->end, self->pgoff, self->dso->name); 213 self->start, self->end, self->pgoff, self->dso->name);
213} 214}
214 215
216size_t map__fprintf_dsoname(struct map *map, FILE *fp)
217{
218 const char *dsoname;
219
220 if (map && map->dso && (map->dso->name || map->dso->long_name)) {
221 if (symbol_conf.show_kernel_path && map->dso->long_name)
222 dsoname = map->dso->long_name;
223 else if (map->dso->name)
224 dsoname = map->dso->name;
225 } else
226 dsoname = "[unknown]";
227
228 return fprintf(fp, "%s", dsoname);
229}
230
215/* 231/*
216 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 232 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
217 * map->dso->adjust_symbols==1 for ET_EXEC-like cases. 233 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 2b8017f8a930..81371bad4ef0 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -33,6 +33,7 @@ struct map {
33 u64 end; 33 u64 end;
34 u8 /* enum map_type */ type; 34 u8 /* enum map_type */ type;
35 bool referenced; 35 bool referenced;
36 bool erange_warned;
36 u32 priv; 37 u32 priv;
37 u64 pgoff; 38 u64 pgoff;
38 39
@@ -118,6 +119,7 @@ void map__delete(struct map *self);
118struct map *map__clone(struct map *self); 119struct map *map__clone(struct map *self);
119int map__overlap(struct map *l, struct map *r); 120int map__overlap(struct map *l, struct map *r);
120size_t map__fprintf(struct map *self, FILE *fp); 121size_t map__fprintf(struct map *self, FILE *fp);
122size_t map__fprintf_dsoname(struct map *map, FILE *fp);
121 123
122int map__load(struct map *self, symbol_filter_t filter); 124int map__load(struct map *self, symbol_filter_t filter);
123struct symbol *map__find_symbol(struct map *self, 125struct symbol *map__find_symbol(struct map *self,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b029296d20d9..5b3a0ef4e232 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,10 @@
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
13#include "debugfs.h" 13#include "debugfs.h"
14#include "parse-events-flex.h"
15#include "pmu.h"
16
17#define MAX_NAME_LEN 100
14 18
15struct event_symbol { 19struct event_symbol {
16 u8 type; 20 u8 type;
@@ -19,11 +23,8 @@ struct event_symbol {
19 const char *alias; 23 const char *alias;
20}; 24};
21 25
22enum event_result { 26int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
23 EVT_FAILED, 27 int *idx);
24 EVT_HANDLED,
25 EVT_HANDLED_ALL
26};
27 28
28#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 29#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
29#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 30#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -165,7 +166,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
165 struct tracepoint_path *path = NULL; 166 struct tracepoint_path *path = NULL;
166 DIR *sys_dir, *evt_dir; 167 DIR *sys_dir, *evt_dir;
167 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 168 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
168 char id_buf[4]; 169 char id_buf[24];
169 int fd; 170 int fd;
170 u64 id; 171 u64 id;
171 char evt_path[MAXPATHLEN]; 172 char evt_path[MAXPATHLEN];
@@ -354,7 +355,24 @@ const char *__event_name(int type, u64 config)
354 return "unknown"; 355 return "unknown";
355} 356}
356 357
357static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size) 358static int add_event(struct list_head *list, int *idx,
359 struct perf_event_attr *attr, char *name)
360{
361 struct perf_evsel *evsel;
362
363 event_attr_init(attr);
364
365 evsel = perf_evsel__new(attr, (*idx)++);
366 if (!evsel)
367 return -ENOMEM;
368
369 list_add_tail(&evsel->node, list);
370
371 evsel->name = strdup(name);
372 return 0;
373}
374
375static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
358{ 376{
359 int i, j; 377 int i, j;
360 int n, longest = -1; 378 int n, longest = -1;
@@ -362,58 +380,57 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int
362 for (i = 0; i < size; i++) { 380 for (i = 0; i < size; i++) {
363 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { 381 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
364 n = strlen(names[i][j]); 382 n = strlen(names[i][j]);
365 if (n > longest && !strncasecmp(*str, names[i][j], n)) 383 if (n > longest && !strncasecmp(str, names[i][j], n))
366 longest = n; 384 longest = n;
367 } 385 }
368 if (longest > 0) { 386 if (longest > 0)
369 *str += longest;
370 return i; 387 return i;
371 }
372 } 388 }
373 389
374 return -1; 390 return -1;
375} 391}
376 392
377static enum event_result 393int parse_events_add_cache(struct list_head *list, int *idx,
378parse_generic_hw_event(const char **str, struct perf_event_attr *attr) 394 char *type, char *op_result1, char *op_result2)
379{ 395{
380 const char *s = *str; 396 struct perf_event_attr attr;
397 char name[MAX_NAME_LEN];
381 int cache_type = -1, cache_op = -1, cache_result = -1; 398 int cache_type = -1, cache_op = -1, cache_result = -1;
399 char *op_result[2] = { op_result1, op_result2 };
400 int i, n;
382 401
383 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
384 /* 402 /*
385 * No fallback - if we cannot get a clear cache type 403 * No fallback - if we cannot get a clear cache type
386 * then bail out: 404 * then bail out:
387 */ 405 */
406 cache_type = parse_aliases(type, hw_cache,
407 PERF_COUNT_HW_CACHE_MAX);
388 if (cache_type == -1) 408 if (cache_type == -1)
389 return EVT_FAILED; 409 return -EINVAL;
410
411 n = snprintf(name, MAX_NAME_LEN, "%s", type);
412
413 for (i = 0; (i < 2) && (op_result[i]); i++) {
414 char *str = op_result[i];
390 415
391 while ((cache_op == -1 || cache_result == -1) && *s == '-') { 416 snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
392 ++s;
393 417
394 if (cache_op == -1) { 418 if (cache_op == -1) {
395 cache_op = parse_aliases(&s, hw_cache_op, 419 cache_op = parse_aliases(str, hw_cache_op,
396 PERF_COUNT_HW_CACHE_OP_MAX); 420 PERF_COUNT_HW_CACHE_OP_MAX);
397 if (cache_op >= 0) { 421 if (cache_op >= 0) {
398 if (!is_cache_op_valid(cache_type, cache_op)) 422 if (!is_cache_op_valid(cache_type, cache_op))
399 return EVT_FAILED; 423 return -EINVAL;
400 continue; 424 continue;
401 } 425 }
402 } 426 }
403 427
404 if (cache_result == -1) { 428 if (cache_result == -1) {
405 cache_result = parse_aliases(&s, hw_cache_result, 429 cache_result = parse_aliases(str, hw_cache_result,
406 PERF_COUNT_HW_CACHE_RESULT_MAX); 430 PERF_COUNT_HW_CACHE_RESULT_MAX);
407 if (cache_result >= 0) 431 if (cache_result >= 0)
408 continue; 432 continue;
409 } 433 }
410
411 /*
412 * Can't parse this as a cache op or result, so back up
413 * to the '-'.
414 */
415 --s;
416 break;
417 } 434 }
418 435
419 /* 436 /*
@@ -428,20 +445,17 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
428 if (cache_result == -1) 445 if (cache_result == -1)
429 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; 446 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
430 447
431 attr->config = cache_type | (cache_op << 8) | (cache_result << 16); 448 memset(&attr, 0, sizeof(attr));
432 attr->type = PERF_TYPE_HW_CACHE; 449 attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
433 450 attr.type = PERF_TYPE_HW_CACHE;
434 *str = s; 451 return add_event(list, idx, &attr, name);
435 return EVT_HANDLED;
436} 452}
437 453
438static enum event_result 454static int add_tracepoint(struct list_head *list, int *idx,
439parse_single_tracepoint_event(char *sys_name, 455 char *sys_name, char *evt_name)
440 const char *evt_name,
441 unsigned int evt_length,
442 struct perf_event_attr *attr,
443 const char **strp)
444{ 456{
457 struct perf_event_attr attr;
458 char name[MAX_NAME_LEN];
445 char evt_path[MAXPATHLEN]; 459 char evt_path[MAXPATHLEN];
446 char id_buf[4]; 460 char id_buf[4];
447 u64 id; 461 u64 id;
@@ -452,130 +466,80 @@ parse_single_tracepoint_event(char *sys_name,
452 466
453 fd = open(evt_path, O_RDONLY); 467 fd = open(evt_path, O_RDONLY);
454 if (fd < 0) 468 if (fd < 0)
455 return EVT_FAILED; 469 return -1;
456 470
457 if (read(fd, id_buf, sizeof(id_buf)) < 0) { 471 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
458 close(fd); 472 close(fd);
459 return EVT_FAILED; 473 return -1;
460 } 474 }
461 475
462 close(fd); 476 close(fd);
463 id = atoll(id_buf); 477 id = atoll(id_buf);
464 attr->config = id;
465 attr->type = PERF_TYPE_TRACEPOINT;
466 *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
467
468 attr->sample_type |= PERF_SAMPLE_RAW;
469 attr->sample_type |= PERF_SAMPLE_TIME;
470 attr->sample_type |= PERF_SAMPLE_CPU;
471 478
472 attr->sample_period = 1; 479 memset(&attr, 0, sizeof(attr));
480 attr.config = id;
481 attr.type = PERF_TYPE_TRACEPOINT;
482 attr.sample_type |= PERF_SAMPLE_RAW;
483 attr.sample_type |= PERF_SAMPLE_TIME;
484 attr.sample_type |= PERF_SAMPLE_CPU;
485 attr.sample_period = 1;
473 486
474 487 snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
475 return EVT_HANDLED; 488 return add_event(list, idx, &attr, name);
476} 489}
477 490
478/* sys + ':' + event + ':' + flags*/ 491static int add_tracepoint_multi(struct list_head *list, int *idx,
479#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 492 char *sys_name, char *evt_name)
480static enum event_result
481parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
482 const char *evt_exp, char *flags)
483{ 493{
484 char evt_path[MAXPATHLEN]; 494 char evt_path[MAXPATHLEN];
485 struct dirent *evt_ent; 495 struct dirent *evt_ent;
486 DIR *evt_dir; 496 DIR *evt_dir;
497 int ret = 0;
487 498
488 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); 499 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
489 evt_dir = opendir(evt_path); 500 evt_dir = opendir(evt_path);
490
491 if (!evt_dir) { 501 if (!evt_dir) {
492 perror("Can't open event dir"); 502 perror("Can't open event dir");
493 return EVT_FAILED; 503 return -1;
494 } 504 }
495 505
496 while ((evt_ent = readdir(evt_dir))) { 506 while (!ret && (evt_ent = readdir(evt_dir))) {
497 char event_opt[MAX_EVOPT_LEN + 1];
498 int len;
499
500 if (!strcmp(evt_ent->d_name, ".") 507 if (!strcmp(evt_ent->d_name, ".")
501 || !strcmp(evt_ent->d_name, "..") 508 || !strcmp(evt_ent->d_name, "..")
502 || !strcmp(evt_ent->d_name, "enable") 509 || !strcmp(evt_ent->d_name, "enable")
503 || !strcmp(evt_ent->d_name, "filter")) 510 || !strcmp(evt_ent->d_name, "filter"))
504 continue; 511 continue;
505 512
506 if (!strglobmatch(evt_ent->d_name, evt_exp)) 513 if (!strglobmatch(evt_ent->d_name, evt_name))
507 continue; 514 continue;
508 515
509 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 516 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
510 evt_ent->d_name, flags ? ":" : "",
511 flags ?: "");
512 if (len < 0)
513 return EVT_FAILED;
514
515 if (parse_events(evlist, event_opt, 0))
516 return EVT_FAILED;
517 } 517 }
518 518
519 return EVT_HANDLED_ALL; 519 return ret;
520} 520}
521 521
522static enum event_result 522int parse_events_add_tracepoint(struct list_head *list, int *idx,
523parse_tracepoint_event(struct perf_evlist *evlist, const char **strp, 523 char *sys, char *event)
524 struct perf_event_attr *attr)
525{ 524{
526 const char *evt_name; 525 int ret;
527 char *flags = NULL, *comma_loc;
528 char sys_name[MAX_EVENT_LENGTH];
529 unsigned int sys_length, evt_length;
530
531 if (debugfs_valid_mountpoint(tracing_events_path))
532 return 0;
533
534 evt_name = strchr(*strp, ':');
535 if (!evt_name)
536 return EVT_FAILED;
537
538 sys_length = evt_name - *strp;
539 if (sys_length >= MAX_EVENT_LENGTH)
540 return 0;
541 526
542 strncpy(sys_name, *strp, sys_length); 527 ret = debugfs_valid_mountpoint(tracing_events_path);
543 sys_name[sys_length] = '\0'; 528 if (ret)
544 evt_name = evt_name + 1; 529 return ret;
545 530
546 comma_loc = strchr(evt_name, ','); 531 return strpbrk(event, "*?") ?
547 if (comma_loc) { 532 add_tracepoint_multi(list, idx, sys, event) :
548 /* take the event name up to the comma */ 533 add_tracepoint(list, idx, sys, event);
549 evt_name = strndup(evt_name, comma_loc - evt_name);
550 }
551 flags = strchr(evt_name, ':');
552 if (flags) {
553 /* split it out: */
554 evt_name = strndup(evt_name, flags - evt_name);
555 flags++;
556 }
557
558 evt_length = strlen(evt_name);
559 if (evt_length >= MAX_EVENT_LENGTH)
560 return EVT_FAILED;
561 if (strpbrk(evt_name, "*?")) {
562 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
563 return parse_multiple_tracepoint_event(evlist, sys_name,
564 evt_name, flags);
565 } else {
566 return parse_single_tracepoint_event(sys_name, evt_name,
567 evt_length, attr, strp);
568 }
569} 534}
570 535
571static enum event_result 536static int
572parse_breakpoint_type(const char *type, const char **strp, 537parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
573 struct perf_event_attr *attr)
574{ 538{
575 int i; 539 int i;
576 540
577 for (i = 0; i < 3; i++) { 541 for (i = 0; i < 3; i++) {
578 if (!type[i]) 542 if (!type || !type[i])
579 break; 543 break;
580 544
581 switch (type[i]) { 545 switch (type[i]) {
@@ -589,164 +553,146 @@ parse_breakpoint_type(const char *type, const char **strp,
589 attr->bp_type |= HW_BREAKPOINT_X; 553 attr->bp_type |= HW_BREAKPOINT_X;
590 break; 554 break;
591 default: 555 default:
592 return EVT_FAILED; 556 return -EINVAL;
593 } 557 }
594 } 558 }
559
595 if (!attr->bp_type) /* Default */ 560 if (!attr->bp_type) /* Default */
596 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; 561 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
597 562
598 *strp = type + i; 563 return 0;
599
600 return EVT_HANDLED;
601} 564}
602 565
603static enum event_result 566int parse_events_add_breakpoint(struct list_head *list, int *idx,
604parse_breakpoint_event(const char **strp, struct perf_event_attr *attr) 567 void *ptr, char *type)
605{ 568{
606 const char *target; 569 struct perf_event_attr attr;
607 const char *type; 570 char name[MAX_NAME_LEN];
608 char *endaddr;
609 u64 addr;
610 enum event_result err;
611
612 target = strchr(*strp, ':');
613 if (!target)
614 return EVT_FAILED;
615
616 if (strncmp(*strp, "mem", target - *strp) != 0)
617 return EVT_FAILED;
618
619 target++;
620
621 addr = strtoull(target, &endaddr, 0);
622 if (target == endaddr)
623 return EVT_FAILED;
624
625 attr->bp_addr = addr;
626 *strp = endaddr;
627 571
628 type = strchr(target, ':'); 572 memset(&attr, 0, sizeof(attr));
573 attr.bp_addr = (unsigned long) ptr;
629 574
630 /* If no type is defined, just rw as default */ 575 if (parse_breakpoint_type(type, &attr))
631 if (!type) { 576 return -EINVAL;
632 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
633 } else {
634 err = parse_breakpoint_type(++type, strp, attr);
635 if (err == EVT_FAILED)
636 return EVT_FAILED;
637 }
638 577
639 /* 578 /*
640 * We should find a nice way to override the access length 579 * We should find a nice way to override the access length
641 * Provide some defaults for now 580 * Provide some defaults for now
642 */ 581 */
643 if (attr->bp_type == HW_BREAKPOINT_X) 582 if (attr.bp_type == HW_BREAKPOINT_X)
644 attr->bp_len = sizeof(long); 583 attr.bp_len = sizeof(long);
645 else 584 else
646 attr->bp_len = HW_BREAKPOINT_LEN_4; 585 attr.bp_len = HW_BREAKPOINT_LEN_4;
647 586
648 attr->type = PERF_TYPE_BREAKPOINT; 587 attr.type = PERF_TYPE_BREAKPOINT;
649 588
650 return EVT_HANDLED; 589 snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
590 return add_event(list, idx, &attr, name);
651} 591}
652 592
653static int check_events(const char *str, unsigned int i) 593static int config_term(struct perf_event_attr *attr,
594 struct parse_events__term *term)
654{ 595{
655 int n; 596 switch (term->type) {
597 case PARSE_EVENTS__TERM_TYPE_CONFIG:
598 attr->config = term->val.num;
599 break;
600 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
601 attr->config1 = term->val.num;
602 break;
603 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
604 attr->config2 = term->val.num;
605 break;
606 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
607 attr->sample_period = term->val.num;
608 break;
609 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
610 /*
611 * TODO uncomment when the field is available
612 * attr->branch_sample_type = term->val.num;
613 */
614 break;
615 default:
616 return -EINVAL;
617 }
618 return 0;
619}
656 620
657 n = strlen(event_symbols[i].symbol); 621static int config_attr(struct perf_event_attr *attr,
658 if (!strncasecmp(str, event_symbols[i].symbol, n)) 622 struct list_head *head, int fail)
659 return n; 623{
624 struct parse_events__term *term;
660 625
661 n = strlen(event_symbols[i].alias); 626 list_for_each_entry(term, head, list)
662 if (n) { 627 if (config_term(attr, term) && fail)
663 if (!strncasecmp(str, event_symbols[i].alias, n)) 628 return -EINVAL;
664 return n;
665 }
666 629
667 return 0; 630 return 0;
668} 631}
669 632
670static enum event_result 633int parse_events_add_numeric(struct list_head *list, int *idx,
671parse_symbolic_event(const char **strp, struct perf_event_attr *attr) 634 unsigned long type, unsigned long config,
635 struct list_head *head_config)
672{ 636{
673 const char *str = *strp; 637 struct perf_event_attr attr;
674 unsigned int i; 638
675 int n; 639 memset(&attr, 0, sizeof(attr));
676 640 attr.type = type;
677 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 641 attr.config = config;
678 n = check_events(str, i); 642
679 if (n > 0) { 643 if (head_config &&
680 attr->type = event_symbols[i].type; 644 config_attr(&attr, head_config, 1))
681 attr->config = event_symbols[i].config; 645 return -EINVAL;
682 *strp = str + n; 646
683 return EVT_HANDLED; 647 return add_event(list, idx, &attr,
684 } 648 (char *) __event_name(type, config));
685 }
686 return EVT_FAILED;
687} 649}
688 650
689static enum event_result 651int parse_events_add_pmu(struct list_head *list, int *idx,
690parse_raw_event(const char **strp, struct perf_event_attr *attr) 652 char *name, struct list_head *head_config)
691{ 653{
692 const char *str = *strp; 654 struct perf_event_attr attr;
693 u64 config; 655 struct perf_pmu *pmu;
694 int n; 656
695 657 pmu = perf_pmu__find(name);
696 if (*str != 'r') 658 if (!pmu)
697 return EVT_FAILED; 659 return -EINVAL;
698 n = hex2u64(str + 1, &config); 660
699 if (n > 0) { 661 memset(&attr, 0, sizeof(attr));
700 const char *end = str + n + 1; 662
701 if (*end != '\0' && *end != ',' && *end != ':') 663 /*
702 return EVT_FAILED; 664 * Configure hardcoded terms first, no need to check
703 665 * return value when called with fail == 0 ;)
704 *strp = end; 666 */
705 attr->type = PERF_TYPE_RAW; 667 config_attr(&attr, head_config, 0);
706 attr->config = config; 668
707 return EVT_HANDLED; 669 if (perf_pmu__config(pmu, &attr, head_config))
708 } 670 return -EINVAL;
709 return EVT_FAILED; 671
672 return add_event(list, idx, &attr, (char *) "pmu");
710} 673}
711 674
712static enum event_result 675void parse_events_update_lists(struct list_head *list_event,
713parse_numeric_event(const char **strp, struct perf_event_attr *attr) 676 struct list_head *list_all)
714{ 677{
715 const char *str = *strp; 678 /*
716 char *endp; 679 * Called for single event definition. Update the
717 unsigned long type; 680 * 'all event' list, and reinit the 'signle event'
718 u64 config; 681 * list, for next event definition.
719 682 */
720 type = strtoul(str, &endp, 0); 683 list_splice_tail(list_event, list_all);
721 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') { 684 INIT_LIST_HEAD(list_event);
722 str = endp + 1;
723 config = strtoul(str, &endp, 0);
724 if (endp > str) {
725 attr->type = type;
726 attr->config = config;
727 *strp = endp;
728 return EVT_HANDLED;
729 }
730 }
731 return EVT_FAILED;
732} 685}
733 686
734static int 687int parse_events_modifier(struct list_head *list, char *str)
735parse_event_modifier(const char **strp, struct perf_event_attr *attr)
736{ 688{
737 const char *str = *strp; 689 struct perf_evsel *evsel;
738 int exclude = 0, exclude_GH = 0; 690 int exclude = 0, exclude_GH = 0;
739 int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0; 691 int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0;
740 692
741 if (!*str) 693 if (str == NULL)
742 return 0; 694 return 0;
743 695
744 if (*str == ',')
745 return 0;
746
747 if (*str++ != ':')
748 return -1;
749
750 while (*str) { 696 while (*str) {
751 if (*str == 'u') { 697 if (*str == 'u') {
752 if (!exclude) 698 if (!exclude)
@@ -775,111 +721,62 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
775 721
776 ++str; 722 ++str;
777 } 723 }
778 if (str < *strp + 2)
779 return -1;
780 724
781 *strp = str; 725 /*
726 * precise ip:
727 *
728 * 0 - SAMPLE_IP can have arbitrary skid
729 * 1 - SAMPLE_IP must have constant skid
730 * 2 - SAMPLE_IP requested to have 0 skid
731 * 3 - SAMPLE_IP must have 0 skid
732 *
733 * See also PERF_RECORD_MISC_EXACT_IP
734 */
735 if (precise > 3)
736 return -EINVAL;
782 737
783 attr->exclude_user = eu; 738 list_for_each_entry(evsel, list, node) {
784 attr->exclude_kernel = ek; 739 evsel->attr.exclude_user = eu;
785 attr->exclude_hv = eh; 740 evsel->attr.exclude_kernel = ek;
786 attr->precise_ip = precise; 741 evsel->attr.exclude_hv = eh;
787 attr->exclude_host = eH; 742 evsel->attr.precise_ip = precise;
788 attr->exclude_guest = eG; 743 evsel->attr.exclude_host = eH;
744 evsel->attr.exclude_guest = eG;
745 }
789 746
790 return 0; 747 return 0;
791} 748}
792 749
793/* 750int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
794 * Each event can have multiple symbolic names.
795 * Symbolic names are (almost) exactly matched.
796 */
797static enum event_result
798parse_event_symbols(struct perf_evlist *evlist, const char **str,
799 struct perf_event_attr *attr)
800{ 751{
801 enum event_result ret; 752 LIST_HEAD(list);
802 753 LIST_HEAD(list_tmp);
803 ret = parse_tracepoint_event(evlist, str, attr); 754 YY_BUFFER_STATE buffer;
804 if (ret != EVT_FAILED) 755 int ret, idx = evlist->nr_entries;
805 goto modifier;
806
807 ret = parse_raw_event(str, attr);
808 if (ret != EVT_FAILED)
809 goto modifier;
810 756
811 ret = parse_numeric_event(str, attr); 757 buffer = parse_events__scan_string(str);
812 if (ret != EVT_FAILED)
813 goto modifier;
814 758
815 ret = parse_symbolic_event(str, attr); 759 ret = parse_events_parse(&list, &list_tmp, &idx);
816 if (ret != EVT_FAILED)
817 goto modifier;
818 760
819 ret = parse_generic_hw_event(str, attr); 761 parse_events__flush_buffer(buffer);
820 if (ret != EVT_FAILED) 762 parse_events__delete_buffer(buffer);
821 goto modifier;
822 763
823 ret = parse_breakpoint_event(str, attr); 764 if (!ret) {
824 if (ret != EVT_FAILED) 765 int entries = idx - evlist->nr_entries;
825 goto modifier; 766 perf_evlist__splice_list_tail(evlist, &list, entries);
826 767 return 0;
827 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
828 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
829 return EVT_FAILED;
830
831modifier:
832 if (parse_event_modifier(str, attr) < 0) {
833 fprintf(stderr, "invalid event modifier: '%s'\n", *str);
834 fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
835
836 return EVT_FAILED;
837 } 768 }
838 769
770 /*
771 * There are 2 users - builtin-record and builtin-test objects.
772 * Both call perf_evlist__delete in case of error, so we dont
773 * need to bother.
774 */
775 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
776 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
839 return ret; 777 return ret;
840} 778}
841 779
842int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
843{
844 struct perf_event_attr attr;
845 enum event_result ret;
846 const char *ostr;
847
848 for (;;) {
849 ostr = str;
850 memset(&attr, 0, sizeof(attr));
851 event_attr_init(&attr);
852 ret = parse_event_symbols(evlist, &str, &attr);
853 if (ret == EVT_FAILED)
854 return -1;
855
856 if (!(*str == 0 || *str == ',' || isspace(*str)))
857 return -1;
858
859 if (ret != EVT_HANDLED_ALL) {
860 struct perf_evsel *evsel;
861 evsel = perf_evsel__new(&attr, evlist->nr_entries);
862 if (evsel == NULL)
863 return -1;
864 perf_evlist__add(evlist, evsel);
865
866 evsel->name = calloc(str - ostr + 1, 1);
867 if (!evsel->name)
868 return -1;
869 strncpy(evsel->name, ostr, str - ostr);
870 }
871
872 if (*str == 0)
873 break;
874 if (*str == ',')
875 ++str;
876 while (isspace(*str))
877 ++str;
878 }
879
880 return 0;
881}
882
883int parse_events_option(const struct option *opt, const char *str, 780int parse_events_option(const struct option *opt, const char *str,
884 int unset __used) 781 int unset __used)
885{ 782{
@@ -1052,8 +949,6 @@ int print_hwcache_events(const char *event_glob)
1052 return printed; 949 return printed;
1053} 950}
1054 951
1055#define MAX_NAME_LEN 100
1056
1057/* 952/*
1058 * Print the help text for the event symbols: 953 * Print the help text for the event symbols:
1059 */ 954 */
@@ -1102,8 +997,12 @@ void print_events(const char *event_glob)
1102 997
1103 printf("\n"); 998 printf("\n");
1104 printf(" %-50s [%s]\n", 999 printf(" %-50s [%s]\n",
1105 "rNNN (see 'perf list --help' on how to encode it)", 1000 "rNNN",
1106 event_type_descriptors[PERF_TYPE_RAW]); 1001 event_type_descriptors[PERF_TYPE_RAW]);
1002 printf(" %-50s [%s]\n",
1003 "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
1004 event_type_descriptors[PERF_TYPE_RAW]);
1005 printf(" (see 'perf list --help' on how to encode it)\n");
1107 printf("\n"); 1006 printf("\n");
1108 1007
1109 printf(" %-50s [%s]\n", 1008 printf(" %-50s [%s]\n",
@@ -1113,3 +1012,51 @@ void print_events(const char *event_glob)
1113 1012
1114 print_tracepoint_events(NULL, NULL); 1013 print_tracepoint_events(NULL, NULL);
1115} 1014}
1015
1016int parse_events__is_hardcoded_term(struct parse_events__term *term)
1017{
1018 return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX;
1019}
1020
1021int parse_events__new_term(struct parse_events__term **_term, int type,
1022 char *config, char *str, long num)
1023{
1024 struct parse_events__term *term;
1025
1026 term = zalloc(sizeof(*term));
1027 if (!term)
1028 return -ENOMEM;
1029
1030 INIT_LIST_HEAD(&term->list);
1031 term->type = type;
1032 term->config = config;
1033
1034 switch (type) {
1035 case PARSE_EVENTS__TERM_TYPE_CONFIG:
1036 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
1037 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
1038 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
1039 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
1040 case PARSE_EVENTS__TERM_TYPE_NUM:
1041 term->val.num = num;
1042 break;
1043 case PARSE_EVENTS__TERM_TYPE_STR:
1044 term->val.str = str;
1045 break;
1046 default:
1047 return -EINVAL;
1048 }
1049
1050 *_term = term;
1051 return 0;
1052}
1053
1054void parse_events__free_terms(struct list_head *terms)
1055{
1056 struct parse_events__term *term, *h;
1057
1058 list_for_each_entry_safe(term, h, terms, list)
1059 free(term);
1060
1061 free(terms);
1062}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 7e0cbe75d5f1..ca069f893381 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,55 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
33 33
34#define EVENTS_HELP_MAX (128*1024) 34#define EVENTS_HELP_MAX (128*1024)
35 35
36enum {
37 PARSE_EVENTS__TERM_TYPE_CONFIG,
38 PARSE_EVENTS__TERM_TYPE_CONFIG1,
39 PARSE_EVENTS__TERM_TYPE_CONFIG2,
40 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
41 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
42 PARSE_EVENTS__TERM_TYPE_NUM,
43 PARSE_EVENTS__TERM_TYPE_STR,
44
45 PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
46 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
47};
48
49struct parse_events__term {
50 char *config;
51 union {
52 char *str;
53 long num;
54 } val;
55 int type;
56
57 struct list_head list;
58};
59
60int parse_events__is_hardcoded_term(struct parse_events__term *term);
61int parse_events__new_term(struct parse_events__term **term, int type,
62 char *config, char *str, long num);
63void parse_events__free_terms(struct list_head *terms);
64int parse_events_modifier(struct list_head *list __used, char *str __used);
65int parse_events_add_tracepoint(struct list_head *list, int *idx,
66 char *sys, char *event);
67int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config,
68 unsigned long config1, unsigned long config2,
69 char *mod);
70int parse_events_add_numeric(struct list_head *list, int *idx,
71 unsigned long type, unsigned long config,
72 struct list_head *head_config);
73int parse_events_add_cache(struct list_head *list, int *idx,
74 char *type, char *op_result1, char *op_result2);
75int parse_events_add_breakpoint(struct list_head *list, int *idx,
76 void *ptr, char *type);
77int parse_events_add_pmu(struct list_head *list, int *idx,
78 char *pmu , struct list_head *head_config);
79void parse_events_update_lists(struct list_head *list_event,
80 struct list_head *list_all);
81void parse_events_error(struct list_head *list_all,
82 struct list_head *list_event,
83 int *idx, char const *msg);
84
36void print_events(const char *event_glob); 85void print_events(const char *event_glob);
37void print_events_type(u8 type); 86void print_events_type(u8 type);
38void print_tracepoint_events(const char *subsys_glob, const char *event_glob); 87void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
new file mode 100644
index 000000000000..05d766e3ecb5
--- /dev/null
+++ b/tools/perf/util/parse-events.l
@@ -0,0 +1,127 @@
1
2%option prefix="parse_events_"
3
4%{
5#include <errno.h>
6#include "../perf.h"
7#include "parse-events-bison.h"
8#include "parse-events.h"
9
10static int __value(char *str, int base, int token)
11{
12 long num;
13
14 errno = 0;
15 num = strtoul(str, NULL, base);
16 if (errno)
17 return PE_ERROR;
18
19 parse_events_lval.num = num;
20 return token;
21}
22
23static int value(int base)
24{
25 return __value(parse_events_text, base, PE_VALUE);
26}
27
28static int raw(void)
29{
30 return __value(parse_events_text + 1, 16, PE_RAW);
31}
32
33static int str(int token)
34{
35 parse_events_lval.str = strdup(parse_events_text);
36 return token;
37}
38
39static int sym(int type, int config)
40{
41 parse_events_lval.num = (type << 16) + config;
42 return PE_VALUE_SYM;
43}
44
45static int term(int type)
46{
47 parse_events_lval.num = type;
48 return PE_TERM;
49}
50
51%}
52
53num_dec [0-9]+
54num_hex 0x[a-fA-F0-9]+
55num_raw_hex [a-fA-F0-9]+
56name [a-zA-Z_*?][a-zA-Z0-9_*?]*
57modifier_event [ukhp]{1,5}
58modifier_bp [rwx]
59
60%%
61cpu-cycles|cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
62stalled-cycles-frontend|idle-cycles-frontend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
63stalled-cycles-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
64instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
65cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
66cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
67branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
68branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
69bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
70ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
71cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
72task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
73page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
74minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
75major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
76context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
77cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
78alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
79emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
80
81L1-dcache|l1-d|l1d|L1-data |
82L1-icache|l1-i|l1i|L1-instruction |
83LLC|L2 |
84dTLB|d-tlb|Data-TLB |
85iTLB|i-tlb|Instruction-TLB |
86branch|branches|bpu|btb|bpc |
87node { return str(PE_NAME_CACHE_TYPE); }
88
89load|loads|read |
90store|stores|write |
91prefetch|prefetches |
92speculative-read|speculative-load |
93refs|Reference|ops|access |
94misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
95
96 /*
97 * These are event config hardcoded term names to be specified
98 * within xxx/.../ syntax. So far we dont clash with other names,
99 * so we can put them here directly. In case the we have a conflict
100 * in future, this needs to go into '//' condition block.
101 */
102config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
103config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
104config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
105period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
106branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
107
108mem: { return PE_PREFIX_MEM; }
109r{num_raw_hex} { return raw(); }
110{num_dec} { return value(10); }
111{num_hex} { return value(16); }
112
113{modifier_event} { return str(PE_MODIFIER_EVENT); }
114{modifier_bp} { return str(PE_MODIFIER_BP); }
115{name} { return str(PE_NAME); }
116"/" { return '/'; }
117- { return '-'; }
118, { return ','; }
119: { return ':'; }
120= { return '='; }
121
122%%
123
124int parse_events_wrap(void)
125{
126 return 1;
127}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
new file mode 100644
index 000000000000..d9637da7333c
--- /dev/null
+++ b/tools/perf/util/parse-events.y
@@ -0,0 +1,229 @@
1
2%name-prefix "parse_events_"
3%parse-param {struct list_head *list_all}
4%parse-param {struct list_head *list_event}
5%parse-param {int *idx}
6
7%{
8
9#define YYDEBUG 1
10
11#include <linux/compiler.h>
12#include <linux/list.h>
13#include "types.h"
14#include "util.h"
15#include "parse-events.h"
16
17extern int parse_events_lex (void);
18
19#define ABORT_ON(val) \
20do { \
21 if (val) \
22 YYABORT; \
23} while (0)
24
25%}
26
27%token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM
28%token PE_NAME
29%token PE_MODIFIER_EVENT PE_MODIFIER_BP
30%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
31%token PE_PREFIX_MEM PE_PREFIX_RAW
32%token PE_ERROR
33%type <num> PE_VALUE
34%type <num> PE_VALUE_SYM
35%type <num> PE_RAW
36%type <num> PE_TERM
37%type <str> PE_NAME
38%type <str> PE_NAME_CACHE_TYPE
39%type <str> PE_NAME_CACHE_OP_RESULT
40%type <str> PE_MODIFIER_EVENT
41%type <str> PE_MODIFIER_BP
42%type <head> event_config
43%type <term> event_term
44
45%union
46{
47 char *str;
48 unsigned long num;
49 struct list_head *head;
50 struct parse_events__term *term;
51}
52%%
53
54events:
55events ',' event | event
56
57event:
58event_def PE_MODIFIER_EVENT
59{
60 /*
61 * Apply modifier on all events added by single event definition
62 * (there could be more events added for multiple tracepoint
63 * definitions via '*?'.
64 */
65 ABORT_ON(parse_events_modifier(list_event, $2));
66 parse_events_update_lists(list_event, list_all);
67}
68|
69event_def
70{
71 parse_events_update_lists(list_event, list_all);
72}
73
74event_def: event_pmu |
75 event_legacy_symbol |
76 event_legacy_cache sep_dc |
77 event_legacy_mem |
78 event_legacy_tracepoint sep_dc |
79 event_legacy_numeric sep_dc |
80 event_legacy_raw sep_dc
81
82event_pmu:
83PE_NAME '/' event_config '/'
84{
85 ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
86 parse_events__free_terms($3);
87}
88
89event_legacy_symbol:
90PE_VALUE_SYM '/' event_config '/'
91{
92 int type = $1 >> 16;
93 int config = $1 & 255;
94
95 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
96 parse_events__free_terms($3);
97}
98|
99PE_VALUE_SYM sep_slash_dc
100{
101 int type = $1 >> 16;
102 int config = $1 & 255;
103
104 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
105}
106
107event_legacy_cache:
108PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
109{
110 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
111}
112|
113PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
114{
115 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
116}
117|
118PE_NAME_CACHE_TYPE
119{
120 ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL));
121}
122
123event_legacy_mem:
124PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
125{
126 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
127}
128|
129PE_PREFIX_MEM PE_VALUE sep_dc
130{
131 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
132}
133
134event_legacy_tracepoint:
135PE_NAME ':' PE_NAME
136{
137 ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
138}
139
140event_legacy_numeric:
141PE_VALUE ':' PE_VALUE
142{
143 ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
144}
145
146event_legacy_raw:
147PE_RAW
148{
149 ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
150}
151
152event_config:
153event_config ',' event_term
154{
155 struct list_head *head = $1;
156 struct parse_events__term *term = $3;
157
158 ABORT_ON(!head);
159 list_add_tail(&term->list, head);
160 $$ = $1;
161}
162|
163event_term
164{
165 struct list_head *head = malloc(sizeof(*head));
166 struct parse_events__term *term = $1;
167
168 ABORT_ON(!head);
169 INIT_LIST_HEAD(head);
170 list_add_tail(&term->list, head);
171 $$ = head;
172}
173
174event_term:
175PE_NAME '=' PE_NAME
176{
177 struct parse_events__term *term;
178
179 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
180 $1, $3, 0));
181 $$ = term;
182}
183|
184PE_NAME '=' PE_VALUE
185{
186 struct parse_events__term *term;
187
188 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
189 $1, NULL, $3));
190 $$ = term;
191}
192|
193PE_NAME
194{
195 struct parse_events__term *term;
196
197 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
198 $1, NULL, 1));
199 $$ = term;
200}
201|
202PE_TERM '=' PE_VALUE
203{
204 struct parse_events__term *term;
205
206 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3));
207 $$ = term;
208}
209|
210PE_TERM
211{
212 struct parse_events__term *term;
213
214 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1));
215 $$ = term;
216}
217
218sep_dc: ':' |
219
220sep_slash_dc: '/' | ':' |
221
222%%
223
224void parse_events_error(struct list_head *list_all __used,
225 struct list_head *list_event __used,
226 int *idx __used,
227 char const *msg __used)
228{
229}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
new file mode 100644
index 000000000000..cb08a118e811
--- /dev/null
+++ b/tools/perf/util/pmu.c
@@ -0,0 +1,469 @@
1
2#include <linux/list.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <unistd.h>
6#include <stdio.h>
7#include <dirent.h>
8#include "sysfs.h"
9#include "util.h"
10#include "pmu.h"
11#include "parse-events.h"
12
13int perf_pmu_parse(struct list_head *list, char *name);
14extern FILE *perf_pmu_in;
15
16static LIST_HEAD(pmus);
17
18/*
19 * Parse & process all the sysfs attributes located under
20 * the directory specified in 'dir' parameter.
21 */
22static int pmu_format_parse(char *dir, struct list_head *head)
23{
24 struct dirent *evt_ent;
25 DIR *format_dir;
26 int ret = 0;
27
28 format_dir = opendir(dir);
29 if (!format_dir)
30 return -EINVAL;
31
32 while (!ret && (evt_ent = readdir(format_dir))) {
33 char path[PATH_MAX];
34 char *name = evt_ent->d_name;
35 FILE *file;
36
37 if (!strcmp(name, ".") || !strcmp(name, ".."))
38 continue;
39
40 snprintf(path, PATH_MAX, "%s/%s", dir, name);
41
42 ret = -EINVAL;
43 file = fopen(path, "r");
44 if (!file)
45 break;
46
47 perf_pmu_in = file;
48 ret = perf_pmu_parse(head, name);
49 fclose(file);
50 }
51
52 closedir(format_dir);
53 return ret;
54}
55
56/*
57 * Reading/parsing the default pmu format definition, which should be
58 * located at:
59 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
60 */
61static int pmu_format(char *name, struct list_head *format)
62{
63 struct stat st;
64 char path[PATH_MAX];
65 const char *sysfs;
66
67 sysfs = sysfs_find_mountpoint();
68 if (!sysfs)
69 return -1;
70
71 snprintf(path, PATH_MAX,
72 "%s/bus/event_source/devices/%s/format", sysfs, name);
73
74 if (stat(path, &st) < 0)
75 return -1;
76
77 if (pmu_format_parse(path, format))
78 return -1;
79
80 return 0;
81}
82
83/*
84 * Reading/parsing the default pmu type value, which should be
85 * located at:
86 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
87 */
88static int pmu_type(char *name, __u32 *type)
89{
90 struct stat st;
91 char path[PATH_MAX];
92 const char *sysfs;
93 FILE *file;
94 int ret = 0;
95
96 sysfs = sysfs_find_mountpoint();
97 if (!sysfs)
98 return -1;
99
100 snprintf(path, PATH_MAX,
101 "%s/bus/event_source/devices/%s/type", sysfs, name);
102
103 if (stat(path, &st) < 0)
104 return -1;
105
106 file = fopen(path, "r");
107 if (!file)
108 return -EINVAL;
109
110 if (1 != fscanf(file, "%u", type))
111 ret = -1;
112
113 fclose(file);
114 return ret;
115}
116
117static struct perf_pmu *pmu_lookup(char *name)
118{
119 struct perf_pmu *pmu;
120 LIST_HEAD(format);
121 __u32 type;
122
123 /*
124 * The pmu data we store & need consists of the pmu
125 * type value and format definitions. Load both right
126 * now.
127 */
128 if (pmu_format(name, &format))
129 return NULL;
130
131 if (pmu_type(name, &type))
132 return NULL;
133
134 pmu = zalloc(sizeof(*pmu));
135 if (!pmu)
136 return NULL;
137
138 INIT_LIST_HEAD(&pmu->format);
139 list_splice(&format, &pmu->format);
140 pmu->name = strdup(name);
141 pmu->type = type;
142 return pmu;
143}
144
145static struct perf_pmu *pmu_find(char *name)
146{
147 struct perf_pmu *pmu;
148
149 list_for_each_entry(pmu, &pmus, list)
150 if (!strcmp(pmu->name, name))
151 return pmu;
152
153 return NULL;
154}
155
156struct perf_pmu *perf_pmu__find(char *name)
157{
158 struct perf_pmu *pmu;
159
160 /*
161 * Once PMU is loaded it stays in the list,
162 * so we keep us from multiple reading/parsing
163 * the pmu format definitions.
164 */
165 pmu = pmu_find(name);
166 if (pmu)
167 return pmu;
168
169 return pmu_lookup(name);
170}
171
172static struct perf_pmu__format*
173pmu_find_format(struct list_head *formats, char *name)
174{
175 struct perf_pmu__format *format;
176
177 list_for_each_entry(format, formats, list)
178 if (!strcmp(format->name, name))
179 return format;
180
181 return NULL;
182}
183
184/*
185 * Returns value based on the format definition (format parameter)
186 * and unformated value (value parameter).
187 *
188 * TODO maybe optimize a little ;)
189 */
190static __u64 pmu_format_value(unsigned long *format, __u64 value)
191{
192 unsigned long fbit, vbit;
193 __u64 v = 0;
194
195 for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
196
197 if (!test_bit(fbit, format))
198 continue;
199
200 if (!(value & (1llu << vbit++)))
201 continue;
202
203 v |= (1llu << fbit);
204 }
205
206 return v;
207}
208
209/*
210 * Setup one of config[12] attr members based on the
211 * user input data - temr parameter.
212 */
213static int pmu_config_term(struct list_head *formats,
214 struct perf_event_attr *attr,
215 struct parse_events__term *term)
216{
217 struct perf_pmu__format *format;
218 __u64 *vp;
219
220 /*
221 * Support only for hardcoded and numnerial terms.
222 * Hardcoded terms should be already in, so nothing
223 * to be done for them.
224 */
225 if (parse_events__is_hardcoded_term(term))
226 return 0;
227
228 if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
229 return -EINVAL;
230
231 format = pmu_find_format(formats, term->config);
232 if (!format)
233 return -EINVAL;
234
235 switch (format->value) {
236 case PERF_PMU_FORMAT_VALUE_CONFIG:
237 vp = &attr->config;
238 break;
239 case PERF_PMU_FORMAT_VALUE_CONFIG1:
240 vp = &attr->config1;
241 break;
242 case PERF_PMU_FORMAT_VALUE_CONFIG2:
243 vp = &attr->config2;
244 break;
245 default:
246 return -EINVAL;
247 }
248
249 *vp |= pmu_format_value(format->bits, term->val.num);
250 return 0;
251}
252
253static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
254 struct list_head *head_terms)
255{
256 struct parse_events__term *term, *h;
257
258 list_for_each_entry_safe(term, h, head_terms, list)
259 if (pmu_config_term(formats, attr, term))
260 return -EINVAL;
261
262 return 0;
263}
264
265/*
266 * Configures event's 'attr' parameter based on the:
267 * 1) users input - specified in terms parameter
268 * 2) pmu format definitions - specified by pmu parameter
269 */
270int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
271 struct list_head *head_terms)
272{
273 attr->type = pmu->type;
274 return pmu_config(&pmu->format, attr, head_terms);
275}
276
277int perf_pmu__new_format(struct list_head *list, char *name,
278 int config, unsigned long *bits)
279{
280 struct perf_pmu__format *format;
281
282 format = zalloc(sizeof(*format));
283 if (!format)
284 return -ENOMEM;
285
286 format->name = strdup(name);
287 format->value = config;
288 memcpy(format->bits, bits, sizeof(format->bits));
289
290 list_add_tail(&format->list, list);
291 return 0;
292}
293
294void perf_pmu__set_format(unsigned long *bits, long from, long to)
295{
296 long b;
297
298 if (!to)
299 to = from;
300
301 memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
302 for (b = from; b <= to; b++)
303 set_bit(b, bits);
304}
305
306/* Simulated format definitions. */
307static struct test_format {
308 const char *name;
309 const char *value;
310} test_formats[] = {
311 { "krava01", "config:0-1,62-63\n", },
312 { "krava02", "config:10-17\n", },
313 { "krava03", "config:5\n", },
314 { "krava11", "config1:0,2,4,6,8,20-28\n", },
315 { "krava12", "config1:63\n", },
316 { "krava13", "config1:45-47\n", },
317 { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
318 { "krava22", "config2:8,18,48,58\n", },
319 { "krava23", "config2:28-29,38\n", },
320};
321
322#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
323
324/* Simulated users input. */
325static struct parse_events__term test_terms[] = {
326 {
327 .config = (char *) "krava01",
328 .val.num = 15,
329 .type = PARSE_EVENTS__TERM_TYPE_NUM,
330 },
331 {
332 .config = (char *) "krava02",
333 .val.num = 170,
334 .type = PARSE_EVENTS__TERM_TYPE_NUM,
335 },
336 {
337 .config = (char *) "krava03",
338 .val.num = 1,
339 .type = PARSE_EVENTS__TERM_TYPE_NUM,
340 },
341 {
342 .config = (char *) "krava11",
343 .val.num = 27,
344 .type = PARSE_EVENTS__TERM_TYPE_NUM,
345 },
346 {
347 .config = (char *) "krava12",
348 .val.num = 1,
349 .type = PARSE_EVENTS__TERM_TYPE_NUM,
350 },
351 {
352 .config = (char *) "krava13",
353 .val.num = 2,
354 .type = PARSE_EVENTS__TERM_TYPE_NUM,
355 },
356 {
357 .config = (char *) "krava21",
358 .val.num = 119,
359 .type = PARSE_EVENTS__TERM_TYPE_NUM,
360 },
361 {
362 .config = (char *) "krava22",
363 .val.num = 11,
364 .type = PARSE_EVENTS__TERM_TYPE_NUM,
365 },
366 {
367 .config = (char *) "krava23",
368 .val.num = 2,
369 .type = PARSE_EVENTS__TERM_TYPE_NUM,
370 },
371};
372#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
373
374/*
375 * Prepare format directory data, exported by kernel
376 * at /sys/bus/event_source/devices/<dev>/format.
377 */
378static char *test_format_dir_get(void)
379{
380 static char dir[PATH_MAX];
381 unsigned int i;
382
383 snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
384 if (!mkdtemp(dir))
385 return NULL;
386
387 for (i = 0; i < TEST_FORMATS_CNT; i++) {
388 static char name[PATH_MAX];
389 struct test_format *format = &test_formats[i];
390 FILE *file;
391
392 snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
393
394 file = fopen(name, "w");
395 if (!file)
396 return NULL;
397
398 if (1 != fwrite(format->value, strlen(format->value), 1, file))
399 break;
400
401 fclose(file);
402 }
403
404 return dir;
405}
406
407/* Cleanup format directory. */
408static int test_format_dir_put(char *dir)
409{
410 char buf[PATH_MAX];
411 snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
412 if (system(buf))
413 return -1;
414
415 snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
416 return system(buf);
417}
418
419static struct list_head *test_terms_list(void)
420{
421 static LIST_HEAD(terms);
422 unsigned int i;
423
424 for (i = 0; i < TERMS_CNT; i++)
425 list_add_tail(&test_terms[i].list, &terms);
426
427 return &terms;
428}
429
430#undef TERMS_CNT
431
432int perf_pmu__test(void)
433{
434 char *format = test_format_dir_get();
435 LIST_HEAD(formats);
436 struct list_head *terms = test_terms_list();
437 int ret;
438
439 if (!format)
440 return -EINVAL;
441
442 do {
443 struct perf_event_attr attr;
444
445 memset(&attr, 0, sizeof(attr));
446
447 ret = pmu_format_parse(format, &formats);
448 if (ret)
449 break;
450
451 ret = pmu_config(&formats, &attr, terms);
452 if (ret)
453 break;
454
455 ret = -EINVAL;
456
457 if (attr.config != 0xc00000000002a823)
458 break;
459 if (attr.config1 != 0x8000400000000145)
460 break;
461 if (attr.config2 != 0x0400000020041d07)
462 break;
463
464 ret = 0;
465 } while (0);
466
467 test_format_dir_put(format);
468 return ret;
469}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
new file mode 100644
index 000000000000..68c0db965e1f
--- /dev/null
+++ b/tools/perf/util/pmu.h
@@ -0,0 +1,41 @@
1#ifndef __PMU_H
2#define __PMU_H
3
4#include <linux/bitops.h>
5#include "../../../include/linux/perf_event.h"
6
7enum {
8 PERF_PMU_FORMAT_VALUE_CONFIG,
9 PERF_PMU_FORMAT_VALUE_CONFIG1,
10 PERF_PMU_FORMAT_VALUE_CONFIG2,
11};
12
13#define PERF_PMU_FORMAT_BITS 64
14
15struct perf_pmu__format {
16 char *name;
17 int value;
18 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
19 struct list_head list;
20};
21
22struct perf_pmu {
23 char *name;
24 __u32 type;
25 struct list_head format;
26 struct list_head list;
27};
28
29struct perf_pmu *perf_pmu__find(char *name);
30int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
31 struct list_head *head_terms);
32
33int perf_pmu_wrap(void);
34void perf_pmu_error(struct list_head *list, char *name, char const *msg);
35
36int perf_pmu__new_format(struct list_head *list, char *name,
37 int config, unsigned long *bits);
38void perf_pmu__set_format(unsigned long *bits, long from, long to);
39
40int perf_pmu__test(void);
41#endif /* __PMU_H */
diff --git a/tools/perf/util/pmu.l b/tools/perf/util/pmu.l
new file mode 100644
index 000000000000..a15d9fbd7c0e
--- /dev/null
+++ b/tools/perf/util/pmu.l
@@ -0,0 +1,43 @@
1%option prefix="perf_pmu_"
2
3%{
4#include <stdlib.h>
5#include <linux/bitops.h>
6#include "pmu.h"
7#include "pmu-bison.h"
8
9static int value(int base)
10{
11 long num;
12
13 errno = 0;
14 num = strtoul(perf_pmu_text, NULL, base);
15 if (errno)
16 return PP_ERROR;
17
18 perf_pmu_lval.num = num;
19 return PP_VALUE;
20}
21
22%}
23
24num_dec [0-9]+
25
26%%
27
28{num_dec} { return value(10); }
29config { return PP_CONFIG; }
30config1 { return PP_CONFIG1; }
31config2 { return PP_CONFIG2; }
32- { return '-'; }
33: { return ':'; }
34, { return ','; }
35. { ; }
36\n { ; }
37
38%%
39
40int perf_pmu_wrap(void)
41{
42 return 1;
43}
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
new file mode 100644
index 000000000000..20ea77e93169
--- /dev/null
+++ b/tools/perf/util/pmu.y
@@ -0,0 +1,93 @@
1
2%name-prefix "perf_pmu_"
3%parse-param {struct list_head *format}
4%parse-param {char *name}
5
6%{
7
8#include <linux/compiler.h>
9#include <linux/list.h>
10#include <linux/bitmap.h>
11#include <string.h>
12#include "pmu.h"
13
14extern int perf_pmu_lex (void);
15
16#define ABORT_ON(val) \
17do { \
18 if (val) \
19 YYABORT; \
20} while (0)
21
22%}
23
24%token PP_CONFIG PP_CONFIG1 PP_CONFIG2
25%token PP_VALUE PP_ERROR
26%type <num> PP_VALUE
27%type <bits> bit_term
28%type <bits> bits
29
30%union
31{
32 unsigned long num;
33 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
34}
35
36%%
37
38format:
39format format_term
40|
41format_term
42
43format_term:
44PP_CONFIG ':' bits
45{
46 ABORT_ON(perf_pmu__new_format(format, name,
47 PERF_PMU_FORMAT_VALUE_CONFIG,
48 $3));
49}
50|
51PP_CONFIG1 ':' bits
52{
53 ABORT_ON(perf_pmu__new_format(format, name,
54 PERF_PMU_FORMAT_VALUE_CONFIG1,
55 $3));
56}
57|
58PP_CONFIG2 ':' bits
59{
60 ABORT_ON(perf_pmu__new_format(format, name,
61 PERF_PMU_FORMAT_VALUE_CONFIG2,
62 $3));
63}
64
65bits:
66bits ',' bit_term
67{
68 bitmap_or($$, $1, $3, 64);
69}
70|
71bit_term
72{
73 memcpy($$, $1, sizeof($1));
74}
75
76bit_term:
77PP_VALUE '-' PP_VALUE
78{
79 perf_pmu__set_format($$, $1, $3);
80}
81|
82PP_VALUE
83{
84 perf_pmu__set_format($$, $1, 0);
85}
86
87%%
88
89void perf_pmu_error(struct list_head *list __used,
90 char *name __used,
91 char const *msg __used)
92{
93}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index e33554a562b3..8a8ee64e72d1 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -34,7 +34,6 @@
34 34
35#include "util.h" 35#include "util.h"
36#include "event.h" 36#include "event.h"
37#include "string.h"
38#include "strlist.h" 37#include "strlist.h"
39#include "debug.h" 38#include "debug.h"
40#include "cache.h" 39#include "cache.h"
@@ -273,10 +272,10 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
273/* Try to find perf_probe_event with debuginfo */ 272/* Try to find perf_probe_event with debuginfo */
274static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 273static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
275 struct probe_trace_event **tevs, 274 struct probe_trace_event **tevs,
276 int max_tevs, const char *module) 275 int max_tevs, const char *target)
277{ 276{
278 bool need_dwarf = perf_probe_event_need_dwarf(pev); 277 bool need_dwarf = perf_probe_event_need_dwarf(pev);
279 struct debuginfo *dinfo = open_debuginfo(module); 278 struct debuginfo *dinfo = open_debuginfo(target);
280 int ntevs, ret = 0; 279 int ntevs, ret = 0;
281 280
282 if (!dinfo) { 281 if (!dinfo) {
@@ -295,9 +294,9 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
295 294
296 if (ntevs > 0) { /* Succeeded to find trace events */ 295 if (ntevs > 0) { /* Succeeded to find trace events */
297 pr_debug("find %d probe_trace_events.\n", ntevs); 296 pr_debug("find %d probe_trace_events.\n", ntevs);
298 if (module) 297 if (target)
299 ret = add_module_to_probe_trace_events(*tevs, ntevs, 298 ret = add_module_to_probe_trace_events(*tevs, ntevs,
300 module); 299 target);
301 return ret < 0 ? ret : ntevs; 300 return ret < 0 ? ret : ntevs;
302 } 301 }
303 302
@@ -1729,7 +1728,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1729 } 1728 }
1730 1729
1731 ret = 0; 1730 ret = 0;
1732 printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":"); 1731 printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
1733 for (i = 0; i < ntevs; i++) { 1732 for (i = 0; i < ntevs; i++) {
1734 tev = &tevs[i]; 1733 tev = &tevs[i];
1735 if (pev->event) 1734 if (pev->event)
@@ -1784,7 +1783,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1784 1783
1785 if (ret >= 0) { 1784 if (ret >= 0) {
1786 /* Show how to use the event. */ 1785 /* Show how to use the event. */
1787 printf("\nYou can now use it on all perf tools, such as:\n\n"); 1786 printf("\nYou can now use it in all perf tools, such as:\n\n");
1788 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 1787 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
1789 tev->event); 1788 tev->event);
1790 } 1789 }
@@ -1796,14 +1795,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1796 1795
1797static int convert_to_probe_trace_events(struct perf_probe_event *pev, 1796static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1798 struct probe_trace_event **tevs, 1797 struct probe_trace_event **tevs,
1799 int max_tevs, const char *module) 1798 int max_tevs, const char *target)
1800{ 1799{
1801 struct symbol *sym; 1800 struct symbol *sym;
1802 int ret = 0, i; 1801 int ret = 0, i;
1803 struct probe_trace_event *tev; 1802 struct probe_trace_event *tev;
1804 1803
1805 /* Convert perf_probe_event with debuginfo */ 1804 /* Convert perf_probe_event with debuginfo */
1806 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); 1805 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
1807 if (ret != 0) 1806 if (ret != 0)
1808 return ret; /* Found in debuginfo or got an error */ 1807 return ret; /* Found in debuginfo or got an error */
1809 1808
@@ -1819,8 +1818,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1819 goto error; 1818 goto error;
1820 } 1819 }
1821 1820
1822 if (module) { 1821 if (target) {
1823 tev->point.module = strdup(module); 1822 tev->point.module = strdup(target);
1824 if (tev->point.module == NULL) { 1823 if (tev->point.module == NULL) {
1825 ret = -ENOMEM; 1824 ret = -ENOMEM;
1826 goto error; 1825 goto error;
@@ -1890,7 +1889,7 @@ struct __event_package {
1890}; 1889};
1891 1890
1892int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 1891int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1893 int max_tevs, const char *module, bool force_add) 1892 int max_tevs, const char *target, bool force_add)
1894{ 1893{
1895 int i, j, ret; 1894 int i, j, ret;
1896 struct __event_package *pkgs; 1895 struct __event_package *pkgs;
@@ -1913,7 +1912,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1913 ret = convert_to_probe_trace_events(pkgs[i].pev, 1912 ret = convert_to_probe_trace_events(pkgs[i].pev,
1914 &pkgs[i].tevs, 1913 &pkgs[i].tevs,
1915 max_tevs, 1914 max_tevs,
1916 module); 1915 target);
1917 if (ret < 0) 1916 if (ret < 0)
1918 goto end; 1917 goto end;
1919 pkgs[i].ntevs = ret; 1918 pkgs[i].ntevs = ret;
@@ -1965,7 +1964,7 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
1965 goto error; 1964 goto error;
1966 } 1965 }
1967 1966
1968 printf("Remove event: %s\n", ent->s); 1967 printf("Removed event: %s\n", ent->s);
1969 return 0; 1968 return 0;
1970error: 1969error:
1971 pr_warning("Failed to delete event: %s\n", strerror(-ret)); 1970 pr_warning("Failed to delete event: %s\n", strerror(-ret));
@@ -2069,7 +2068,7 @@ static int filter_available_functions(struct map *map __unused,
2069 return 1; 2068 return 1;
2070} 2069}
2071 2070
2072int show_available_funcs(const char *module, struct strfilter *_filter) 2071int show_available_funcs(const char *target, struct strfilter *_filter)
2073{ 2072{
2074 struct map *map; 2073 struct map *map;
2075 int ret; 2074 int ret;
@@ -2080,9 +2079,9 @@ int show_available_funcs(const char *module, struct strfilter *_filter)
2080 if (ret < 0) 2079 if (ret < 0)
2081 return ret; 2080 return ret;
2082 2081
2083 map = kernel_get_module_map(module); 2082 map = kernel_get_module_map(target);
2084 if (!map) { 2083 if (!map) {
2085 pr_err("Failed to find %s map.\n", (module) ? : "kernel"); 2084 pr_err("Failed to find %s map.\n", (target) ? : "kernel");
2086 return -EINVAL; 2085 return -EINVAL;
2087 } 2086 }
2088 available_func_filter = _filter; 2087 available_func_filter = _filter;
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 74bd2e63c4b4..d448984ed789 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -30,7 +30,6 @@
30#include <stdlib.h> 30#include <stdlib.h>
31#include <string.h> 31#include <string.h>
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h>
34#include <dwarf-regs.h> 33#include <dwarf-regs.h>
35 34
36#include <linux/bitops.h> 35#include <linux/bitops.h>
@@ -973,10 +972,12 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
973 struct dwarf_callback_param *param = data; 972 struct dwarf_callback_param *param = data;
974 struct probe_finder *pf = param->data; 973 struct probe_finder *pf = param->data;
975 struct perf_probe_point *pp = &pf->pev->point; 974 struct perf_probe_point *pp = &pf->pev->point;
975 Dwarf_Attribute attr;
976 976
977 /* Check tag and diename */ 977 /* Check tag and diename */
978 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 978 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
979 !die_compare_name(sp_die, pp->function)) 979 !die_compare_name(sp_die, pp->function) ||
980 dwarf_attr(sp_die, DW_AT_declaration, &attr))
980 return DWARF_CB_OK; 981 return DWARF_CB_OK;
981 982
982 /* Check declared file */ 983 /* Check declared file */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
new file mode 100644
index 000000000000..2884e67ee625
--- /dev/null
+++ b/tools/perf/util/python-ext-sources
@@ -0,0 +1,19 @@
1#
2# List of files needed by perf python extention
3#
4# Each source file must be placed on its own line so that it can be
5# processed by Makefile and util/setup.py accordingly.
6#
7
8util/python.c
9util/ctype.c
10util/evlist.c
11util/evsel.c
12util/cpumap.c
13util/thread_map.c
14util/util.c
15util/xyarray.c
16util/cgroup.c
17util/debugfs.c
18util/strlist.c
19../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 9dd47a4f2596..e03b58a48424 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -425,14 +425,14 @@ struct pyrf_thread_map {
425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, 425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
426 PyObject *args, PyObject *kwargs) 426 PyObject *args, PyObject *kwargs)
427{ 427{
428 static char *kwlist[] = { "pid", "tid", NULL }; 428 static char *kwlist[] = { "pid", "tid", "uid", NULL };
429 int pid = -1, tid = -1; 429 int pid = -1, tid = -1, uid = UINT_MAX;
430 430
431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", 431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii",
432 kwlist, &pid, &tid)) 432 kwlist, &pid, &tid, &uid))
433 return -1; 433 return -1;
434 434
435 pthreads->threads = thread_map__new(pid, tid); 435 pthreads->threads = thread_map__new(pid, tid, uid);
436 if (pthreads->threads == NULL) 436 if (pthreads->threads == NULL)
437 return -1; 437 return -1;
438 return 0; 438 return 0;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 0b2a48783172..c2623c6f9b51 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -24,7 +24,6 @@
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <string.h> 26#include <string.h>
27#include <ctype.h>
28#include <errno.h> 27#include <errno.h>
29 28
30#include "../../perf.h" 29#include "../../perf.h"
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index b5ca2558c7bb..1efd3bee6336 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force)
24 self->fd = STDIN_FILENO; 24 self->fd = STDIN_FILENO;
25 25
26 if (perf_session__read_header(self, self->fd) < 0) 26 if (perf_session__read_header(self, self->fd) < 0)
27 pr_err("incompatible file format"); 27 pr_err("incompatible file format (rerun with -v to learn more)");
28 28
29 return 0; 29 return 0;
30 } 30 }
@@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force)
56 } 56 }
57 57
58 if (perf_session__read_header(self, self->fd) < 0) { 58 if (perf_session__read_header(self, self->fd) < 0) {
59 pr_err("incompatible file format"); 59 pr_err("incompatible file format (rerun with -v to learn more)");
60 goto out_close; 60 goto out_close;
61 } 61 }
62 62
@@ -140,6 +140,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
140 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 140 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
141 INIT_LIST_HEAD(&self->ordered_samples.to_free); 141 INIT_LIST_HEAD(&self->ordered_samples.to_free);
142 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 142 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
143 hists__init(&self->hists);
143 144
144 if (mode == O_RDONLY) { 145 if (mode == O_RDONLY) {
145 if (perf_session__open(self, force) < 0) 146 if (perf_session__open(self, force) < 0)
@@ -229,6 +230,64 @@ static bool symbol__match_parent_regex(struct symbol *sym)
229 return 0; 230 return 0;
230} 231}
231 232
233static const u8 cpumodes[] = {
234 PERF_RECORD_MISC_USER,
235 PERF_RECORD_MISC_KERNEL,
236 PERF_RECORD_MISC_GUEST_USER,
237 PERF_RECORD_MISC_GUEST_KERNEL
238};
239#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
240
241static void ip__resolve_ams(struct machine *self, struct thread *thread,
242 struct addr_map_symbol *ams,
243 u64 ip)
244{
245 struct addr_location al;
246 size_t i;
247 u8 m;
248
249 memset(&al, 0, sizeof(al));
250
251 for (i = 0; i < NCPUMODES; i++) {
252 m = cpumodes[i];
253 /*
254 * We cannot use the header.misc hint to determine whether a
255 * branch stack address is user, kernel, guest, hypervisor.
256 * Branches may straddle the kernel/user/hypervisor boundaries.
257 * Thus, we have to try consecutively until we find a match
258 * or else, the symbol is unknown
259 */
260 thread__find_addr_location(thread, self, m, MAP__FUNCTION,
261 ip, &al, NULL);
262 if (al.sym)
263 goto found;
264 }
265found:
266 ams->addr = ip;
267 ams->al_addr = al.addr;
268 ams->sym = al.sym;
269 ams->map = al.map;
270}
271
272struct branch_info *machine__resolve_bstack(struct machine *self,
273 struct thread *thr,
274 struct branch_stack *bs)
275{
276 struct branch_info *bi;
277 unsigned int i;
278
279 bi = calloc(bs->nr, sizeof(struct branch_info));
280 if (!bi)
281 return NULL;
282
283 for (i = 0; i < bs->nr; i++) {
284 ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
285 ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
286 bi[i].flags = bs->entries[i].flags;
287 }
288 return bi;
289}
290
232int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, 291int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
233 struct thread *thread, 292 struct thread *thread,
234 struct ip_callchain *chain, 293 struct ip_callchain *chain,
@@ -697,6 +756,18 @@ static void callchain__printf(struct perf_sample *sample)
697 i, sample->callchain->ips[i]); 756 i, sample->callchain->ips[i]);
698} 757}
699 758
759static void branch_stack__printf(struct perf_sample *sample)
760{
761 uint64_t i;
762
763 printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr);
764
765 for (i = 0; i < sample->branch_stack->nr; i++)
766 printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 "\n",
767 i, sample->branch_stack->entries[i].from,
768 sample->branch_stack->entries[i].to);
769}
770
700static void perf_session__print_tstamp(struct perf_session *session, 771static void perf_session__print_tstamp(struct perf_session *session,
701 union perf_event *event, 772 union perf_event *event,
702 struct perf_sample *sample) 773 struct perf_sample *sample)
@@ -744,6 +815,9 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
744 815
745 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) 816 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
746 callchain__printf(sample); 817 callchain__printf(sample);
818
819 if (session->sample_type & PERF_SAMPLE_BRANCH_STACK)
820 branch_stack__printf(sample);
747} 821}
748 822
749static struct machine * 823static struct machine *
@@ -752,8 +826,16 @@ static struct machine *
752{ 826{
753 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 827 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
754 828
755 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) 829 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
756 return perf_session__find_machine(session, event->ip.pid); 830 u32 pid;
831
832 if (event->header.type == PERF_RECORD_MMAP)
833 pid = event->mmap.pid;
834 else
835 pid = event->ip.pid;
836
837 return perf_session__find_machine(session, pid);
838 }
757 839
758 return perf_session__find_host_machine(session); 840 return perf_session__find_host_machine(session);
759} 841}
@@ -794,7 +876,11 @@ static int perf_session_deliver_event(struct perf_session *session,
794 dump_sample(session, event, sample); 876 dump_sample(session, event, sample);
795 if (evsel == NULL) { 877 if (evsel == NULL) {
796 ++session->hists.stats.nr_unknown_id; 878 ++session->hists.stats.nr_unknown_id;
797 return -1; 879 return 0;
880 }
881 if (machine == NULL) {
882 ++session->hists.stats.nr_unprocessable_samples;
883 return 0;
798 } 884 }
799 return tool->sample(tool, event, sample, evsel, machine); 885 return tool->sample(tool, event, sample, evsel, machine);
800 case PERF_RECORD_MMAP: 886 case PERF_RECORD_MMAP:
@@ -964,6 +1050,12 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
964 session->hists.stats.nr_invalid_chains, 1050 session->hists.stats.nr_invalid_chains,
965 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); 1051 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
966 } 1052 }
1053
1054 if (session->hists.stats.nr_unprocessable_samples != 0) {
1055 ui__warning("%u unprocessable samples recorded.\n"
1056 "Do you have a KVM guest running and not using 'perf kvm'?\n",
1057 session->hists.stats.nr_unprocessable_samples);
1058 }
967} 1059}
968 1060
969#define session_done() (*(volatile int *)(&session_done)) 1061#define session_done() (*(volatile int *)(&session_done))
@@ -1293,10 +1385,9 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1293 1385
1294void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, 1386void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1295 struct machine *machine, struct perf_evsel *evsel, 1387 struct machine *machine, struct perf_evsel *evsel,
1296 int print_sym, int print_dso) 1388 int print_sym, int print_dso, int print_symoffset)
1297{ 1389{
1298 struct addr_location al; 1390 struct addr_location al;
1299 const char *symname, *dsoname;
1300 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor; 1391 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
1301 struct callchain_cursor_node *node; 1392 struct callchain_cursor_node *node;
1302 1393
@@ -1324,20 +1415,13 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1324 1415
1325 printf("\t%16" PRIx64, node->ip); 1416 printf("\t%16" PRIx64, node->ip);
1326 if (print_sym) { 1417 if (print_sym) {
1327 if (node->sym && node->sym->name) 1418 printf(" ");
1328 symname = node->sym->name; 1419 symbol__fprintf_symname(node->sym, stdout);
1329 else
1330 symname = "";
1331
1332 printf(" %s", symname);
1333 } 1420 }
1334 if (print_dso) { 1421 if (print_dso) {
1335 if (node->map && node->map->dso && node->map->dso->name) 1422 printf(" (");
1336 dsoname = node->map->dso->name; 1423 map__fprintf_dsoname(al.map, stdout);
1337 else 1424 printf(")");
1338 dsoname = "";
1339
1340 printf(" (%s)", dsoname);
1341 } 1425 }
1342 printf("\n"); 1426 printf("\n");
1343 1427
@@ -1347,21 +1431,18 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1347 } else { 1431 } else {
1348 printf("%16" PRIx64, sample->ip); 1432 printf("%16" PRIx64, sample->ip);
1349 if (print_sym) { 1433 if (print_sym) {
1350 if (al.sym && al.sym->name) 1434 printf(" ");
1351 symname = al.sym->name; 1435 if (print_symoffset)
1436 symbol__fprintf_symname_offs(al.sym, &al,
1437 stdout);
1352 else 1438 else
1353 symname = ""; 1439 symbol__fprintf_symname(al.sym, stdout);
1354
1355 printf(" %s", symname);
1356 } 1440 }
1357 1441
1358 if (print_dso) { 1442 if (print_dso) {
1359 if (al.map && al.map->dso && al.map->dso->name) 1443 printf(" (");
1360 dsoname = al.map->dso->name; 1444 map__fprintf_dsoname(al.map, stdout);
1361 else 1445 printf(")");
1362 dsoname = "";
1363
1364 printf(" (%s)", dsoname);
1365 } 1446 }
1366 } 1447 }
1367} 1448}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 37bc38381fb6..7a5434c00565 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -73,6 +73,10 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel
73 struct ip_callchain *chain, 73 struct ip_callchain *chain,
74 struct symbol **parent); 74 struct symbol **parent);
75 75
76struct branch_info *machine__resolve_bstack(struct machine *self,
77 struct thread *thread,
78 struct branch_stack *bs);
79
76bool perf_session__has_traces(struct perf_session *self, const char *msg); 80bool perf_session__has_traces(struct perf_session *self, const char *msg);
77 81
78void mem_bswap_64(void *src, int byte_size); 82void mem_bswap_64(void *src, int byte_size);
@@ -147,7 +151,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
147 151
148void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, 152void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
149 struct machine *machine, struct perf_evsel *evsel, 153 struct machine *machine, struct perf_evsel *evsel,
150 int print_sym, int print_dso); 154 int print_sym, int print_dso, int print_symoffset);
151 155
152int perf_session__cpu_bitmap(struct perf_session *session, 156int perf_session__cpu_bitmap(struct perf_session *session,
153 const char *cpu_list, unsigned long *cpu_bitmap); 157 const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 36d4c5619575..d0f9f29cf181 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -24,11 +24,11 @@ cflags += getenv('CFLAGS', '').split()
24build_lib = getenv('PYTHON_EXTBUILD_LIB') 24build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP') 25build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26 26
27ext_sources = [f.strip() for f in file('util/python-ext-sources')
28 if len(f.strip()) > 0 and f[0] != '#']
29
27perf = Extension('perf', 30perf = Extension('perf',
28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 31 sources = ext_sources,
29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
30 'util/util.c', 'util/xyarray.c', 'util/cgroup.c',
31 'util/debugfs.c'],
32 include_dirs = ['util/include'], 32 include_dirs = ['util/include'],
33 extra_compile_args = cflags, 33 extra_compile_args = cflags,
34 ) 34 )
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 16da30d8d765..a27237430c5f 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -8,6 +8,7 @@ const char default_sort_order[] = "comm,dso,symbol";
8const char *sort_order = default_sort_order; 8const char *sort_order = default_sort_order;
9int sort__need_collapse = 0; 9int sort__need_collapse = 0;
10int sort__has_parent = 0; 10int sort__has_parent = 0;
11int sort__branch_mode = -1; /* -1 = means not set */
11 12
12enum sort_type sort__first_dimension; 13enum sort_type sort__first_dimension;
13 14
@@ -33,6 +34,9 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
33 } 34 }
34 } 35 }
35 va_end(ap); 36 va_end(ap);
37
38 if (n >= (int)size)
39 return size - 1;
36 return n; 40 return n;
37} 41}
38 42
@@ -94,6 +98,26 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
94 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 98 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
95} 99}
96 100
101static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
102{
103 struct dso *dso_l = map_l ? map_l->dso : NULL;
104 struct dso *dso_r = map_r ? map_r->dso : NULL;
105 const char *dso_name_l, *dso_name_r;
106
107 if (!dso_l || !dso_r)
108 return cmp_null(dso_l, dso_r);
109
110 if (verbose) {
111 dso_name_l = dso_l->long_name;
112 dso_name_r = dso_r->long_name;
113 } else {
114 dso_name_l = dso_l->short_name;
115 dso_name_r = dso_r->short_name;
116 }
117
118 return strcmp(dso_name_l, dso_name_r);
119}
120
97struct sort_entry sort_comm = { 121struct sort_entry sort_comm = {
98 .se_header = "Command", 122 .se_header = "Command",
99 .se_cmp = sort__comm_cmp, 123 .se_cmp = sort__comm_cmp,
@@ -107,36 +131,74 @@ struct sort_entry sort_comm = {
107static int64_t 131static int64_t
108sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
109{ 133{
110 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL; 134 return _sort__dso_cmp(left->ms.map, right->ms.map);
111 struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL; 135}
112 const char *dso_name_l, *dso_name_r;
113 136
114 if (!dso_l || !dso_r)
115 return cmp_null(dso_l, dso_r);
116 137
117 if (verbose) { 138static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
118 dso_name_l = dso_l->long_name; 139 u64 ip_l, u64 ip_r)
119 dso_name_r = dso_r->long_name; 140{
120 } else { 141 if (!sym_l || !sym_r)
121 dso_name_l = dso_l->short_name; 142 return cmp_null(sym_l, sym_r);
122 dso_name_r = dso_r->short_name; 143
144 if (sym_l == sym_r)
145 return 0;
146
147 if (sym_l)
148 ip_l = sym_l->start;
149 if (sym_r)
150 ip_r = sym_r->start;
151
152 return (int64_t)(ip_r - ip_l);
153}
154
155static int _hist_entry__dso_snprintf(struct map *map, char *bf,
156 size_t size, unsigned int width)
157{
158 if (map && map->dso) {
159 const char *dso_name = !verbose ? map->dso->short_name :
160 map->dso->long_name;
161 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
123 } 162 }
124 163
125 return strcmp(dso_name_l, dso_name_r); 164 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
126} 165}
127 166
128static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, 167static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
129 size_t size, unsigned int width) 168 size_t size, unsigned int width)
130{ 169{
131 if (self->ms.map && self->ms.map->dso) { 170 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
132 const char *dso_name = !verbose ? self->ms.map->dso->short_name : 171}
133 self->ms.map->dso->long_name; 172
134 return repsep_snprintf(bf, size, "%-*s", width, dso_name); 173static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
174 u64 ip, char level, char *bf, size_t size,
175 unsigned int width __used)
176{
177 size_t ret = 0;
178
179 if (verbose) {
180 char o = map ? dso__symtab_origin(map->dso) : '!';
181 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
182 BITS_PER_LONG / 4, ip, o);
135 } 183 }
136 184
137 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); 185 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
186 if (sym)
187 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
188 width - ret,
189 sym->name);
190 else {
191 size_t len = BITS_PER_LONG / 4;
192 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
193 len, ip);
194 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
195 width - ret, "");
196 }
197
198 return ret;
138} 199}
139 200
201
140struct sort_entry sort_dso = { 202struct sort_entry sort_dso = {
141 .se_header = "Shared Object", 203 .se_header = "Shared Object",
142 .se_cmp = sort__dso_cmp, 204 .se_cmp = sort__dso_cmp,
@@ -144,8 +206,14 @@ struct sort_entry sort_dso = {
144 .se_width_idx = HISTC_DSO, 206 .se_width_idx = HISTC_DSO,
145}; 207};
146 208
147/* --sort symbol */ 209static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
210 size_t size, unsigned int width __used)
211{
212 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
213 self->level, bf, size, width);
214}
148 215
216/* --sort symbol */
149static int64_t 217static int64_t
150sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 218sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
151{ 219{
@@ -163,31 +231,7 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
163 ip_l = left->ms.sym->start; 231 ip_l = left->ms.sym->start;
164 ip_r = right->ms.sym->start; 232 ip_r = right->ms.sym->start;
165 233
166 return (int64_t)(ip_r - ip_l); 234 return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
167}
168
169static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
170 size_t size, unsigned int width __used)
171{
172 size_t ret = 0;
173
174 if (verbose) {
175 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
176 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
177 BITS_PER_LONG / 4, self->ip, o);
178 }
179
180 if (!sort_dso.elide)
181 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
182
183 if (self->ms.sym)
184 ret += repsep_snprintf(bf + ret, size - ret, "%s",
185 self->ms.sym->name);
186 else
187 ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
188 BITS_PER_LONG / 4, self->ip);
189
190 return ret;
191} 235}
192 236
193struct sort_entry sort_sym = { 237struct sort_entry sort_sym = {
@@ -246,19 +290,155 @@ struct sort_entry sort_cpu = {
246 .se_width_idx = HISTC_CPU, 290 .se_width_idx = HISTC_CPU,
247}; 291};
248 292
293static int64_t
294sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
295{
296 return _sort__dso_cmp(left->branch_info->from.map,
297 right->branch_info->from.map);
298}
299
300static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
301 size_t size, unsigned int width)
302{
303 return _hist_entry__dso_snprintf(self->branch_info->from.map,
304 bf, size, width);
305}
306
307struct sort_entry sort_dso_from = {
308 .se_header = "Source Shared Object",
309 .se_cmp = sort__dso_from_cmp,
310 .se_snprintf = hist_entry__dso_from_snprintf,
311 .se_width_idx = HISTC_DSO_FROM,
312};
313
314static int64_t
315sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
316{
317 return _sort__dso_cmp(left->branch_info->to.map,
318 right->branch_info->to.map);
319}
320
321static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf,
322 size_t size, unsigned int width)
323{
324 return _hist_entry__dso_snprintf(self->branch_info->to.map,
325 bf, size, width);
326}
327
328static int64_t
329sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
330{
331 struct addr_map_symbol *from_l = &left->branch_info->from;
332 struct addr_map_symbol *from_r = &right->branch_info->from;
333
334 if (!from_l->sym && !from_r->sym)
335 return right->level - left->level;
336
337 return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr,
338 from_r->addr);
339}
340
341static int64_t
342sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
343{
344 struct addr_map_symbol *to_l = &left->branch_info->to;
345 struct addr_map_symbol *to_r = &right->branch_info->to;
346
347 if (!to_l->sym && !to_r->sym)
348 return right->level - left->level;
349
350 return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr);
351}
352
353static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
354 size_t size, unsigned int width __used)
355{
356 struct addr_map_symbol *from = &self->branch_info->from;
357 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
358 self->level, bf, size, width);
359
360}
361
362static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
363 size_t size, unsigned int width __used)
364{
365 struct addr_map_symbol *to = &self->branch_info->to;
366 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
367 self->level, bf, size, width);
368
369}
370
371struct sort_entry sort_dso_to = {
372 .se_header = "Target Shared Object",
373 .se_cmp = sort__dso_to_cmp,
374 .se_snprintf = hist_entry__dso_to_snprintf,
375 .se_width_idx = HISTC_DSO_TO,
376};
377
378struct sort_entry sort_sym_from = {
379 .se_header = "Source Symbol",
380 .se_cmp = sort__sym_from_cmp,
381 .se_snprintf = hist_entry__sym_from_snprintf,
382 .se_width_idx = HISTC_SYMBOL_FROM,
383};
384
385struct sort_entry sort_sym_to = {
386 .se_header = "Target Symbol",
387 .se_cmp = sort__sym_to_cmp,
388 .se_snprintf = hist_entry__sym_to_snprintf,
389 .se_width_idx = HISTC_SYMBOL_TO,
390};
391
392static int64_t
393sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
394{
395 const unsigned char mp = left->branch_info->flags.mispred !=
396 right->branch_info->flags.mispred;
397 const unsigned char p = left->branch_info->flags.predicted !=
398 right->branch_info->flags.predicted;
399
400 return mp || p;
401}
402
403static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
404 size_t size, unsigned int width){
405 static const char *out = "N/A";
406
407 if (self->branch_info->flags.predicted)
408 out = "N";
409 else if (self->branch_info->flags.mispred)
410 out = "Y";
411
412 return repsep_snprintf(bf, size, "%-*s", width, out);
413}
414
415struct sort_entry sort_mispredict = {
416 .se_header = "Branch Mispredicted",
417 .se_cmp = sort__mispredict_cmp,
418 .se_snprintf = hist_entry__mispredict_snprintf,
419 .se_width_idx = HISTC_MISPREDICT,
420};
421
249struct sort_dimension { 422struct sort_dimension {
250 const char *name; 423 const char *name;
251 struct sort_entry *entry; 424 struct sort_entry *entry;
252 int taken; 425 int taken;
253}; 426};
254 427
428#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
429
255static struct sort_dimension sort_dimensions[] = { 430static struct sort_dimension sort_dimensions[] = {
256 { .name = "pid", .entry = &sort_thread, }, 431 DIM(SORT_PID, "pid", sort_thread),
257 { .name = "comm", .entry = &sort_comm, }, 432 DIM(SORT_COMM, "comm", sort_comm),
258 { .name = "dso", .entry = &sort_dso, }, 433 DIM(SORT_DSO, "dso", sort_dso),
259 { .name = "symbol", .entry = &sort_sym, }, 434 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
260 { .name = "parent", .entry = &sort_parent, }, 435 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
261 { .name = "cpu", .entry = &sort_cpu, }, 436 DIM(SORT_SYM, "symbol", sort_sym),
437 DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
438 DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
439 DIM(SORT_PARENT, "parent", sort_parent),
440 DIM(SORT_CPU, "cpu", sort_cpu),
441 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
262}; 442};
263 443
264int sort_dimension__add(const char *tok) 444int sort_dimension__add(const char *tok)
@@ -270,7 +450,6 @@ int sort_dimension__add(const char *tok)
270 450
271 if (strncasecmp(tok, sd->name, strlen(tok))) 451 if (strncasecmp(tok, sd->name, strlen(tok)))
272 continue; 452 continue;
273
274 if (sd->entry == &sort_parent) { 453 if (sd->entry == &sort_parent) {
275 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 454 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
276 if (ret) { 455 if (ret) {
@@ -302,6 +481,16 @@ int sort_dimension__add(const char *tok)
302 sort__first_dimension = SORT_PARENT; 481 sort__first_dimension = SORT_PARENT;
303 else if (!strcmp(sd->name, "cpu")) 482 else if (!strcmp(sd->name, "cpu"))
304 sort__first_dimension = SORT_CPU; 483 sort__first_dimension = SORT_CPU;
484 else if (!strcmp(sd->name, "symbol_from"))
485 sort__first_dimension = SORT_SYM_FROM;
486 else if (!strcmp(sd->name, "symbol_to"))
487 sort__first_dimension = SORT_SYM_TO;
488 else if (!strcmp(sd->name, "dso_from"))
489 sort__first_dimension = SORT_DSO_FROM;
490 else if (!strcmp(sd->name, "dso_to"))
491 sort__first_dimension = SORT_DSO_TO;
492 else if (!strcmp(sd->name, "mispredict"))
493 sort__first_dimension = SORT_MISPREDICT;
305 } 494 }
306 495
307 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 496 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
@@ -309,7 +498,6 @@ int sort_dimension__add(const char *tok)
309 498
310 return 0; 499 return 0;
311 } 500 }
312
313 return -ESRCH; 501 return -ESRCH;
314} 502}
315 503
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 3f67ae395752..472aa5a63a58 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -31,11 +31,16 @@ extern const char *parent_pattern;
31extern const char default_sort_order[]; 31extern const char default_sort_order[];
32extern int sort__need_collapse; 32extern int sort__need_collapse;
33extern int sort__has_parent; 33extern int sort__has_parent;
34extern int sort__branch_mode;
34extern char *field_sep; 35extern char *field_sep;
35extern struct sort_entry sort_comm; 36extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso; 37extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym; 38extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent; 39extern struct sort_entry sort_parent;
40extern struct sort_entry sort_dso_from;
41extern struct sort_entry sort_dso_to;
42extern struct sort_entry sort_sym_from;
43extern struct sort_entry sort_sym_to;
39extern enum sort_type sort__first_dimension; 44extern enum sort_type sort__first_dimension;
40 45
41/** 46/**
@@ -72,6 +77,7 @@ struct hist_entry {
72 struct hist_entry *pair; 77 struct hist_entry *pair;
73 struct rb_root sorted_chain; 78 struct rb_root sorted_chain;
74 }; 79 };
80 struct branch_info *branch_info;
75 struct callchain_root callchain[0]; 81 struct callchain_root callchain[0];
76}; 82};
77 83
@@ -82,6 +88,11 @@ enum sort_type {
82 SORT_SYM, 88 SORT_SYM,
83 SORT_PARENT, 89 SORT_PARENT,
84 SORT_CPU, 90 SORT_CPU,
91 SORT_DSO_FROM,
92 SORT_DSO_TO,
93 SORT_SYM_FROM,
94 SORT_SYM_TO,
95 SORT_MISPREDICT,
85}; 96};
86 97
87/* 98/*
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 92e068517c1a..2eeb51baf077 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -1,4 +1,5 @@
1#include "cache.h" 1#include "cache.h"
2#include <linux/kernel.h>
2 3
3int prefixcmp(const char *str, const char *prefix) 4int prefixcmp(const char *str, const char *prefix)
4{ 5{
@@ -89,14 +90,14 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
89 if (!strbuf_avail(sb)) 90 if (!strbuf_avail(sb))
90 strbuf_grow(sb, 64); 91 strbuf_grow(sb, 64);
91 va_start(ap, fmt); 92 va_start(ap, fmt);
92 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 93 len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
93 va_end(ap); 94 va_end(ap);
94 if (len < 0) 95 if (len < 0)
95 die("your vsnprintf is broken"); 96 die("your vscnprintf is broken");
96 if (len > strbuf_avail(sb)) { 97 if (len > strbuf_avail(sb)) {
97 strbuf_grow(sb, len); 98 strbuf_grow(sb, len);
98 va_start(ap, fmt); 99 va_start(ap, fmt);
99 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 100 len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
100 va_end(ap); 101 va_end(ap);
101 if (len > strbuf_avail(sb)) { 102 if (len > strbuf_avail(sb)) {
102 die("this should not happen, your snprintf is broken"); 103 die("this should not happen, your snprintf is broken");
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 0975438c3e72..c0a028c3ebaf 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,7 +1,5 @@
1#include <ctype.h>
2#include <dirent.h> 1#include <dirent.h>
3#include <errno.h> 2#include <errno.h>
4#include <libgen.h>
5#include <stdlib.h> 3#include <stdlib.h>
6#include <stdio.h> 4#include <stdio.h>
7#include <string.h> 5#include <string.h>
@@ -12,6 +10,7 @@
12#include <unistd.h> 10#include <unistd.h>
13#include <inttypes.h> 11#include <inttypes.h>
14#include "build-id.h" 12#include "build-id.h"
13#include "util.h"
15#include "debug.h" 14#include "debug.h"
16#include "symbol.h" 15#include "symbol.h"
17#include "strlist.h" 16#include "strlist.h"
@@ -51,6 +50,8 @@ struct symbol_conf symbol_conf = {
51 50
52int dso__name_len(const struct dso *dso) 51int dso__name_len(const struct dso *dso)
53{ 52{
53 if (!dso)
54 return strlen("[unknown]");
54 if (verbose) 55 if (verbose)
55 return dso->long_name_len; 56 return dso->long_name_len;
56 57
@@ -263,6 +264,28 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
263 sym->name); 264 sym->name);
264} 265}
265 266
267size_t symbol__fprintf_symname_offs(const struct symbol *sym,
268 const struct addr_location *al, FILE *fp)
269{
270 unsigned long offset;
271 size_t length;
272
273 if (sym && sym->name) {
274 length = fprintf(fp, "%s", sym->name);
275 if (al) {
276 offset = al->addr - sym->start;
277 length += fprintf(fp, "+0x%lx", offset);
278 }
279 return length;
280 } else
281 return fprintf(fp, "[unknown]");
282}
283
284size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
285{
286 return symbol__fprintf_symname_offs(sym, NULL, fp);
287}
288
266void dso__set_long_name(struct dso *dso, char *name) 289void dso__set_long_name(struct dso *dso, char *name)
267{ 290{
268 if (name == NULL) 291 if (name == NULL)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 123c2e14353e..ac49ef208a5f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -5,6 +5,7 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include <stdint.h> 6#include <stdint.h>
7#include "map.h" 7#include "map.h"
8#include "../perf.h"
8#include <linux/list.h> 9#include <linux/list.h>
9#include <linux/rbtree.h> 10#include <linux/rbtree.h>
10#include <stdio.h> 11#include <stdio.h>
@@ -70,6 +71,7 @@ struct symbol_conf {
70 unsigned short priv_size; 71 unsigned short priv_size;
71 unsigned short nr_events; 72 unsigned short nr_events;
72 bool try_vmlinux_path, 73 bool try_vmlinux_path,
74 show_kernel_path,
73 use_modules, 75 use_modules,
74 sort_by_name, 76 sort_by_name,
75 show_nr_samples, 77 show_nr_samples,
@@ -95,7 +97,11 @@ struct symbol_conf {
95 *col_width_list_str; 97 *col_width_list_str;
96 struct strlist *dso_list, 98 struct strlist *dso_list,
97 *comm_list, 99 *comm_list,
98 *sym_list; 100 *sym_list,
101 *dso_from_list,
102 *dso_to_list,
103 *sym_from_list,
104 *sym_to_list;
99 const char *symfs; 105 const char *symfs;
100}; 106};
101 107
@@ -119,6 +125,19 @@ struct map_symbol {
119 bool has_children; 125 bool has_children;
120}; 126};
121 127
128struct addr_map_symbol {
129 struct map *map;
130 struct symbol *sym;
131 u64 addr;
132 u64 al_addr;
133};
134
135struct branch_info {
136 struct addr_map_symbol from;
137 struct addr_map_symbol to;
138 struct branch_flags flags;
139};
140
122struct addr_location { 141struct addr_location {
123 struct thread *thread; 142 struct thread *thread;
124 struct map *map; 143 struct map *map;
@@ -241,6 +260,9 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);
241 260
242int symbol__init(void); 261int symbol__init(void);
243void symbol__exit(void); 262void symbol__exit(void);
263size_t symbol__fprintf_symname_offs(const struct symbol *sym,
264 const struct addr_location *al, FILE *fp);
265size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
244bool symbol_type__is_a(char symbol_type, enum map_type map_type); 266bool symbol_type__is_a(char symbol_type, enum map_type map_type);
245 267
246size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); 268size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
new file mode 100644
index 000000000000..48c6902e749f
--- /dev/null
+++ b/tools/perf/util/sysfs.c
@@ -0,0 +1,60 @@
1
2#include "util.h"
3#include "sysfs.h"
4
5static const char * const sysfs_known_mountpoints[] = {
6 "/sys",
7 0,
8};
9
10static int sysfs_found;
11char sysfs_mountpoint[PATH_MAX];
12
13static int sysfs_valid_mountpoint(const char *sysfs)
14{
15 struct statfs st_fs;
16
17 if (statfs(sysfs, &st_fs) < 0)
18 return -ENOENT;
19 else if (st_fs.f_type != (long) SYSFS_MAGIC)
20 return -ENOENT;
21
22 return 0;
23}
24
25const char *sysfs_find_mountpoint(void)
26{
27 const char * const *ptr;
28 char type[100];
29 FILE *fp;
30
31 if (sysfs_found)
32 return (const char *) sysfs_mountpoint;
33
34 ptr = sysfs_known_mountpoints;
35 while (*ptr) {
36 if (sysfs_valid_mountpoint(*ptr) == 0) {
37 sysfs_found = 1;
38 strcpy(sysfs_mountpoint, *ptr);
39 return sysfs_mountpoint;
40 }
41 ptr++;
42 }
43
44 /* give up and parse /proc/mounts */
45 fp = fopen("/proc/mounts", "r");
46 if (fp == NULL)
47 return NULL;
48
49 while (!sysfs_found &&
50 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
51 sysfs_mountpoint, type) == 2) {
52
53 if (strcmp(type, "sysfs") == 0)
54 sysfs_found = 1;
55 }
56
57 fclose(fp);
58
59 return sysfs_found ? sysfs_mountpoint : NULL;
60}
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h
new file mode 100644
index 000000000000..a813b7203938
--- /dev/null
+++ b/tools/perf/util/sysfs.h
@@ -0,0 +1,6 @@
1#ifndef __SYSFS_H__
2#define __SYSFS_H__
3
4const char *sysfs_find_mountpoint(void);
5
6#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index a5df131b77c3..84d9bd782004 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -1,6 +1,13 @@
1#include <dirent.h> 1#include <dirent.h>
2#include <limits.h>
3#include <stdbool.h>
2#include <stdlib.h> 4#include <stdlib.h>
3#include <stdio.h> 5#include <stdio.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
9#include "strlist.h"
10#include <string.h>
4#include "thread_map.h" 11#include "thread_map.h"
5 12
6/* Skip "." and ".." directories */ 13/* Skip "." and ".." directories */
@@ -23,7 +30,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
23 sprintf(name, "/proc/%d/task", pid); 30 sprintf(name, "/proc/%d/task", pid);
24 items = scandir(name, &namelist, filter, NULL); 31 items = scandir(name, &namelist, filter, NULL);
25 if (items <= 0) 32 if (items <= 0)
26 return NULL; 33 return NULL;
27 34
28 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); 35 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
29 if (threads != NULL) { 36 if (threads != NULL) {
@@ -51,14 +58,240 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
51 return threads; 58 return threads;
52} 59}
53 60
54struct thread_map *thread_map__new(pid_t pid, pid_t tid) 61struct thread_map *thread_map__new_by_uid(uid_t uid)
62{
63 DIR *proc;
64 int max_threads = 32, items, i;
65 char path[256];
66 struct dirent dirent, *next, **namelist = NULL;
67 struct thread_map *threads = malloc(sizeof(*threads) +
68 max_threads * sizeof(pid_t));
69 if (threads == NULL)
70 goto out;
71
72 proc = opendir("/proc");
73 if (proc == NULL)
74 goto out_free_threads;
75
76 threads->nr = 0;
77
78 while (!readdir_r(proc, &dirent, &next) && next) {
79 char *end;
80 bool grow = false;
81 struct stat st;
82 pid_t pid = strtol(dirent.d_name, &end, 10);
83
84 if (*end) /* only interested in proper numerical dirents */
85 continue;
86
87 snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
88
89 if (stat(path, &st) != 0)
90 continue;
91
92 if (st.st_uid != uid)
93 continue;
94
95 snprintf(path, sizeof(path), "/proc/%d/task", pid);
96 items = scandir(path, &namelist, filter, NULL);
97 if (items <= 0)
98 goto out_free_closedir;
99
100 while (threads->nr + items >= max_threads) {
101 max_threads *= 2;
102 grow = true;
103 }
104
105 if (grow) {
106 struct thread_map *tmp;
107
108 tmp = realloc(threads, (sizeof(*threads) +
109 max_threads * sizeof(pid_t)));
110 if (tmp == NULL)
111 goto out_free_namelist;
112
113 threads = tmp;
114 }
115
116 for (i = 0; i < items; i++)
117 threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
118
119 for (i = 0; i < items; i++)
120 free(namelist[i]);
121 free(namelist);
122
123 threads->nr += items;
124 }
125
126out_closedir:
127 closedir(proc);
128out:
129 return threads;
130
131out_free_threads:
132 free(threads);
133 return NULL;
134
135out_free_namelist:
136 for (i = 0; i < items; i++)
137 free(namelist[i]);
138 free(namelist);
139
140out_free_closedir:
141 free(threads);
142 threads = NULL;
143 goto out_closedir;
144}
145
146struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
55{ 147{
56 if (pid != -1) 148 if (pid != -1)
57 return thread_map__new_by_pid(pid); 149 return thread_map__new_by_pid(pid);
150
151 if (tid == -1 && uid != UINT_MAX)
152 return thread_map__new_by_uid(uid);
153
58 return thread_map__new_by_tid(tid); 154 return thread_map__new_by_tid(tid);
59} 155}
60 156
157static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
158{
159 struct thread_map *threads = NULL, *nt;
160 char name[256];
161 int items, total_tasks = 0;
162 struct dirent **namelist = NULL;
163 int i, j = 0;
164 pid_t pid, prev_pid = INT_MAX;
165 char *end_ptr;
166 struct str_node *pos;
167 struct strlist *slist = strlist__new(false, pid_str);
168
169 if (!slist)
170 return NULL;
171
172 strlist__for_each(pos, slist) {
173 pid = strtol(pos->s, &end_ptr, 10);
174
175 if (pid == INT_MIN || pid == INT_MAX ||
176 (*end_ptr != '\0' && *end_ptr != ','))
177 goto out_free_threads;
178
179 if (pid == prev_pid)
180 continue;
181
182 sprintf(name, "/proc/%d/task", pid);
183 items = scandir(name, &namelist, filter, NULL);
184 if (items <= 0)
185 goto out_free_threads;
186
187 total_tasks += items;
188 nt = realloc(threads, (sizeof(*threads) +
189 sizeof(pid_t) * total_tasks));
190 if (nt == NULL)
191 goto out_free_threads;
192
193 threads = nt;
194
195 if (threads) {
196 for (i = 0; i < items; i++)
197 threads->map[j++] = atoi(namelist[i]->d_name);
198 threads->nr = total_tasks;
199 }
200
201 for (i = 0; i < items; i++)
202 free(namelist[i]);
203 free(namelist);
204
205 if (!threads)
206 break;
207 }
208
209out:
210 strlist__delete(slist);
211 return threads;
212
213out_free_threads:
214 free(threads);
215 threads = NULL;
216 goto out;
217}
218
219static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
220{
221 struct thread_map *threads = NULL, *nt;
222 int ntasks = 0;
223 pid_t tid, prev_tid = INT_MAX;
224 char *end_ptr;
225 struct str_node *pos;
226 struct strlist *slist;
227
228 /* perf-stat expects threads to be generated even if tid not given */
229 if (!tid_str) {
230 threads = malloc(sizeof(*threads) + sizeof(pid_t));
231 if (threads != NULL) {
232 threads->map[0] = -1;
233 threads->nr = 1;
234 }
235 return threads;
236 }
237
238 slist = strlist__new(false, tid_str);
239 if (!slist)
240 return NULL;
241
242 strlist__for_each(pos, slist) {
243 tid = strtol(pos->s, &end_ptr, 10);
244
245 if (tid == INT_MIN || tid == INT_MAX ||
246 (*end_ptr != '\0' && *end_ptr != ','))
247 goto out_free_threads;
248
249 if (tid == prev_tid)
250 continue;
251
252 ntasks++;
253 nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks);
254
255 if (nt == NULL)
256 goto out_free_threads;
257
258 threads = nt;
259 threads->map[ntasks - 1] = tid;
260 threads->nr = ntasks;
261 }
262out:
263 return threads;
264
265out_free_threads:
266 free(threads);
267 threads = NULL;
268 goto out;
269}
270
271struct thread_map *thread_map__new_str(const char *pid, const char *tid,
272 uid_t uid)
273{
274 if (pid)
275 return thread_map__new_by_pid_str(pid);
276
277 if (!tid && uid != UINT_MAX)
278 return thread_map__new_by_uid(uid);
279
280 return thread_map__new_by_tid_str(tid);
281}
282
61void thread_map__delete(struct thread_map *threads) 283void thread_map__delete(struct thread_map *threads)
62{ 284{
63 free(threads); 285 free(threads);
64} 286}
287
288size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
289{
290 int i;
291 size_t printed = fprintf(fp, "%d thread%s: ",
292 threads->nr, threads->nr > 1 ? "s" : "");
293 for (i = 0; i < threads->nr; ++i)
294 printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]);
295
296 return printed + fprintf(fp, "\n");
297}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 3cb907311409..7da80f14418b 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -2,6 +2,7 @@
2#define __PERF_THREAD_MAP_H 2#define __PERF_THREAD_MAP_H
3 3
4#include <sys/types.h> 4#include <sys/types.h>
5#include <stdio.h>
5 6
6struct thread_map { 7struct thread_map {
7 int nr; 8 int nr;
@@ -10,6 +11,14 @@ struct thread_map {
10 11
11struct thread_map *thread_map__new_by_pid(pid_t pid); 12struct thread_map *thread_map__new_by_pid(pid_t pid);
12struct thread_map *thread_map__new_by_tid(pid_t tid); 13struct thread_map *thread_map__new_by_tid(pid_t tid);
13struct thread_map *thread_map__new(pid_t pid, pid_t tid); 14struct thread_map *thread_map__new_by_uid(uid_t uid);
15struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
16
17struct thread_map *thread_map__new_str(const char *pid,
18 const char *tid, uid_t uid);
19
14void thread_map__delete(struct thread_map *threads); 20void thread_map__delete(struct thread_map *threads);
21
22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
23
15#endif /* __PERF_THREAD_MAP_H */ 24#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 500471dffa4f..09fe579ccafb 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -69,12 +69,15 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
69 69
70 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
71 71
72 if (top->target_pid != -1) 72 if (top->target_pid)
73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d", 73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
74 top->target_pid); 74 top->target_pid);
75 else if (top->target_tid != -1) 75 else if (top->target_tid)
76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d", 76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
77 top->target_tid); 77 top->target_tid);
78 else if (top->uid_str != NULL)
79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
80 top->uid_str);
78 else 81 else
79 ret += SNPRINTF(bf + ret, size - ret, " (all"); 82 ret += SNPRINTF(bf + ret, size - ret, " (all");
80 83
@@ -82,7 +85,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
82 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
83 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); 86 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
84 else { 87 else {
85 if (top->target_tid != -1) 88 if (top->target_tid)
86 ret += SNPRINTF(bf + ret, size - ret, ")"); 89 ret += SNPRINTF(bf + ret, size - ret, ")");
87 else 90 else
88 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index a248f3c2c60d..ce61cb2d1acf 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -23,7 +23,8 @@ struct perf_top {
23 u64 guest_us_samples, guest_kernel_samples; 23 u64 guest_us_samples, guest_kernel_samples;
24 int print_entries, count_filter, delay_secs; 24 int print_entries, count_filter, delay_secs;
25 int freq; 25 int freq;
26 pid_t target_pid, target_tid; 26 const char *target_pid, *target_tid;
27 uid_t uid;
27 bool hide_kernel_symbols, hide_user_symbols, zero; 28 bool hide_kernel_symbols, hide_user_symbols, zero;
28 bool system_wide; 29 bool system_wide;
29 bool use_tui, use_stdio; 30 bool use_tui, use_stdio;
@@ -33,7 +34,8 @@ struct perf_top {
33 bool vmlinux_warned; 34 bool vmlinux_warned;
34 bool inherit; 35 bool inherit;
35 bool group; 36 bool group;
36 bool sample_id_all_avail; 37 bool sample_id_all_missing;
38 bool exclude_guest_missing;
37 bool dump_symtab; 39 bool dump_symtab;
38 const char *cpu_list; 40 const char *cpu_list;
39 struct hist_entry *sym_filter_entry; 41 struct hist_entry *sym_filter_entry;
@@ -45,6 +47,7 @@ struct perf_top {
45 int realtime_prio; 47 int realtime_prio;
46 int sym_pcnt_filter; 48 int sym_pcnt_filter;
47 const char *sym_filter; 49 const char *sym_filter;
50 const char *uid_str;
48}; 51};
49 52
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 53size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 1a8d4dc4f386..dfd1bd8371a4 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -25,7 +25,6 @@
25#include <stdio.h> 25#include <stdio.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <string.h> 27#include <string.h>
28#include <ctype.h>
29#include <errno.h> 28#include <errno.h>
30 29
31#include "../perf.h" 30#include "../perf.h"
@@ -723,7 +722,7 @@ static char *event_read_name(void)
723static int event_read_id(void) 722static int event_read_id(void)
724{ 723{
725 char *token; 724 char *token;
726 int id; 725 int id = -1;
727 726
728 if (read_expected_item(EVENT_ITEM, "ID") < 0) 727 if (read_expected_item(EVENT_ITEM, "ID") < 0)
729 return -1; 728 return -1;
@@ -732,15 +731,13 @@ static int event_read_id(void)
732 return -1; 731 return -1;
733 732
734 if (read_expect_type(EVENT_ITEM, &token) < 0) 733 if (read_expect_type(EVENT_ITEM, &token) < 0)
735 goto fail; 734 goto free;
736 735
737 id = strtoul(token, NULL, 0); 736 id = strtoul(token, NULL, 0);
738 free_token(token);
739 return id;
740 737
741 fail: 738 free:
742 free_token(token); 739 free_token(token);
743 return -1; 740 return id;
744} 741}
745 742
746static int field_is_string(struct format_field *field) 743static int field_is_string(struct format_field *field)
@@ -1424,6 +1421,11 @@ static long long arg_num_eval(struct print_arg *arg)
1424 die("unknown op '%s'", arg->op.op); 1421 die("unknown op '%s'", arg->op.op);
1425 } 1422 }
1426 break; 1423 break;
1424 case '+':
1425 left = arg_num_eval(arg->op.left);
1426 right = arg_num_eval(arg->op.right);
1427 val = left + right;
1428 break;
1427 default: 1429 default:
1428 die("unknown op '%s'", arg->op.op); 1430 die("unknown op '%s'", arg->op.op);
1429 } 1431 }
@@ -1484,6 +1486,13 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1484 1486
1485 free_token(token); 1487 free_token(token);
1486 type = process_arg(event, arg, &token); 1488 type = process_arg(event, arg, &token);
1489
1490 if (type == EVENT_OP)
1491 type = process_op(event, arg, &token);
1492
1493 if (type == EVENT_ERROR)
1494 goto out_free;
1495
1487 if (test_type_token(type, token, EVENT_DELIM, ",")) 1496 if (test_type_token(type, token, EVENT_DELIM, ","))
1488 goto out_free; 1497 goto out_free;
1489 1498
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index f55cc3a765a1..b9592e0de8d7 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -33,7 +33,6 @@
33#include <pthread.h> 33#include <pthread.h>
34#include <fcntl.h> 34#include <fcntl.h>
35#include <unistd.h> 35#include <unistd.h>
36#include <ctype.h>
37#include <errno.h> 36#include <errno.h>
38 37
39#include "../perf.h" 38#include "../perf.h"
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index a3fdf55f317b..18ae6c1831d3 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -22,7 +22,6 @@
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <ctype.h>
26#include <errno.h> 25#include <errno.h>
27 26
28#include "../perf.h" 27#include "../perf.h"
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index 84d761b730c1..6ee82f60feaf 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -49,6 +49,8 @@ int ui_browser__warning(struct ui_browser *browser, int timeout,
49 const char *format, ...); 49 const char *format, ...);
50int ui_browser__help_window(struct ui_browser *browser, const char *text); 50int ui_browser__help_window(struct ui_browser *browser, const char *text);
51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); 51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
52int ui_browser__input_window(const char *title, const char *text, char *input,
53 const char *exit_msg, int delay_sec);
52 54
53void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); 55void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
54unsigned int ui_browser__argv_refresh(struct ui_browser *browser); 56unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 295a9c93f945..57a4c6ef3fd2 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -69,14 +69,17 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
69 if (!self->navkeypressed) 69 if (!self->navkeypressed)
70 width += 1; 70 width += 1;
71 71
72 if (!ab->hide_src_code && ol->offset != -1)
73 if (!current_entry || (self->use_navkeypressed &&
74 !self->navkeypressed))
75 ui_browser__set_color(self, HE_COLORSET_CODE);
76
72 if (!*ol->line) 77 if (!*ol->line)
73 slsmg_write_nstring(" ", width - 18); 78 slsmg_write_nstring(" ", width - 18);
74 else 79 else
75 slsmg_write_nstring(ol->line, width - 18); 80 slsmg_write_nstring(ol->line, width - 18);
76 81
77 if (!current_entry) 82 if (current_entry)
78 ui_browser__set_color(self, HE_COLORSET_CODE);
79 else
80 ab->selection = ol; 83 ab->selection = ol;
81} 84}
82 85
@@ -230,9 +233,9 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
230 struct rb_node *nd = NULL; 233 struct rb_node *nd = NULL;
231 struct map_symbol *ms = self->b.priv; 234 struct map_symbol *ms = self->b.priv;
232 struct symbol *sym = ms->sym; 235 struct symbol *sym = ms->sym;
233 const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, " 236 const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
234 "H: Hottest, -> Line action, S -> Toggle source " 237 "H: Go to hottest line, ->/ENTER: Line action, "
235 "code view"; 238 "S: Toggle source code view";
236 int key; 239 int key;
237 240
238 if (ui_browser__show(&self->b, sym->name, help) < 0) 241 if (ui_browser__show(&self->b, sym->name, help) < 0)
@@ -284,9 +287,11 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
284 nd = self->curr_hot; 287 nd = self->curr_hot;
285 break; 288 break;
286 case 'H': 289 case 'H':
290 case 'h':
287 nd = self->curr_hot; 291 nd = self->curr_hot;
288 break; 292 break;
289 case 'S': 293 case 'S':
294 case 's':
290 if (annotate_browser__toggle_source(self)) 295 if (annotate_browser__toggle_source(self))
291 ui_helpline__puts(help); 296 ui_helpline__puts(help);
292 continue; 297 continue;
@@ -338,6 +343,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
338 pthread_mutex_unlock(&notes->lock); 343 pthread_mutex_unlock(&notes->lock);
339 symbol__tui_annotate(target, ms->map, evidx, 344 symbol__tui_annotate(target, ms->map, evidx,
340 timer, arg, delay_secs); 345 timer, arg, delay_secs);
346 ui_browser__show_title(&self->b, sym->name);
341 } 347 }
342 continue; 348 continue;
343 case K_LEFT: 349 case K_LEFT:
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index e81aef1f2569..2f83e5dc9967 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -125,6 +125,9 @@ static int callchain__count_rows(struct rb_root *chain)
125 125
126static bool map_symbol__toggle_fold(struct map_symbol *self) 126static bool map_symbol__toggle_fold(struct map_symbol *self)
127{ 127{
128 if (!self)
129 return false;
130
128 if (!self->has_children) 131 if (!self->has_children)
129 return false; 132 return false;
130 133
@@ -805,8 +808,11 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
805 self->hists = hists; 808 self->hists = hists;
806 self->b.refresh = hist_browser__refresh; 809 self->b.refresh = hist_browser__refresh;
807 self->b.seek = ui_browser__hists_seek; 810 self->b.seek = ui_browser__hists_seek;
808 self->b.use_navkeypressed = true, 811 self->b.use_navkeypressed = true;
809 self->has_symbols = sort_sym.list.next != NULL; 812 if (sort__branch_mode == 1)
813 self->has_symbols = sort_sym_from.list.next != NULL;
814 else
815 self->has_symbols = sort_sym.list.next != NULL;
810 } 816 }
811 817
812 return self; 818 return self;
@@ -837,19 +843,32 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
837 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 843 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
838 844
839 nr_events = convert_unit(nr_events, &unit); 845 nr_events = convert_unit(nr_events, &unit);
840 printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name); 846 printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
841 847
842 if (thread) 848 if (self->uid_filter_str)
843 printed += snprintf(bf + printed, size - printed, 849 printed += snprintf(bf + printed, size - printed,
850 ", UID: %s", self->uid_filter_str);
851 if (thread)
852 printed += scnprintf(bf + printed, size - printed,
844 ", Thread: %s(%d)", 853 ", Thread: %s(%d)",
845 (thread->comm_set ? thread->comm : ""), 854 (thread->comm_set ? thread->comm : ""),
846 thread->pid); 855 thread->pid);
847 if (dso) 856 if (dso)
848 printed += snprintf(bf + printed, size - printed, 857 printed += scnprintf(bf + printed, size - printed,
849 ", DSO: %s", dso->short_name); 858 ", DSO: %s", dso->short_name);
850 return printed; 859 return printed;
851} 860}
852 861
862static inline void free_popup_options(char **options, int n)
863{
864 int i;
865
866 for (i = 0; i < n; ++i) {
867 free(options[i]);
868 options[i] = NULL;
869 }
870}
871
853static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 872static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
854 const char *helpline, const char *ev_name, 873 const char *helpline, const char *ev_name,
855 bool left_exits, 874 bool left_exits,
@@ -858,8 +877,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
858{ 877{
859 struct hists *self = &evsel->hists; 878 struct hists *self = &evsel->hists;
860 struct hist_browser *browser = hist_browser__new(self); 879 struct hist_browser *browser = hist_browser__new(self);
880 struct branch_info *bi;
861 struct pstack *fstack; 881 struct pstack *fstack;
882 char *options[16];
883 int nr_options = 0;
862 int key = -1; 884 int key = -1;
885 char buf[64];
863 886
864 if (browser == NULL) 887 if (browser == NULL)
865 return -1; 888 return -1;
@@ -870,13 +893,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
870 893
871 ui_helpline__push(helpline); 894 ui_helpline__push(helpline);
872 895
896 memset(options, 0, sizeof(options));
897
873 while (1) { 898 while (1) {
874 const struct thread *thread = NULL; 899 const struct thread *thread = NULL;
875 const struct dso *dso = NULL; 900 const struct dso *dso = NULL;
876 char *options[16]; 901 int choice = 0,
877 int nr_options = 0, choice = 0, i,
878 annotate = -2, zoom_dso = -2, zoom_thread = -2, 902 annotate = -2, zoom_dso = -2, zoom_thread = -2,
879 browse_map = -2; 903 annotate_f = -2, annotate_t = -2, browse_map = -2;
904
905 nr_options = 0;
880 906
881 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs); 907 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
882 908
@@ -884,7 +910,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
884 thread = hist_browser__selected_thread(browser); 910 thread = hist_browser__selected_thread(browser);
885 dso = browser->selection->map ? browser->selection->map->dso : NULL; 911 dso = browser->selection->map ? browser->selection->map->dso : NULL;
886 } 912 }
887
888 switch (key) { 913 switch (key) {
889 case K_TAB: 914 case K_TAB:
890 case K_UNTAB: 915 case K_UNTAB:
@@ -899,7 +924,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
899 if (!browser->has_symbols) { 924 if (!browser->has_symbols) {
900 ui_browser__warning(&browser->b, delay_secs * 2, 925 ui_browser__warning(&browser->b, delay_secs * 2,
901 "Annotation is only available for symbolic views, " 926 "Annotation is only available for symbolic views, "
902 "include \"sym\" in --sort to use it."); 927 "include \"sym*\" in --sort to use it.");
903 continue; 928 continue;
904 } 929 }
905 930
@@ -912,6 +937,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
912 goto zoom_dso; 937 goto zoom_dso;
913 case 't': 938 case 't':
914 goto zoom_thread; 939 goto zoom_thread;
940 case 's':
941 if (ui_browser__input_window("Symbol to show",
942 "Please enter the name of symbol you want to see",
943 buf, "ENTER: OK, ESC: Cancel",
944 delay_secs * 2) == K_ENTER) {
945 self->symbol_filter_str = *buf ? buf : NULL;
946 hists__filter_by_symbol(self);
947 hist_browser__reset(browser);
948 }
949 continue;
915 case K_F1: 950 case K_F1:
916 case 'h': 951 case 'h':
917 case '?': 952 case '?':
@@ -929,7 +964,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
929 "C Collapse all callchains\n" 964 "C Collapse all callchains\n"
930 "E Expand all callchains\n" 965 "E Expand all callchains\n"
931 "d Zoom into current DSO\n" 966 "d Zoom into current DSO\n"
932 "t Zoom into current Thread"); 967 "t Zoom into current Thread\n"
968 "s Filter symbol by name");
933 continue; 969 continue;
934 case K_ENTER: 970 case K_ENTER:
935 case K_RIGHT: 971 case K_RIGHT:
@@ -969,12 +1005,34 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
969 if (!browser->has_symbols) 1005 if (!browser->has_symbols)
970 goto add_exit_option; 1006 goto add_exit_option;
971 1007
972 if (browser->selection != NULL && 1008 if (sort__branch_mode == 1) {
973 browser->selection->sym != NULL && 1009 bi = browser->he_selection->branch_info;
974 !browser->selection->map->dso->annotate_warned && 1010 if (browser->selection != NULL &&
975 asprintf(&options[nr_options], "Annotate %s", 1011 bi &&
976 browser->selection->sym->name) > 0) 1012 bi->from.sym != NULL &&
977 annotate = nr_options++; 1013 !bi->from.map->dso->annotate_warned &&
1014 asprintf(&options[nr_options], "Annotate %s",
1015 bi->from.sym->name) > 0)
1016 annotate_f = nr_options++;
1017
1018 if (browser->selection != NULL &&
1019 bi &&
1020 bi->to.sym != NULL &&
1021 !bi->to.map->dso->annotate_warned &&
1022 (bi->to.sym != bi->from.sym ||
1023 bi->to.map->dso != bi->from.map->dso) &&
1024 asprintf(&options[nr_options], "Annotate %s",
1025 bi->to.sym->name) > 0)
1026 annotate_t = nr_options++;
1027 } else {
1028
1029 if (browser->selection != NULL &&
1030 browser->selection->sym != NULL &&
1031 !browser->selection->map->dso->annotate_warned &&
1032 asprintf(&options[nr_options], "Annotate %s",
1033 browser->selection->sym->name) > 0)
1034 annotate = nr_options++;
1035 }
978 1036
979 if (thread != NULL && 1037 if (thread != NULL &&
980 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1038 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
@@ -995,25 +1053,39 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
995 browse_map = nr_options++; 1053 browse_map = nr_options++;
996add_exit_option: 1054add_exit_option:
997 options[nr_options++] = (char *)"Exit"; 1055 options[nr_options++] = (char *)"Exit";
998 1056retry_popup_menu:
999 choice = ui__popup_menu(nr_options, options); 1057 choice = ui__popup_menu(nr_options, options);
1000 1058
1001 for (i = 0; i < nr_options - 1; ++i)
1002 free(options[i]);
1003
1004 if (choice == nr_options - 1) 1059 if (choice == nr_options - 1)
1005 break; 1060 break;
1006 1061
1007 if (choice == -1) 1062 if (choice == -1) {
1063 free_popup_options(options, nr_options - 1);
1008 continue; 1064 continue;
1065 }
1009 1066
1010 if (choice == annotate) { 1067 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
1011 struct hist_entry *he; 1068 struct hist_entry *he;
1012 int err; 1069 int err;
1013do_annotate: 1070do_annotate:
1014 he = hist_browser__selected_entry(browser); 1071 he = hist_browser__selected_entry(browser);
1015 if (he == NULL) 1072 if (he == NULL)
1016 continue; 1073 continue;
1074
1075 /*
1076 * we stash the branch_info symbol + map into the
1077 * the ms so we don't have to rewrite all the annotation
1078 * code to use branch_info.
1079 * in branch mode, the ms struct is not used
1080 */
1081 if (choice == annotate_f) {
1082 he->ms.sym = he->branch_info->from.sym;
1083 he->ms.map = he->branch_info->from.map;
1084 } else if (choice == annotate_t) {
1085 he->ms.sym = he->branch_info->to.sym;
1086 he->ms.map = he->branch_info->to.map;
1087 }
1088
1017 /* 1089 /*
1018 * Don't let this be freed, say, by hists__decay_entry. 1090 * Don't let this be freed, say, by hists__decay_entry.
1019 */ 1091 */
@@ -1021,9 +1093,18 @@ do_annotate:
1021 err = hist_entry__tui_annotate(he, evsel->idx, 1093 err = hist_entry__tui_annotate(he, evsel->idx,
1022 timer, arg, delay_secs); 1094 timer, arg, delay_secs);
1023 he->used = false; 1095 he->used = false;
1096 /*
1097 * offer option to annotate the other branch source or target
1098 * (if they exists) when returning from annotate
1099 */
1100 if ((err == 'q' || err == CTRL('c'))
1101 && annotate_t != -2 && annotate_f != -2)
1102 goto retry_popup_menu;
1103
1024 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1104 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1025 if (err) 1105 if (err)
1026 ui_browser__handle_resize(&browser->b); 1106 ui_browser__handle_resize(&browser->b);
1107
1027 } else if (choice == browse_map) 1108 } else if (choice == browse_map)
1028 map__browse(browser->selection->map); 1109 map__browse(browser->selection->map);
1029 else if (choice == zoom_dso) { 1110 else if (choice == zoom_dso) {
@@ -1069,6 +1150,7 @@ out_free_stack:
1069 pstack__delete(fstack); 1150 pstack__delete(fstack);
1070out: 1151out:
1071 hist_browser__delete(browser); 1152 hist_browser__delete(browser);
1153 free_popup_options(options, nr_options - 1);
1072 return key; 1154 return key;
1073} 1155}
1074 1156
@@ -1095,7 +1177,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1095 HE_COLORSET_NORMAL); 1177 HE_COLORSET_NORMAL);
1096 1178
1097 nr_events = convert_unit(nr_events, &unit); 1179 nr_events = convert_unit(nr_events, &unit);
1098 printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1180 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1099 unit, unit == ' ' ? "" : " ", ev_name); 1181 unit, unit == ' ' ? "" : " ", ev_name);
1100 slsmg_printf("%s", bf); 1182 slsmg_printf("%s", bf);
1101 1183
@@ -1105,8 +1187,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1105 if (!current_entry) 1187 if (!current_entry)
1106 ui_browser__set_color(browser, HE_COLORSET_TOP); 1188 ui_browser__set_color(browser, HE_COLORSET_TOP);
1107 nr_events = convert_unit(nr_events, &unit); 1189 nr_events = convert_unit(nr_events, &unit);
1108 snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events, 1190 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1109 unit, unit == ' ' ? "" : " "); 1191 nr_events, unit, unit == ' ' ? "" : " ");
1110 warn = bf; 1192 warn = bf;
1111 } 1193 }
1112 1194
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index 6905bcc8be2d..eca6575abfd0 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -3,9 +3,9 @@
3#include <newt.h> 3#include <newt.h>
4#include <inttypes.h> 4#include <inttypes.h>
5#include <sys/ttydefaults.h> 5#include <sys/ttydefaults.h>
6#include <ctype.h>
7#include <string.h> 6#include <string.h>
8#include <linux/bitops.h> 7#include <linux/bitops.h>
8#include "../../util.h"
9#include "../../debug.h" 9#include "../../debug.h"
10#include "../../symbol.h" 10#include "../../symbol.h"
11#include "../browser.h" 11#include "../browser.h"
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
index 4f48f5901b30..2f950c2641c8 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/util/ui/helpline.c
@@ -64,7 +64,7 @@ int ui_helpline__show_help(const char *format, va_list ap)
64 static int backlog; 64 static int backlog;
65 65
66 pthread_mutex_lock(&ui__lock); 66 pthread_mutex_lock(&ui__lock);
67 ret = vsnprintf(ui_helpline__last_msg + backlog, 67 ret = vscnprintf(ui_helpline__last_msg + backlog,
68 sizeof(ui_helpline__last_msg) - backlog, format, ap); 68 sizeof(ui_helpline__last_msg) - backlog, format, ap);
69 backlog += ret; 69 backlog += ret;
70 70
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h
index 3458b1985761..809eca5707fa 100644
--- a/tools/perf/util/ui/keysyms.h
+++ b/tools/perf/util/ui/keysyms.h
@@ -16,6 +16,8 @@
16#define K_TAB '\t' 16#define K_TAB '\t'
17#define K_UNTAB SL_KEY_UNTAB 17#define K_UNTAB SL_KEY_UNTAB
18#define K_UP SL_KEY_UP 18#define K_UP SL_KEY_UP
19#define K_BKSPC 0x7f
20#define K_DEL SL_KEY_DELETE
19 21
20/* Not really keys */ 22/* Not really keys */
21#define K_TIMER -1 23#define K_TIMER -1
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index 45daa7c41dad..ad4374a16bb0 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -69,6 +69,88 @@ int ui__popup_menu(int argc, char * const argv[])
69 return popup_menu__run(&menu); 69 return popup_menu__run(&menu);
70} 70}
71 71
72int ui_browser__input_window(const char *title, const char *text, char *input,
73 const char *exit_msg, int delay_secs)
74{
75 int x, y, len, key;
76 int max_len = 60, nr_lines = 0;
77 static char buf[50];
78 const char *t;
79
80 t = text;
81 while (1) {
82 const char *sep = strchr(t, '\n');
83
84 if (sep == NULL)
85 sep = strchr(t, '\0');
86 len = sep - t;
87 if (max_len < len)
88 max_len = len;
89 ++nr_lines;
90 if (*sep == '\0')
91 break;
92 t = sep + 1;
93 }
94
95 max_len += 2;
96 nr_lines += 8;
97 y = SLtt_Screen_Rows / 2 - nr_lines / 2;
98 x = SLtt_Screen_Cols / 2 - max_len / 2;
99
100 SLsmg_set_color(0);
101 SLsmg_draw_box(y, x++, nr_lines, max_len);
102 if (title) {
103 SLsmg_gotorc(y, x + 1);
104 SLsmg_write_string((char *)title);
105 }
106 SLsmg_gotorc(++y, x);
107 nr_lines -= 7;
108 max_len -= 2;
109 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
110 nr_lines, max_len, 1);
111 y += nr_lines;
112 len = 5;
113 while (len--) {
114 SLsmg_gotorc(y + len - 1, x);
115 SLsmg_write_nstring((char *)" ", max_len);
116 }
117 SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
118
119 SLsmg_gotorc(y + 3, x);
120 SLsmg_write_nstring((char *)exit_msg, max_len);
121 SLsmg_refresh();
122
123 x += 2;
124 len = 0;
125 key = ui__getch(delay_secs);
126 while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
127 if (key == K_BKSPC) {
128 if (len == 0)
129 goto next_key;
130 SLsmg_gotorc(y, x + --len);
131 SLsmg_write_char(' ');
132 } else {
133 buf[len] = key;
134 SLsmg_gotorc(y, x + len++);
135 SLsmg_write_char(key);
136 }
137 SLsmg_refresh();
138
139 /* XXX more graceful overflow handling needed */
140 if (len == sizeof(buf) - 1) {
141 ui_helpline__push("maximum size of symbol name reached!");
142 key = K_ENTER;
143 break;
144 }
145next_key:
146 key = ui__getch(delay_secs);
147 }
148
149 buf[len] = '\0';
150 strncpy(input, buf, len+1);
151 return key;
152}
153
72int ui__question_window(const char *title, const char *text, 154int ui__question_window(const char *title, const char *text,
73 const char *exit_msg, int delay_secs) 155 const char *exit_msg, int delay_secs)
74{ 156{
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index d76d1c0ff98f..52bb07c6442a 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -7,6 +7,7 @@
7 * Copyright (C) Linus Torvalds, 2005 7 * Copyright (C) Linus Torvalds, 2005
8 */ 8 */
9#include "util.h" 9#include "util.h"
10#include "debug.h"
10 11
11static void report(const char *prefix, const char *err, va_list params) 12static void report(const char *prefix, const char *err, va_list params)
12{ 13{
@@ -81,3 +82,41 @@ void warning(const char *warn, ...)
81 warn_routine(warn, params); 82 warn_routine(warn, params);
82 va_end(params); 83 va_end(params);
83} 84}
85
86uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
87{
88 struct passwd pwd, *result;
89 char buf[1024];
90
91 if (str == NULL)
92 return UINT_MAX;
93
94 /* UID and PID are mutually exclusive */
95 if (tid || pid) {
96 ui__warning("PID/TID switch overriding UID\n");
97 sleep(1);
98 return UINT_MAX;
99 }
100
101 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
102
103 if (result == NULL) {
104 char *endptr;
105 int uid = strtol(str, &endptr, 10);
106
107 if (*endptr != '\0') {
108 ui__error("Invalid user %s\n", str);
109 return UINT_MAX - 1;
110 }
111
112 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
113
114 if (result == NULL) {
115 ui__error("Problems obtaining information for user %s\n",
116 str);
117 return UINT_MAX - 1;
118 }
119 }
120
121 return result->pw_uid;
122}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 813141047fc2..8109a907841e 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -6,7 +6,7 @@
6 * XXX We need to find a better place for these things... 6 * XXX We need to find a better place for these things...
7 */ 7 */
8bool perf_host = true; 8bool perf_host = true;
9bool perf_guest = true; 9bool perf_guest = false;
10 10
11void event_attr_init(struct perf_event_attr *attr) 11void event_attr_init(struct perf_event_attr *attr)
12{ 12{
@@ -14,6 +14,8 @@ void event_attr_init(struct perf_event_attr *attr)
14 attr->exclude_host = 1; 14 attr->exclude_host = 1;
15 if (!perf_guest) 15 if (!perf_guest)
16 attr->exclude_guest = 1; 16 attr->exclude_guest = 1;
17 /* to capture ABI version */
18 attr->size = sizeof(*attr);
17} 19}
18 20
19int mkdir_p(char *path, mode_t mode) 21int mkdir_p(char *path, mode_t mode)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index ecf9898169c8..0f99f394d8e0 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -199,6 +199,8 @@ static inline int has_extension(const char *filename, const char *ext)
199#undef isalpha 199#undef isalpha
200#undef isprint 200#undef isprint
201#undef isalnum 201#undef isalnum
202#undef islower
203#undef isupper
202#undef tolower 204#undef tolower
203#undef toupper 205#undef toupper
204 206
@@ -219,6 +221,8 @@ extern unsigned char sane_ctype[256];
219#define isalpha(x) sane_istest(x,GIT_ALPHA) 221#define isalpha(x) sane_istest(x,GIT_ALPHA)
220#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 222#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
221#define isprint(x) sane_istest(x,GIT_PRINT) 223#define isprint(x) sane_istest(x,GIT_PRINT)
224#define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20))
225#define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20))
222#define tolower(x) sane_case((unsigned char)(x), 0x20) 226#define tolower(x) sane_case((unsigned char)(x), 0x20)
223#define toupper(x) sane_case((unsigned char)(x), 0) 227#define toupper(x) sane_case((unsigned char)(x), 0)
224 228
@@ -245,6 +249,8 @@ struct perf_event_attr;
245 249
246void event_attr_init(struct perf_event_attr *attr); 250void event_attr_init(struct perf_event_attr *attr);
247 251
252uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
253
248#define _STR(x) #x 254#define _STR(x) #x
249#define STR(x) _STR(x) 255#define STR(x) _STR(x)
250 256