aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-20 13:29:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-20 13:29:15 -0400
commit9c2b957db1772ebf942ae7a9346b14eba6c8ca66 (patch)
tree0dbb83e57260ea7fc0dc421f214d5f1b26262005 /tools
parent0bbfcaff9b2a69c71a95e6902253487ab30cb498 (diff)
parentbea95c152dee1791dd02cbc708afbb115bb00f9a (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf events changes for v3.4 from Ingo Molnar: - New "hardware based branch profiling" feature both on the kernel and the tooling side, on CPUs that support it. (modern x86 Intel CPUs with the 'LBR' hardware feature currently.) This new feature is basically a sophisticated 'magnifying glass' for branch execution - something that is pretty difficult to extract from regular, function histogram centric profiles. The simplest mode is activated via 'perf record -b', and the result looks like this in perf report: $ perf record -b any_call,u -e cycles:u branchy $ perf report -b --sort=symbol 52.34% [.] main [.] f1 24.04% [.] f1 [.] f3 23.60% [.] f1 [.] f2 0.01% [k] _IO_new_file_xsputn [k] _IO_file_overflow 0.01% [k] _IO_vfprintf_internal [k] _IO_new_file_xsputn 0.01% [k] _IO_vfprintf_internal [k] strchrnul 0.01% [k] __printf [k] _IO_vfprintf_internal 0.01% [k] main [k] __printf This output shows from/to branch columns and shows the highest percentage (from,to) jump combinations - i.e. the most likely taken branches in the system. "branches" can also include function calls and any other synchronous and asynchronous transitions of the instruction pointer that are not 'next instruction' - such as system calls, traps, interrupts, etc. This feature comes with (hopefully intuitive) flat ascii and TUI support in perf report. - Various 'perf annotate' visual improvements for us assembly junkies. It will now recognize function calls in the TUI and by hitting enter you can follow the call (recursively) and back, amongst other improvements. - Multiple threads/processes recording support in perf record, perf stat, perf top - which is activated via a comma-list of PIDs: perf top -p 21483,21485 perf stat -p 21483,21485 -ddd perf record -p 21483,21485 - Support for per UID views, via the --uid paramter to perf top, perf report, etc. For example 'perf top --uid mingo' will only show the tasks that I am running, excluding other users, root, etc. - Jump label restructurings and improvements - this includes the factoring out of the (hopefully much clearer) include/linux/static_key.h generic facility: struct static_key key = STATIC_KEY_INIT_FALSE; ... if (static_key_false(&key)) do unlikely code else do likely code ... static_key_slow_inc(); ... static_key_slow_inc(); ... The static_key_false() branch will be generated into the code with as little impact to the likely code path as possible. the static_key_slow_*() APIs flip the branch via live kernel code patching. This facility can now be used more widely within the kernel to micro-optimize hot branches whose likelihood matches the static-key usage and fast/slow cost patterns. - SW function tracer improvements: perf support and filtering support. - Various hardenings of the perf.data ABI, to make older perf.data's smoother on newer tool versions, to make new features integrate more smoothly, to support cross-endian recording/analyzing workflows better, etc. - Restructuring of the kprobes code, the splitting out of 'optprobes', and a corner case bugfix. - Allow the tracing of kernel console output (printk). - Improvements/fixes to user-space RDPMC support, allowing user-space self-profiling code to extract PMU counts without performing any system calls, while playing nice with the kernel side. - 'perf bench' improvements - ... and lots of internal restructurings, cleanups and fixes that made these features possible. And, as usual this list is incomplete as there were also lots of other improvements * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (120 commits) perf report: Fix annotate double quit issue in branch view mode perf report: Remove duplicate annotate choice in branch view mode perf/x86: Prettify pmu config literals perf report: Enable TUI in branch view mode perf report: Auto-detect branch stack sampling mode perf record: Add HEADER_BRANCH_STACK tag perf record: Provide default branch stack sampling mode option perf tools: Make perf able to read files from older ABIs perf tools: Fix ABI compatibility bug in print_event_desc() perf tools: Enable reading of perf.data files from different ABI rev perf: Add ABI reference sizes perf report: Add support for taken branch sampling perf record: Add support for sampling taken branch perf tools: Add code to support PERF_SAMPLE_BRANCH_STACK x86/kprobes: Split out optprobe related code to kprobes-opt.c x86/kprobes: Fix a bug which can modify kernel code permanently x86/kprobes: Fix instruction recovery on optimized path perf: Add callback to flush branch_stack on context switch perf: Disable PERF_SAMPLE_BRANCH_* when not supported perf/x86: Add LBR software filter support for Intel CPUs ...
Diffstat (limited to 'tools')
-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.txt10
-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/Makefile26
-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-lock.c4
-rw-r--r--tools/perf/builtin-probe.c12
-rw-r--r--tools/perf/builtin-record.c152
-rw-r--r--tools/perf/builtin-report.c178
-rw-r--r--tools/perf/builtin-script.c80
-rw-r--r--tools/perf/builtin-stat.c41
-rw-r--r--tools/perf/builtin-test.c188
-rw-r--r--tools/perf/builtin-top.c45
-rw-r--r--tools/perf/perf.h26
-rwxr-xr-xtools/perf/python/twatch.py2
-rw-r--r--tools/perf/util/annotate.c2
-rw-r--r--tools/perf/util/bitmap.c10
-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.c17
-rw-r--r--tools/perf/util/evlist.h9
-rw-r--r--tools/perf/util/evsel.c22
-rw-r--r--tools/perf/util/header.c588
-rw-r--r--tools/perf/util/header.h3
-rw-r--r--tools/perf/util/hist.c122
-rw-r--r--tools/perf/util/hist.h13
-rw-r--r--tools/perf/util/include/asm/dwarf2.h4
-rw-r--r--tools/perf/util/include/linux/bitmap.h11
-rw-r--r--tools/perf/util/map.c15
-rw-r--r--tools/perf/util/map.h1
-rw-r--r--tools/perf/util/probe-event.c33
-rw-r--r--tools/perf/util/probe-finder.c1
-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.c126
-rw-r--r--tools/perf/util/session.h6
-rw-r--r--tools/perf/util/setup.py8
-rw-r--r--tools/perf/util/sort.c287
-rw-r--r--tools/perf/util/sort.h11
-rw-r--r--tools/perf/util/symbol.c24
-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.h6
-rw-r--r--tools/perf/util/trace-event-parse.c13
-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/browsers/annotate.c18
-rw-r--r--tools/perf/util/ui/browsers/hists.c105
-rw-r--r--tools/perf/util/ui/browsers/map.c2
-rw-r--r--tools/perf/util/usage.c39
-rw-r--r--tools/perf/util/util.c2
-rw-r--r--tools/perf/util/util.h6
74 files changed, 2632 insertions, 710 deletions
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..87feeee8b90c 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -153,6 +153,16 @@ OPTIONS
153 information which may be very large and thus may clutter the display. 153 information which may be very large and thus may clutter the display.
154 It currently includes: cpu and numa topology of the host system. 154 It currently includes: cpu and numa topology of the host system.
155 155
156-b::
157--branch-stack::
158 Use the addresses of sampled taken branches instead of the instruction
159 address to build the histograms. To generate meaningful output, the
160 perf.data file must have been obtained using perf record -b or
161 perf record --branch-filter xxx where xxx is a branch filter option.
162 perf report is able to auto-detect whether a perf.data file contains
163 branch stacks and it will automatically switch to the branch view mode,
164 unless --no-branch-stack is used.
165
156SEE ALSO 166SEE ALSO
157-------- 167--------
158linkperf:perf-stat[1], linkperf:perf-annotate[1] 168linkperf: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 8a4b9bccf8b2..74fd7f89208a 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
@@ -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 && \
@@ -258,6 +275,7 @@ LIB_H += util/callchain.h
258LIB_H += util/build-id.h 275LIB_H += util/build-id.h
259LIB_H += util/debug.h 276LIB_H += util/debug.h
260LIB_H += util/debugfs.h 277LIB_H += util/debugfs.h
278LIB_H += util/sysfs.h
261LIB_H += util/event.h 279LIB_H += util/event.h
262LIB_H += util/evsel.h 280LIB_H += util/evsel.h
263LIB_H += util/evlist.h 281LIB_H += util/evlist.h
@@ -304,6 +322,7 @@ LIB_OBJS += $(OUTPUT)util/build-id.o
304LIB_OBJS += $(OUTPUT)util/config.o 322LIB_OBJS += $(OUTPUT)util/config.o
305LIB_OBJS += $(OUTPUT)util/ctype.o 323LIB_OBJS += $(OUTPUT)util/ctype.o
306LIB_OBJS += $(OUTPUT)util/debugfs.o 324LIB_OBJS += $(OUTPUT)util/debugfs.o
325LIB_OBJS += $(OUTPUT)util/sysfs.o
307LIB_OBJS += $(OUTPUT)util/environment.o 326LIB_OBJS += $(OUTPUT)util/environment.o
308LIB_OBJS += $(OUTPUT)util/event.o 327LIB_OBJS += $(OUTPUT)util/event.o
309LIB_OBJS += $(OUTPUT)util/evlist.o 328LIB_OBJS += $(OUTPUT)util/evlist.o
@@ -361,8 +380,10 @@ BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
361BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o 380BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
362ifeq ($(RAW_ARCH),x86_64) 381ifeq ($(RAW_ARCH),x86_64)
363BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o 382BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
383BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
364endif 384endif
365BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o 385BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
386BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
366 387
367BUILTIN_OBJS += $(OUTPUT)builtin-diff.o 388BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
368BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o 389BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
@@ -794,7 +815,6 @@ help:
794 @echo ' quick-install-html - install the html documentation quickly' 815 @echo ' quick-install-html - install the html documentation quickly'
795 @echo '' 816 @echo ''
796 @echo 'Perf maintainer targets:' 817 @echo 'Perf maintainer targets:'
797 @echo ' distclean - alias to clean'
798 @echo ' clean - clean all binary objects and build output' 818 @echo ' clean - clean all binary objects and build output'
799 819
800doc: 820doc:
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-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 227b6ae99785..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;
@@ -208,7 +209,7 @@ fallback_missing_features:
208 if (opts->exclude_guest_missing) 209 if (opts->exclude_guest_missing)
209 attr->exclude_guest = attr->exclude_host = 0; 210 attr->exclude_guest = attr->exclude_host = 0;
210retry_sample_id: 211retry_sample_id:
211 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; 212 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
212try_again: 213try_again:
213 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, 214 if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
214 opts->group, group_fd) < 0) { 215 opts->group, group_fd) < 0) {
@@ -227,11 +228,11 @@ try_again:
227 "guest or host samples.\n"); 228 "guest or host samples.\n");
228 opts->exclude_guest_missing = true; 229 opts->exclude_guest_missing = true;
229 goto fallback_missing_features; 230 goto fallback_missing_features;
230 } else if (opts->sample_id_all_avail) { 231 } else if (!opts->sample_id_all_missing) {
231 /* 232 /*
232 * Old kernel, no attr->sample_id_type_all field 233 * Old kernel, no attr->sample_id_type_all field
233 */ 234 */
234 opts->sample_id_all_avail = false; 235 opts->sample_id_all_missing = true;
235 if (!opts->sample_time && !opts->raw_samples && !time_needed) 236 if (!opts->sample_time && !opts->raw_samples && !time_needed)
236 attr->sample_type &= ~PERF_SAMPLE_TIME; 237 attr->sample_type &= ~PERF_SAMPLE_TIME;
237 238
@@ -396,7 +397,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
396{ 397{
397 struct stat st; 398 struct stat st;
398 int flags; 399 int flags;
399 int err, output; 400 int err, output, feat;
400 unsigned long waking = 0; 401 unsigned long waking = 0;
401 const bool forks = argc > 0; 402 const bool forks = argc > 0;
402 struct machine *machine; 403 struct machine *machine;
@@ -463,8 +464,17 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
463 464
464 rec->session = session; 465 rec->session = session;
465 466
466 if (!rec->no_buildid) 467 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
467 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);
468 478
469 if (!rec->file_new) { 479 if (!rec->file_new) {
470 err = perf_session__read_header(session, output); 480 err = perf_session__read_header(session, output);
@@ -472,22 +482,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
472 goto out_delete_session; 482 goto out_delete_session;
473 } 483 }
474 484
475 if (have_tracepoints(&evsel_list->entries))
476 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
477
478 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
479 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
480 perf_header__set_feat(&session->header, HEADER_ARCH);
481 perf_header__set_feat(&session->header, HEADER_CPUDESC);
482 perf_header__set_feat(&session->header, HEADER_NRCPUS);
483 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
484 perf_header__set_feat(&session->header, HEADER_CMDLINE);
485 perf_header__set_feat(&session->header, HEADER_VERSION);
486 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
487 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
488 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
489 perf_header__set_feat(&session->header, HEADER_CPUID);
490
491 if (forks) { 485 if (forks) {
492 err = perf_evlist__prepare_workload(evsel_list, opts, argv); 486 err = perf_evlist__prepare_workload(evsel_list, opts, argv);
493 if (err < 0) { 487 if (err < 0) {
@@ -647,6 +641,90 @@ out_delete_session:
647 return err; 641 return err;
648} 642}
649 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
650static const char * const record_usage[] = { 728static const char * const record_usage[] = {
651 "perf record [<options>] [<command>]", 729 "perf record [<options>] [<command>]",
652 "perf record [<options>] -- <command> [<options>]", 730 "perf record [<options>] -- <command> [<options>]",
@@ -665,13 +743,10 @@ static const char * const record_usage[] = {
665 */ 743 */
666static struct perf_record record = { 744static struct perf_record record = {
667 .opts = { 745 .opts = {
668 .target_pid = -1,
669 .target_tid = -1,
670 .mmap_pages = UINT_MAX, 746 .mmap_pages = UINT_MAX,
671 .user_freq = UINT_MAX, 747 .user_freq = UINT_MAX,
672 .user_interval = ULLONG_MAX, 748 .user_interval = ULLONG_MAX,
673 .freq = 1000, 749 .freq = 1000,
674 .sample_id_all_avail = true,
675 }, 750 },
676 .write_mode = WRITE_FORCE, 751 .write_mode = WRITE_FORCE,
677 .file_new = true, 752 .file_new = true,
@@ -690,9 +765,9 @@ const struct option record_options[] = {
690 parse_events_option), 765 parse_events_option),
691 OPT_CALLBACK(0, "filter", &record.evlist, "filter", 766 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
692 "event filter", parse_filter), 767 "event filter", parse_filter),
693 OPT_INTEGER('p', "pid", &record.opts.target_pid, 768 OPT_STRING('p', "pid", &record.opts.target_pid, "pid",
694 "record events on existing process id"), 769 "record events on existing process id"),
695 OPT_INTEGER('t', "tid", &record.opts.target_tid, 770 OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
696 "record events on existing thread id"), 771 "record events on existing thread id"),
697 OPT_INTEGER('r', "realtime", &record.realtime_prio, 772 OPT_INTEGER('r', "realtime", &record.realtime_prio,
698 "collect data with this RT SCHED_FIFO priority"), 773 "collect data with this RT SCHED_FIFO priority"),
@@ -738,6 +813,15 @@ const struct option record_options[] = {
738 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 813 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
739 "monitor event in cgroup name only", 814 "monitor event in cgroup name only",
740 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),
741 OPT_END() 825 OPT_END()
742}; 826};
743 827
@@ -758,8 +842,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
758 842
759 argc = parse_options(argc, argv, record_options, record_usage, 843 argc = parse_options(argc, argv, record_options, record_usage,
760 PARSE_OPT_STOP_AT_NON_OPTION); 844 PARSE_OPT_STOP_AT_NON_OPTION);
761 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 && 845 if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
762 !rec->opts.system_wide && !rec->opts.cpu_list) 846 !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
763 usage_with_options(record_usage, record_options); 847 usage_with_options(record_usage, record_options);
764 848
765 if (rec->force && rec->append_file) { 849 if (rec->force && rec->append_file) {
@@ -799,11 +883,17 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
799 goto out_symbol_exit; 883 goto out_symbol_exit;
800 } 884 }
801 885
802 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)
803 rec->opts.target_tid = rec->opts.target_pid; 892 rec->opts.target_tid = rec->opts.target_pid;
804 893
805 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, 894 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
806 rec->opts.target_tid, rec->opts.cpu_list) < 0) 895 rec->opts.target_tid, rec->opts.uid,
896 rec->opts.cpu_list) < 0)
807 usage_with_options(record_usage, record_options); 897 usage_with_options(record_usage, record_options);
808 898
809 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..8e91c6eba18a 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -53,6 +53,82 @@ struct perf_report {
53 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 53 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
54}; 54};
55 55
56static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
57 struct addr_location *al,
58 struct perf_sample *sample,
59 struct perf_evsel *evsel,
60 struct machine *machine)
61{
62 struct perf_report *rep = container_of(tool, struct perf_report, tool);
63 struct symbol *parent = NULL;
64 int err = 0;
65 unsigned i;
66 struct hist_entry *he;
67 struct branch_info *bi, *bx;
68
69 if ((sort__has_parent || symbol_conf.use_callchain)
70 && sample->callchain) {
71 err = machine__resolve_callchain(machine, evsel, al->thread,
72 sample->callchain, &parent);
73 if (err)
74 return err;
75 }
76
77 bi = machine__resolve_bstack(machine, al->thread,
78 sample->branch_stack);
79 if (!bi)
80 return -ENOMEM;
81
82 for (i = 0; i < sample->branch_stack->nr; i++) {
83 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
84 continue;
85 /*
86 * The report shows the percentage of total branches captured
87 * and not events sampled. Thus we use a pseudo period of 1.
88 */
89 he = __hists__add_branch_entry(&evsel->hists, al, parent,
90 &bi[i], 1);
91 if (he) {
92 struct annotation *notes;
93 err = -ENOMEM;
94 bx = he->branch_info;
95 if (bx->from.sym && use_browser > 0) {
96 notes = symbol__annotation(bx->from.sym);
97 if (!notes->src
98 && symbol__alloc_hist(bx->from.sym) < 0)
99 goto out;
100
101 err = symbol__inc_addr_samples(bx->from.sym,
102 bx->from.map,
103 evsel->idx,
104 bx->from.al_addr);
105 if (err)
106 goto out;
107 }
108
109 if (bx->to.sym && use_browser > 0) {
110 notes = symbol__annotation(bx->to.sym);
111 if (!notes->src
112 && symbol__alloc_hist(bx->to.sym) < 0)
113 goto out;
114
115 err = symbol__inc_addr_samples(bx->to.sym,
116 bx->to.map,
117 evsel->idx,
118 bx->to.al_addr);
119 if (err)
120 goto out;
121 }
122 evsel->hists.stats.total_period += 1;
123 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
124 err = 0;
125 } else
126 return -ENOMEM;
127 }
128out:
129 return err;
130}
131
56static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, 132static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
57 struct addr_location *al, 133 struct addr_location *al,
58 struct perf_sample *sample, 134 struct perf_sample *sample,
@@ -126,14 +202,21 @@ static int process_sample_event(struct perf_tool *tool,
126 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 202 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
127 return 0; 203 return 0;
128 204
129 if (al.map != NULL) 205 if (sort__branch_mode == 1) {
130 al.map->dso->hit = 1; 206 if (perf_report__add_branch_hist_entry(tool, &al, sample,
207 evsel, machine)) {
208 pr_debug("problem adding lbr entry, skipping event\n");
209 return -1;
210 }
211 } else {
212 if (al.map != NULL)
213 al.map->dso->hit = 1;
131 214
132 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { 215 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
133 pr_debug("problem incrementing symbol period, skipping event\n"); 216 pr_debug("problem incrementing symbol period, skipping event\n");
134 return -1; 217 return -1;
218 }
135 } 219 }
136
137 return 0; 220 return 0;
138} 221}
139 222
@@ -188,6 +271,15 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
188 } 271 }
189 } 272 }
190 273
274 if (sort__branch_mode == 1) {
275 if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
276 fprintf(stderr, "selected -b but no branch data."
277 " Did you call perf record without"
278 " -b?\n");
279 return -1;
280 }
281 }
282
191 return 0; 283 return 0;
192} 284}
193 285
@@ -246,7 +338,7 @@ static int __cmd_report(struct perf_report *rep)
246{ 338{
247 int ret = -EINVAL; 339 int ret = -EINVAL;
248 u64 nr_samples; 340 u64 nr_samples;
249 struct perf_session *session; 341 struct perf_session *session = rep->session;
250 struct perf_evsel *pos; 342 struct perf_evsel *pos;
251 struct map *kernel_map; 343 struct map *kernel_map;
252 struct kmap *kernel_kmap; 344 struct kmap *kernel_kmap;
@@ -254,13 +346,6 @@ static int __cmd_report(struct perf_report *rep)
254 346
255 signal(SIGINT, sig_handler); 347 signal(SIGINT, sig_handler);
256 348
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) { 349 if (rep->cpu_list) {
265 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 350 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
266 rep->cpu_bitmap); 351 rep->cpu_bitmap);
@@ -427,9 +512,19 @@ setup:
427 return 0; 512 return 0;
428} 513}
429 514
515static int
516parse_branch_mode(const struct option *opt __used, const char *str __used, int unset)
517{
518 sort__branch_mode = !unset;
519 return 0;
520}
521
430int cmd_report(int argc, const char **argv, const char *prefix __used) 522int cmd_report(int argc, const char **argv, const char *prefix __used)
431{ 523{
524 struct perf_session *session;
432 struct stat st; 525 struct stat st;
526 bool has_br_stack = false;
527 int ret = -1;
433 char callchain_default_opt[] = "fractal,0.5,callee"; 528 char callchain_default_opt[] = "fractal,0.5,callee";
434 const char * const report_usage[] = { 529 const char * const report_usage[] = {
435 "perf report [<options>]", 530 "perf report [<options>]",
@@ -477,7 +572,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
477 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 572 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
478 "Use the stdio interface"), 573 "Use the stdio interface"),
479 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 574 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
480 "sort by key(s): pid, comm, dso, symbol, parent"), 575 "sort by key(s): pid, comm, dso, symbol, parent, dso_to,"
576 " dso_from, symbol_to, symbol_from, mispredict"),
481 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 577 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
482 "Show sample percentage for different cpu modes"), 578 "Show sample percentage for different cpu modes"),
483 OPT_STRING('p', "parent", &parent_pattern, "regex", 579 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -517,6 +613,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
517 "Specify disassembler style (e.g. -M intel for intel syntax)"), 613 "Specify disassembler style (e.g. -M intel for intel syntax)"),
518 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 614 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
519 "Show a column with the sum of periods"), 615 "Show a column with the sum of periods"),
616 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
617 "use branch records for histogram filling", parse_branch_mode),
520 OPT_END() 618 OPT_END()
521 }; 619 };
522 620
@@ -536,11 +634,36 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
536 else 634 else
537 report.input_name = "perf.data"; 635 report.input_name = "perf.data";
538 } 636 }
637 session = perf_session__new(report.input_name, O_RDONLY,
638 report.force, false, &report.tool);
639 if (session == NULL)
640 return -ENOMEM;
539 641
540 if (strcmp(report.input_name, "-") != 0) 642 report.session = session;
643
644 has_br_stack = perf_header__has_feat(&session->header,
645 HEADER_BRANCH_STACK);
646
647 if (sort__branch_mode == -1 && has_br_stack)
648 sort__branch_mode = 1;
649
650 /* sort__branch_mode could be 0 if --no-branch-stack */
651 if (sort__branch_mode == 1) {
652 /*
653 * if no sort_order is provided, then specify
654 * branch-mode specific order
655 */
656 if (sort_order == default_sort_order)
657 sort_order = "comm,dso_from,symbol_from,"
658 "dso_to,symbol_to";
659
660 }
661
662 if (strcmp(report.input_name, "-") != 0) {
541 setup_browser(true); 663 setup_browser(true);
542 else 664 } else {
543 use_browser = 0; 665 use_browser = 0;
666 }
544 667
545 /* 668 /*
546 * Only in the newt browser we are doing integrated annotation, 669 * Only in the newt browser we are doing integrated annotation,
@@ -568,13 +691,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
568 } 691 }
569 692
570 if (symbol__init() < 0) 693 if (symbol__init() < 0)
571 return -1; 694 goto error;
572 695
573 setup_sorting(report_usage, options); 696 setup_sorting(report_usage, options);
574 697
575 if (parent_pattern != default_parent_pattern) { 698 if (parent_pattern != default_parent_pattern) {
576 if (sort_dimension__add("parent") < 0) 699 if (sort_dimension__add("parent") < 0)
577 return -1; 700 goto error;
578 701
579 /* 702 /*
580 * Only show the parent fields if we explicitly 703 * Only show the parent fields if we explicitly
@@ -592,9 +715,20 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
592 if (argc) 715 if (argc)
593 usage_with_options(report_usage, options); 716 usage_with_options(report_usage, options);
594 717
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); 718 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 719
599 return __cmd_report(&report); 720 if (sort__branch_mode == 1) {
721 sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
722 sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
723 sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
724 sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
725 } else {
726 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
727 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
728 }
729
730 ret = __cmd_report(&report);
731error:
732 perf_session__delete(session);
733 return ret;
600} 734}
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..ea40e4e8b227 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) {
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..3e087ce8daa6 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -15,6 +15,8 @@
15#include "util/thread_map.h" 15#include "util/thread_map.h"
16#include "../../include/linux/hw_breakpoint.h" 16#include "../../include/linux/hw_breakpoint.h"
17 17
18#include <sys/mman.h>
19
18static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) 20static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
19{ 21{
20 bool *visited = symbol__priv(sym); 22 bool *visited = symbol__priv(sym);
@@ -276,7 +278,7 @@ static int test__open_syscall_event(void)
276 return -1; 278 return -1;
277 } 279 }
278 280
279 threads = thread_map__new(-1, getpid()); 281 threads = thread_map__new(-1, getpid(), UINT_MAX);
280 if (threads == NULL) { 282 if (threads == NULL) {
281 pr_debug("thread_map__new\n"); 283 pr_debug("thread_map__new\n");
282 return -1; 284 return -1;
@@ -342,7 +344,7 @@ static int test__open_syscall_event_on_all_cpus(void)
342 return -1; 344 return -1;
343 } 345 }
344 346
345 threads = thread_map__new(-1, getpid()); 347 threads = thread_map__new(-1, getpid(), UINT_MAX);
346 if (threads == NULL) { 348 if (threads == NULL) {
347 pr_debug("thread_map__new\n"); 349 pr_debug("thread_map__new\n");
348 return -1; 350 return -1;
@@ -490,7 +492,7 @@ static int test__basic_mmap(void)
490 expected_nr_events[i] = random() % 257; 492 expected_nr_events[i] = random() % 257;
491 } 493 }
492 494
493 threads = thread_map__new(-1, getpid()); 495 threads = thread_map__new(-1, getpid(), UINT_MAX);
494 if (threads == NULL) { 496 if (threads == NULL) {
495 pr_debug("thread_map__new\n"); 497 pr_debug("thread_map__new\n");
496 return -1; 498 return -1;
@@ -1008,12 +1010,9 @@ realloc:
1008static int test__PERF_RECORD(void) 1010static int test__PERF_RECORD(void)
1009{ 1011{
1010 struct perf_record_opts opts = { 1012 struct perf_record_opts opts = {
1011 .target_pid = -1,
1012 .target_tid = -1,
1013 .no_delay = true, 1013 .no_delay = true,
1014 .freq = 10, 1014 .freq = 10,
1015 .mmap_pages = 256, 1015 .mmap_pages = 256,
1016 .sample_id_all_avail = true,
1017 }; 1016 };
1018 cpu_set_t *cpu_mask = NULL; 1017 cpu_set_t *cpu_mask = NULL;
1019 size_t cpu_mask_size = 0; 1018 size_t cpu_mask_size = 0;
@@ -1054,7 +1053,7 @@ static int test__PERF_RECORD(void)
1054 * we're monitoring, the one forked there. 1053 * we're monitoring, the one forked there.
1055 */ 1054 */
1056 err = perf_evlist__create_maps(evlist, opts.target_pid, 1055 err = perf_evlist__create_maps(evlist, opts.target_pid,
1057 opts.target_tid, opts.cpu_list); 1056 opts.target_tid, UINT_MAX, opts.cpu_list);
1058 if (err < 0) { 1057 if (err < 0) {
1059 pr_debug("Not enough memory to create thread/cpu maps\n"); 1058 pr_debug("Not enough memory to create thread/cpu maps\n");
1060 goto out_delete_evlist; 1059 goto out_delete_evlist;
@@ -1296,6 +1295,173 @@ out:
1296 return (err < 0 || errs > 0) ? -1 : 0; 1295 return (err < 0 || errs > 0) ? -1 : 0;
1297} 1296}
1298 1297
1298
1299#if defined(__x86_64__) || defined(__i386__)
1300
1301#define barrier() asm volatile("" ::: "memory")
1302
1303static u64 rdpmc(unsigned int counter)
1304{
1305 unsigned int low, high;
1306
1307 asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
1308
1309 return low | ((u64)high) << 32;
1310}
1311
1312static u64 rdtsc(void)
1313{
1314 unsigned int low, high;
1315
1316 asm volatile("rdtsc" : "=a" (low), "=d" (high));
1317
1318 return low | ((u64)high) << 32;
1319}
1320
1321static u64 mmap_read_self(void *addr)
1322{
1323 struct perf_event_mmap_page *pc = addr;
1324 u32 seq, idx, time_mult = 0, time_shift = 0;
1325 u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
1326
1327 do {
1328 seq = pc->lock;
1329 barrier();
1330
1331 enabled = pc->time_enabled;
1332 running = pc->time_running;
1333
1334 if (enabled != running) {
1335 cyc = rdtsc();
1336 time_mult = pc->time_mult;
1337 time_shift = pc->time_shift;
1338 time_offset = pc->time_offset;
1339 }
1340
1341 idx = pc->index;
1342 count = pc->offset;
1343 if (idx)
1344 count += rdpmc(idx - 1);
1345
1346 barrier();
1347 } while (pc->lock != seq);
1348
1349 if (enabled != running) {
1350 u64 quot, rem;
1351
1352 quot = (cyc >> time_shift);
1353 rem = cyc & ((1 << time_shift) - 1);
1354 delta = time_offset + quot * time_mult +
1355 ((rem * time_mult) >> time_shift);
1356
1357 enabled += delta;
1358 if (idx)
1359 running += delta;
1360
1361 quot = count / running;
1362 rem = count % running;
1363 count = quot * enabled + (rem * enabled) / running;
1364 }
1365
1366 return count;
1367}
1368
1369/*
1370 * If the RDPMC instruction faults then signal this back to the test parent task:
1371 */
1372static void segfault_handler(int sig __used, siginfo_t *info __used, void *uc __used)
1373{
1374 exit(-1);
1375}
1376
1377static int __test__rdpmc(void)
1378{
1379 long page_size = sysconf(_SC_PAGE_SIZE);
1380 volatile int tmp = 0;
1381 u64 i, loops = 1000;
1382 int n;
1383 int fd;
1384 void *addr;
1385 struct perf_event_attr attr = {
1386 .type = PERF_TYPE_HARDWARE,
1387 .config = PERF_COUNT_HW_INSTRUCTIONS,
1388 .exclude_kernel = 1,
1389 };
1390 u64 delta_sum = 0;
1391 struct sigaction sa;
1392
1393 sigfillset(&sa.sa_mask);
1394 sa.sa_sigaction = segfault_handler;
1395 sigaction(SIGSEGV, &sa, NULL);
1396
1397 fprintf(stderr, "\n\n");
1398
1399 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
1400 if (fd < 0) {
1401 die("Error: sys_perf_event_open() syscall returned "
1402 "with %d (%s)\n", fd, strerror(errno));
1403 }
1404
1405 addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
1406 if (addr == (void *)(-1)) {
1407 die("Error: mmap() syscall returned "
1408 "with (%s)\n", strerror(errno));
1409 }
1410
1411 for (n = 0; n < 6; n++) {
1412 u64 stamp, now, delta;
1413
1414 stamp = mmap_read_self(addr);
1415
1416 for (i = 0; i < loops; i++)
1417 tmp++;
1418
1419 now = mmap_read_self(addr);
1420 loops *= 10;
1421
1422 delta = now - stamp;
1423 fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta);
1424
1425 delta_sum += delta;
1426 }
1427
1428 munmap(addr, page_size);
1429 close(fd);
1430
1431 fprintf(stderr, " ");
1432
1433 if (!delta_sum)
1434 return -1;
1435
1436 return 0;
1437}
1438
1439static int test__rdpmc(void)
1440{
1441 int status = 0;
1442 int wret = 0;
1443 int ret;
1444 int pid;
1445
1446 pid = fork();
1447 if (pid < 0)
1448 return -1;
1449
1450 if (!pid) {
1451 ret = __test__rdpmc();
1452
1453 exit(ret);
1454 }
1455
1456 wret = waitpid(pid, &status, 0);
1457 if (wret < 0 || status)
1458 return -1;
1459
1460 return 0;
1461}
1462
1463#endif
1464
1299static struct test { 1465static struct test {
1300 const char *desc; 1466 const char *desc;
1301 int (*func)(void); 1467 int (*func)(void);
@@ -1320,6 +1486,12 @@ static struct test {
1320 .desc = "parse events tests", 1486 .desc = "parse events tests",
1321 .func = test__parse_events, 1487 .func = test__parse_events,
1322 }, 1488 },
1489#if defined(__x86_64__) || defined(__i386__)
1490 {
1491 .desc = "x86 rdpmc test",
1492 .func = test__rdpmc,
1493 },
1494#endif
1323 { 1495 {
1324 .desc = "Validate PERF_RECORD_* events & perf_sample fields", 1496 .desc = "Validate PERF_RECORD_* events & perf_sample fields",
1325 .func = test__PERF_RECORD, 1497 .func = test__PERF_RECORD,
@@ -1412,7 +1584,5 @@ int cmd_test(int argc, const char **argv, const char *prefix __used)
1412 if (symbol__init() < 0) 1584 if (symbol__init() < 0)
1413 return -1; 1585 return -1;
1414 1586
1415 setup_pager();
1416
1417 return __cmd_test(argc, argv); 1587 return __cmd_test(argc, argv);
1418} 1588}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ecff31257eb3..e3c63aef8efc 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -64,7 +64,6 @@
64#include <linux/unistd.h> 64#include <linux/unistd.h>
65#include <linux/types.h> 65#include <linux/types.h>
66 66
67
68void get_term_dimensions(struct winsize *ws) 67void get_term_dimensions(struct winsize *ws)
69{ 68{
70 char *s = getenv("LINES"); 69 char *s = getenv("LINES");
@@ -544,10 +543,20 @@ static void perf_top__sort_new_samples(void *arg)
544 543
545static void *display_thread_tui(void *arg) 544static void *display_thread_tui(void *arg)
546{ 545{
546 struct perf_evsel *pos;
547 struct perf_top *top = arg; 547 struct perf_top *top = arg;
548 const char *help = "For a higher level overview, try: perf top --sort comm,dso"; 548 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
549 549
550 perf_top__sort_new_samples(top); 550 perf_top__sort_new_samples(top);
551
552 /*
553 * Initialize the uid_filter_str, in the future the TUI will allow
554 * Zooming in/out UIDs. For now juse use whatever the user passed
555 * via --uid.
556 */
557 list_for_each_entry(pos, &top->evlist->entries, node)
558 pos->hists.uid_filter_str = top->uid_str;
559
551 perf_evlist__tui_browse_hists(top->evlist, help, 560 perf_evlist__tui_browse_hists(top->evlist, help,
552 perf_top__sort_new_samples, 561 perf_top__sort_new_samples,
553 top, top->delay_secs); 562 top, top->delay_secs);
@@ -668,6 +677,12 @@ static void perf_event__process_sample(struct perf_tool *tool,
668 return; 677 return;
669 } 678 }
670 679
680 if (!machine) {
681 pr_err("%u unprocessable samples recorded.",
682 top->session->hists.stats.nr_unprocessable_samples++);
683 return;
684 }
685
671 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 686 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
672 top->exact_samples++; 687 top->exact_samples++;
673 688
@@ -861,7 +876,7 @@ fallback_missing_features:
861 if (top->exclude_guest_missing) 876 if (top->exclude_guest_missing)
862 attr->exclude_guest = attr->exclude_host = 0; 877 attr->exclude_guest = attr->exclude_host = 0;
863retry_sample_id: 878retry_sample_id:
864 attr->sample_id_all = top->sample_id_all_avail ? 1 : 0; 879 attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
865try_again: 880try_again:
866 if (perf_evsel__open(counter, top->evlist->cpus, 881 if (perf_evsel__open(counter, top->evlist->cpus,
867 top->evlist->threads, top->group, 882 top->evlist->threads, top->group,
@@ -878,11 +893,11 @@ try_again:
878 "guest or host samples.\n"); 893 "guest or host samples.\n");
879 top->exclude_guest_missing = true; 894 top->exclude_guest_missing = true;
880 goto fallback_missing_features; 895 goto fallback_missing_features;
881 } else if (top->sample_id_all_avail) { 896 } else if (!top->sample_id_all_missing) {
882 /* 897 /*
883 * Old kernel, no attr->sample_id_type_all field 898 * Old kernel, no attr->sample_id_type_all field
884 */ 899 */
885 top->sample_id_all_avail = false; 900 top->sample_id_all_missing = true;
886 goto retry_sample_id; 901 goto retry_sample_id;
887 } 902 }
888 } 903 }
@@ -967,7 +982,7 @@ static int __cmd_top(struct perf_top *top)
967 if (ret) 982 if (ret)
968 goto out_delete; 983 goto out_delete;
969 984
970 if (top->target_tid != -1) 985 if (top->target_tid || top->uid != UINT_MAX)
971 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 986 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
972 perf_event__process, 987 perf_event__process,
973 &top->session->host_machine); 988 &top->session->host_machine);
@@ -1105,10 +1120,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1105 struct perf_top top = { 1120 struct perf_top top = {
1106 .count_filter = 5, 1121 .count_filter = 5,
1107 .delay_secs = 2, 1122 .delay_secs = 2,
1108 .target_pid = -1, 1123 .uid = UINT_MAX,
1109 .target_tid = -1,
1110 .freq = 1000, /* 1 KHz */ 1124 .freq = 1000, /* 1 KHz */
1111 .sample_id_all_avail = true,
1112 .mmap_pages = 128, 1125 .mmap_pages = 128,
1113 .sym_pcnt_filter = 5, 1126 .sym_pcnt_filter = 5,
1114 }; 1127 };
@@ -1119,9 +1132,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1119 parse_events_option), 1132 parse_events_option),
1120 OPT_INTEGER('c', "count", &top.default_interval, 1133 OPT_INTEGER('c', "count", &top.default_interval,
1121 "event period to sample"), 1134 "event period to sample"),
1122 OPT_INTEGER('p', "pid", &top.target_pid, 1135 OPT_STRING('p', "pid", &top.target_pid, "pid",
1123 "profile events on existing process id"), 1136 "profile events on existing process id"),
1124 OPT_INTEGER('t', "tid", &top.target_tid, 1137 OPT_STRING('t', "tid", &top.target_tid, "tid",
1125 "profile events on existing thread id"), 1138 "profile events on existing thread id"),
1126 OPT_BOOLEAN('a', "all-cpus", &top.system_wide, 1139 OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
1127 "system-wide collection from all CPUs"), 1140 "system-wide collection from all CPUs"),
@@ -1180,6 +1193,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1180 "Display raw encoding of assembly instructions (default)"), 1193 "Display raw encoding of assembly instructions (default)"),
1181 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1194 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1182 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1195 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1196 OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
1183 OPT_END() 1197 OPT_END()
1184 }; 1198 };
1185 1199
@@ -1205,18 +1219,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1205 1219
1206 setup_browser(false); 1220 setup_browser(false);
1207 1221
1222 top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
1223 if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
1224 goto out_delete_evlist;
1225
1208 /* CPU and PID are mutually exclusive */ 1226 /* CPU and PID are mutually exclusive */
1209 if (top.target_tid > 0 && top.cpu_list) { 1227 if (top.target_tid && top.cpu_list) {
1210 printf("WARNING: PID switch overriding CPU\n"); 1228 printf("WARNING: PID switch overriding CPU\n");
1211 sleep(1); 1229 sleep(1);
1212 top.cpu_list = NULL; 1230 top.cpu_list = NULL;
1213 } 1231 }
1214 1232
1215 if (top.target_pid != -1) 1233 if (top.target_pid)
1216 top.target_tid = top.target_pid; 1234 top.target_tid = top.target_pid;
1217 1235
1218 if (perf_evlist__create_maps(top.evlist, top.target_pid, 1236 if (perf_evlist__create_maps(top.evlist, top.target_pid,
1219 top.target_tid, top.cpu_list) < 0) 1237 top.target_tid, top.uid, top.cpu_list) < 0)
1220 usage_with_options(top_usage, options); 1238 usage_with_options(top_usage, options);
1221 1239
1222 if (!top.evlist->nr_entries && 1240 if (!top.evlist->nr_entries &&
@@ -1280,6 +1298,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1280 1298
1281 status = __cmd_top(&top); 1299 status = __cmd_top(&top);
1282 1300
1301out_delete_evlist:
1283 perf_evlist__delete(top.evlist); 1302 perf_evlist__delete(top.evlist);
1284 1303
1285 return status; 1304 return status;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 3afa39ac1d40..89e3355ab173 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -173,7 +173,6 @@ sys_perf_event_open(struct perf_event_attr *attr,
173 pid_t pid, int cpu, int group_fd, 173 pid_t pid, int cpu, int group_fd,
174 unsigned long flags) 174 unsigned long flags)
175{ 175{
176 attr->size = sizeof(*attr);
177 return syscall(__NR_perf_event_open, attr, pid, cpu, 176 return syscall(__NR_perf_event_open, attr, pid, cpu,
178 group_fd, flags); 177 group_fd, flags);
179} 178}
@@ -186,14 +185,32 @@ struct ip_callchain {
186 u64 ips[0]; 185 u64 ips[0];
187}; 186};
188 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
189extern bool perf_host, perf_guest; 205extern bool perf_host, perf_guest;
190extern const char perf_version_string[]; 206extern const char perf_version_string[];
191 207
192void pthread__unblock_sigwinch(void); 208void pthread__unblock_sigwinch(void);
193 209
194struct perf_record_opts { 210struct perf_record_opts {
195 pid_t target_pid; 211 const char *target_pid;
196 pid_t target_tid; 212 const char *target_tid;
213 uid_t uid;
197 bool call_graph; 214 bool call_graph;
198 bool group; 215 bool group;
199 bool inherit_stat; 216 bool inherit_stat;
@@ -204,13 +221,14 @@ struct perf_record_opts {
204 bool raw_samples; 221 bool raw_samples;
205 bool sample_address; 222 bool sample_address;
206 bool sample_time; 223 bool sample_time;
207 bool sample_id_all_avail; 224 bool sample_id_all_missing;
208 bool exclude_guest_missing; 225 bool exclude_guest_missing;
209 bool system_wide; 226 bool system_wide;
210 bool period; 227 bool period;
211 unsigned int freq; 228 unsigned int freq;
212 unsigned int mmap_pages; 229 unsigned int mmap_pages;
213 unsigned int user_freq; 230 unsigned int user_freq;
231 int branch_stack;
214 u64 default_interval; 232 u64 default_interval;
215 u64 user_interval; 233 u64 user_interval;
216 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..e5a462f1d07c 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -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 }
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/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..159263d17c2d 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -97,9 +97,9 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
97 ++evlist->nr_entries; 97 ++evlist->nr_entries;
98} 98}
99 99
100static void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 100void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
101 struct list_head *list, 101 struct list_head *list,
102 int nr_entries) 102 int nr_entries)
103{ 103{
104 list_splice_tail(list, &evlist->entries); 104 list_splice_tail(list, &evlist->entries);
105 evlist->nr_entries += nr_entries; 105 evlist->nr_entries += nr_entries;
@@ -597,15 +597,15 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
597 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 597 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
598} 598}
599 599
600int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, 600int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
601 pid_t target_tid, const char *cpu_list) 601 const char *target_tid, uid_t uid, const char *cpu_list)
602{ 602{
603 evlist->threads = thread_map__new(target_pid, target_tid); 603 evlist->threads = thread_map__new_str(target_pid, target_tid, uid);
604 604
605 if (evlist->threads == NULL) 605 if (evlist->threads == NULL)
606 return -1; 606 return -1;
607 607
608 if (cpu_list == NULL && target_tid != -1) 608 if (uid != UINT_MAX || (cpu_list == NULL && target_tid))
609 evlist->cpus = cpu_map__dummy_new(); 609 evlist->cpus = cpu_map__dummy_new();
610 else 610 else
611 evlist->cpus = cpu_map__new(cpu_list); 611 evlist->cpus = cpu_map__new(cpu_list);
@@ -765,6 +765,7 @@ out_err:
765 list_for_each_entry_reverse(evsel, &evlist->entries, node) 765 list_for_each_entry_reverse(evsel, &evlist->entries, node)
766 perf_evsel__close(evsel, ncpus, nthreads); 766 perf_evsel__close(evsel, ncpus, nthreads);
767 767
768 errno = -err;
768 return err; 769 return err;
769} 770}
770 771
@@ -824,7 +825,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
824 exit(-1); 825 exit(-1);
825 } 826 }
826 827
827 if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) 828 if (!opts->system_wide && !opts->target_tid && !opts->target_pid)
828 evlist->threads->map[0] = evlist->workload.pid; 829 evlist->threads->map[0] = evlist->workload.pid;
829 830
830 close(child_ready_pipe[1]); 831 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..f421f7cbc0d3 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -68,7 +68,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
68 struct perf_event_attr *attr = &evsel->attr; 68 struct perf_event_attr *attr = &evsel->attr;
69 int track = !evsel->idx; /* only the first counter needs these */ 69 int track = !evsel->idx; /* only the first counter needs these */
70 70
71 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; 71 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
72 attr->inherit = !opts->no_inherit; 72 attr->inherit = !opts->no_inherit;
73 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 73 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
74 PERF_FORMAT_TOTAL_TIME_RUNNING | 74 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -111,7 +111,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
111 if (opts->period) 111 if (opts->period)
112 attr->sample_type |= PERF_SAMPLE_PERIOD; 112 attr->sample_type |= PERF_SAMPLE_PERIOD;
113 113
114 if (opts->sample_id_all_avail && 114 if (!opts->sample_id_all_missing &&
115 (opts->sample_time || opts->system_wide || 115 (opts->sample_time || opts->system_wide ||
116 !opts->no_inherit || opts->cpu_list)) 116 !opts->no_inherit || opts->cpu_list))
117 attr->sample_type |= PERF_SAMPLE_TIME; 117 attr->sample_type |= PERF_SAMPLE_TIME;
@@ -126,11 +126,15 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
126 attr->watermark = 0; 126 attr->watermark = 0;
127 attr->wakeup_events = 1; 127 attr->wakeup_events = 1;
128 } 128 }
129 if (opts->branch_stack) {
130 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK;
131 attr->branch_sample_type = opts->branch_stack;
132 }
129 133
130 attr->mmap = track; 134 attr->mmap = track;
131 attr->comm = track; 135 attr->comm = track;
132 136
133 if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) { 137 if (!opts->target_pid && !opts->target_tid && !opts->system_wide) {
134 attr->disabled = 1; 138 attr->disabled = 1;
135 attr->enable_on_exec = 1; 139 attr->enable_on_exec = 1;
136 } 140 }
@@ -536,7 +540,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
536 } 540 }
537 541
538 if (type & PERF_SAMPLE_READ) { 542 if (type & PERF_SAMPLE_READ) {
539 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n"); 543 fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n");
540 return -1; 544 return -1;
541 } 545 }
542 546
@@ -576,6 +580,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
576 data->raw_data = (void *) pdata; 580 data->raw_data = (void *) pdata;
577 } 581 }
578 582
583 if (type & PERF_SAMPLE_BRANCH_STACK) {
584 u64 sz;
585
586 data->branch_stack = (struct branch_stack *)array;
587 array++; /* nr */
588
589 sz = data->branch_stack->nr * sizeof(struct branch_entry);
590 sz /= sizeof(u64);
591 array += sz;
592 }
579 return 0; 593 return 0;
580} 594}
581 595
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 14bb035c5fd9..fcd9cf3ea63e 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;
@@ -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,25 +1169,23 @@ 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;
1166 1178
1167 msz = sizeof(attr); 1179 msz = sizeof(attr);
1168 if (sz < msz) 1180 if (sz < (ssize_t)msz)
1169 msz = sz; 1181 msz = sz;
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 e11e482bd185..3dc99a9b71f5 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -50,21 +50,25 @@ static void hists__reset_col_len(struct hists *hists)
50 hists__set_col_len(hists, col, 0); 50 hists__set_col_len(hists, col, 0);
51} 51}
52 52
53static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
54{
55 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
56
57 if (hists__col_len(hists, dso) < unresolved_col_width &&
58 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
59 !symbol_conf.dso_list)
60 hists__set_col_len(hists, dso, unresolved_col_width);
61}
62
53static void hists__calc_col_len(struct hists *hists, struct hist_entry *h) 63static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
54{ 64{
65 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
55 u16 len; 66 u16 len;
56 67
57 if (h->ms.sym) 68 if (h->ms.sym)
58 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen); 69 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
59 else { 70 else
60 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 71 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 72
69 len = thread__comm_len(h->thread); 73 len = thread__comm_len(h->thread);
70 if (hists__new_col_len(hists, HISTC_COMM, len)) 74 if (hists__new_col_len(hists, HISTC_COMM, len))
@@ -74,6 +78,37 @@ static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
74 len = dso__name_len(h->ms.map->dso); 78 len = dso__name_len(h->ms.map->dso);
75 hists__new_col_len(hists, HISTC_DSO, len); 79 hists__new_col_len(hists, HISTC_DSO, len);
76 } 80 }
81
82 if (h->branch_info) {
83 int symlen;
84 /*
85 * +4 accounts for '[x] ' priv level info
86 * +2 account of 0x prefix on raw addresses
87 */
88 if (h->branch_info->from.sym) {
89 symlen = (int)h->branch_info->from.sym->namelen + 4;
90 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
91
92 symlen = dso__name_len(h->branch_info->from.map->dso);
93 hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
94 } else {
95 symlen = unresolved_col_width + 4 + 2;
96 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
97 hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
98 }
99
100 if (h->branch_info->to.sym) {
101 symlen = (int)h->branch_info->to.sym->namelen + 4;
102 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
103
104 symlen = dso__name_len(h->branch_info->to.map->dso);
105 hists__new_col_len(hists, HISTC_DSO_TO, symlen);
106 } else {
107 symlen = unresolved_col_width + 4 + 2;
108 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
109 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
110 }
111 }
77} 112}
78 113
79static void hist_entry__add_cpumode_period(struct hist_entry *he, 114static void hist_entry__add_cpumode_period(struct hist_entry *he,
@@ -195,26 +230,14 @@ static u8 symbol__parent_filter(const struct symbol *parent)
195 return 0; 230 return 0;
196} 231}
197 232
198struct hist_entry *__hists__add_entry(struct hists *hists, 233static struct hist_entry *add_hist_entry(struct hists *hists,
234 struct hist_entry *entry,
199 struct addr_location *al, 235 struct addr_location *al,
200 struct symbol *sym_parent, u64 period) 236 u64 period)
201{ 237{
202 struct rb_node **p; 238 struct rb_node **p;
203 struct rb_node *parent = NULL; 239 struct rb_node *parent = NULL;
204 struct hist_entry *he; 240 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; 241 int cmp;
219 242
220 pthread_mutex_lock(&hists->lock); 243 pthread_mutex_lock(&hists->lock);
@@ -225,7 +248,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
225 parent = *p; 248 parent = *p;
226 he = rb_entry(parent, struct hist_entry, rb_node_in); 249 he = rb_entry(parent, struct hist_entry, rb_node_in);
227 250
228 cmp = hist_entry__cmp(&entry, he); 251 cmp = hist_entry__cmp(entry, he);
229 252
230 if (!cmp) { 253 if (!cmp) {
231 he->period += period; 254 he->period += period;
@@ -239,7 +262,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
239 p = &(*p)->rb_right; 262 p = &(*p)->rb_right;
240 } 263 }
241 264
242 he = hist_entry__new(&entry); 265 he = hist_entry__new(entry);
243 if (!he) 266 if (!he)
244 goto out_unlock; 267 goto out_unlock;
245 268
@@ -252,6 +275,51 @@ out_unlock:
252 return he; 275 return he;
253} 276}
254 277
278struct hist_entry *__hists__add_branch_entry(struct hists *self,
279 struct addr_location *al,
280 struct symbol *sym_parent,
281 struct branch_info *bi,
282 u64 period)
283{
284 struct hist_entry entry = {
285 .thread = al->thread,
286 .ms = {
287 .map = bi->to.map,
288 .sym = bi->to.sym,
289 },
290 .cpu = al->cpu,
291 .ip = bi->to.addr,
292 .level = al->level,
293 .period = period,
294 .parent = sym_parent,
295 .filtered = symbol__parent_filter(sym_parent),
296 .branch_info = bi,
297 };
298
299 return add_hist_entry(self, &entry, al, period);
300}
301
302struct hist_entry *__hists__add_entry(struct hists *self,
303 struct addr_location *al,
304 struct symbol *sym_parent, u64 period)
305{
306 struct hist_entry entry = {
307 .thread = al->thread,
308 .ms = {
309 .map = al->map,
310 .sym = al->sym,
311 },
312 .cpu = al->cpu,
313 .ip = al->addr,
314 .level = al->level,
315 .period = period,
316 .parent = sym_parent,
317 .filtered = symbol__parent_filter(sym_parent),
318 };
319
320 return add_hist_entry(self, &entry, al, period);
321}
322
255int64_t 323int64_t
256hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 324hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
257{ 325{
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index f55f0a8d1f81..9413f3e31fea 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,7 @@ 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;
58 pthread_mutex_t lock; 65 pthread_mutex_t lock;
59 struct events_stats stats; 66 struct events_stats stats;
60 u64 event_stream; 67 u64 event_stream;
@@ -72,6 +79,12 @@ int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
72 struct hists *hists); 79 struct hists *hists);
73void hist_entry__free(struct hist_entry *); 80void hist_entry__free(struct hist_entry *);
74 81
82struct hist_entry *__hists__add_branch_entry(struct hists *self,
83 struct addr_location *al,
84 struct symbol *sym_parent,
85 struct branch_info *bi,
86 u64 period);
87
75void hists__output_resort(struct hists *self); 88void hists__output_resort(struct hists *self);
76void hists__output_resort_threaded(struct hists *hists); 89void hists__output_resort_threaded(struct hists *hists);
77void hists__collapse_resort(struct hists *self); 90void hists__collapse_resort(struct hists *self);
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/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/map.c b/tools/perf/util/map.c
index 316aa0ab7122..dea6d1c1a954 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -212,6 +212,21 @@ size_t map__fprintf(struct map *self, FILE *fp)
212 self->start, self->end, self->pgoff, self->dso->name); 212 self->start, self->end, self->pgoff, self->dso->name);
213} 213}
214 214
215size_t map__fprintf_dsoname(struct map *map, FILE *fp)
216{
217 const char *dsoname;
218
219 if (map && map->dso && (map->dso->name || map->dso->long_name)) {
220 if (symbol_conf.show_kernel_path && map->dso->long_name)
221 dsoname = map->dso->long_name;
222 else if (map->dso->name)
223 dsoname = map->dso->name;
224 } else
225 dsoname = "[unknown]";
226
227 return fprintf(fp, "%s", dsoname);
228}
229
215/* 230/*
216 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 231 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
217 * map->dso->adjust_symbols==1 for ET_EXEC-like cases. 232 * 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..b100c20b7f94 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -118,6 +118,7 @@ void map__delete(struct map *self);
118struct map *map__clone(struct map *self); 118struct map *map__clone(struct map *self);
119int map__overlap(struct map *l, struct map *r); 119int map__overlap(struct map *l, struct map *r);
120size_t map__fprintf(struct map *self, FILE *fp); 120size_t map__fprintf(struct map *self, FILE *fp);
121size_t map__fprintf_dsoname(struct map *map, FILE *fp);
121 122
122int map__load(struct map *self, symbol_filter_t filter); 123int map__load(struct map *self, symbol_filter_t filter);
123struct symbol *map__find_symbol(struct map *self, 124struct symbol *map__find_symbol(struct map *self,
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..2cc162d3b78c 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>
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..002ebbf59f48 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
@@ -229,6 +229,64 @@ static bool symbol__match_parent_regex(struct symbol *sym)
229 return 0; 229 return 0;
230} 230}
231 231
232static const u8 cpumodes[] = {
233 PERF_RECORD_MISC_USER,
234 PERF_RECORD_MISC_KERNEL,
235 PERF_RECORD_MISC_GUEST_USER,
236 PERF_RECORD_MISC_GUEST_KERNEL
237};
238#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
239
240static void ip__resolve_ams(struct machine *self, struct thread *thread,
241 struct addr_map_symbol *ams,
242 u64 ip)
243{
244 struct addr_location al;
245 size_t i;
246 u8 m;
247
248 memset(&al, 0, sizeof(al));
249
250 for (i = 0; i < NCPUMODES; i++) {
251 m = cpumodes[i];
252 /*
253 * We cannot use the header.misc hint to determine whether a
254 * branch stack address is user, kernel, guest, hypervisor.
255 * Branches may straddle the kernel/user/hypervisor boundaries.
256 * Thus, we have to try consecutively until we find a match
257 * or else, the symbol is unknown
258 */
259 thread__find_addr_location(thread, self, m, MAP__FUNCTION,
260 ip, &al, NULL);
261 if (al.sym)
262 goto found;
263 }
264found:
265 ams->addr = ip;
266 ams->al_addr = al.addr;
267 ams->sym = al.sym;
268 ams->map = al.map;
269}
270
271struct branch_info *machine__resolve_bstack(struct machine *self,
272 struct thread *thr,
273 struct branch_stack *bs)
274{
275 struct branch_info *bi;
276 unsigned int i;
277
278 bi = calloc(bs->nr, sizeof(struct branch_info));
279 if (!bi)
280 return NULL;
281
282 for (i = 0; i < bs->nr; i++) {
283 ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
284 ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
285 bi[i].flags = bs->entries[i].flags;
286 }
287 return bi;
288}
289
232int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, 290int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
233 struct thread *thread, 291 struct thread *thread,
234 struct ip_callchain *chain, 292 struct ip_callchain *chain,
@@ -697,6 +755,18 @@ static void callchain__printf(struct perf_sample *sample)
697 i, sample->callchain->ips[i]); 755 i, sample->callchain->ips[i]);
698} 756}
699 757
758static void branch_stack__printf(struct perf_sample *sample)
759{
760 uint64_t i;
761
762 printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr);
763
764 for (i = 0; i < sample->branch_stack->nr; i++)
765 printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 "\n",
766 i, sample->branch_stack->entries[i].from,
767 sample->branch_stack->entries[i].to);
768}
769
700static void perf_session__print_tstamp(struct perf_session *session, 770static void perf_session__print_tstamp(struct perf_session *session,
701 union perf_event *event, 771 union perf_event *event,
702 struct perf_sample *sample) 772 struct perf_sample *sample)
@@ -744,6 +814,9 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
744 814
745 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) 815 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
746 callchain__printf(sample); 816 callchain__printf(sample);
817
818 if (session->sample_type & PERF_SAMPLE_BRANCH_STACK)
819 branch_stack__printf(sample);
747} 820}
748 821
749static struct machine * 822static struct machine *
@@ -796,6 +869,10 @@ static int perf_session_deliver_event(struct perf_session *session,
796 ++session->hists.stats.nr_unknown_id; 869 ++session->hists.stats.nr_unknown_id;
797 return -1; 870 return -1;
798 } 871 }
872 if (machine == NULL) {
873 ++session->hists.stats.nr_unprocessable_samples;
874 return -1;
875 }
799 return tool->sample(tool, event, sample, evsel, machine); 876 return tool->sample(tool, event, sample, evsel, machine);
800 case PERF_RECORD_MMAP: 877 case PERF_RECORD_MMAP:
801 return tool->mmap(tool, event, sample, machine); 878 return tool->mmap(tool, event, sample, machine);
@@ -964,6 +1041,12 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
964 session->hists.stats.nr_invalid_chains, 1041 session->hists.stats.nr_invalid_chains,
965 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); 1042 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
966 } 1043 }
1044
1045 if (session->hists.stats.nr_unprocessable_samples != 0) {
1046 ui__warning("%u unprocessable samples recorded.\n"
1047 "Do you have a KVM guest running and not using 'perf kvm'?\n",
1048 session->hists.stats.nr_unprocessable_samples);
1049 }
967} 1050}
968 1051
969#define session_done() (*(volatile int *)(&session_done)) 1052#define session_done() (*(volatile int *)(&session_done))
@@ -1293,10 +1376,9 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1293 1376
1294void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, 1377void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1295 struct machine *machine, struct perf_evsel *evsel, 1378 struct machine *machine, struct perf_evsel *evsel,
1296 int print_sym, int print_dso) 1379 int print_sym, int print_dso, int print_symoffset)
1297{ 1380{
1298 struct addr_location al; 1381 struct addr_location al;
1299 const char *symname, *dsoname;
1300 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor; 1382 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
1301 struct callchain_cursor_node *node; 1383 struct callchain_cursor_node *node;
1302 1384
@@ -1324,20 +1406,13 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1324 1406
1325 printf("\t%16" PRIx64, node->ip); 1407 printf("\t%16" PRIx64, node->ip);
1326 if (print_sym) { 1408 if (print_sym) {
1327 if (node->sym && node->sym->name) 1409 printf(" ");
1328 symname = node->sym->name; 1410 symbol__fprintf_symname(node->sym, stdout);
1329 else
1330 symname = "";
1331
1332 printf(" %s", symname);
1333 } 1411 }
1334 if (print_dso) { 1412 if (print_dso) {
1335 if (node->map && node->map->dso && node->map->dso->name) 1413 printf(" (");
1336 dsoname = node->map->dso->name; 1414 map__fprintf_dsoname(al.map, stdout);
1337 else 1415 printf(")");
1338 dsoname = "";
1339
1340 printf(" (%s)", dsoname);
1341 } 1416 }
1342 printf("\n"); 1417 printf("\n");
1343 1418
@@ -1347,21 +1422,18 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1347 } else { 1422 } else {
1348 printf("%16" PRIx64, sample->ip); 1423 printf("%16" PRIx64, sample->ip);
1349 if (print_sym) { 1424 if (print_sym) {
1350 if (al.sym && al.sym->name) 1425 printf(" ");
1351 symname = al.sym->name; 1426 if (print_symoffset)
1427 symbol__fprintf_symname_offs(al.sym, &al,
1428 stdout);
1352 else 1429 else
1353 symname = ""; 1430 symbol__fprintf_symname(al.sym, stdout);
1354
1355 printf(" %s", symname);
1356 } 1431 }
1357 1432
1358 if (print_dso) { 1433 if (print_dso) {
1359 if (al.map && al.map->dso && al.map->dso->name) 1434 printf(" (");
1360 dsoname = al.map->dso->name; 1435 map__fprintf_dsoname(al.map, stdout);
1361 else 1436 printf(")");
1362 dsoname = "";
1363
1364 printf(" (%s)", dsoname);
1365 } 1437 }
1366 } 1438 }
1367} 1439}
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 076c9d4e1ea4..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
@@ -97,6 +98,26 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
97 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 98 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
98} 99}
99 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
100struct sort_entry sort_comm = { 121struct sort_entry sort_comm = {
101 .se_header = "Command", 122 .se_header = "Command",
102 .se_cmp = sort__comm_cmp, 123 .se_cmp = sort__comm_cmp,
@@ -110,36 +131,74 @@ struct sort_entry sort_comm = {
110static int64_t 131static int64_t
111sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
112{ 133{
113 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL; 134 return _sort__dso_cmp(left->ms.map, right->ms.map);
114 struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL; 135}
115 const char *dso_name_l, *dso_name_r;
116 136
117 if (!dso_l || !dso_r)
118 return cmp_null(dso_l, dso_r);
119 137
120 if (verbose) { 138static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
121 dso_name_l = dso_l->long_name; 139 u64 ip_l, u64 ip_r)
122 dso_name_r = dso_r->long_name; 140{
123 } else { 141 if (!sym_l || !sym_r)
124 dso_name_l = dso_l->short_name; 142 return cmp_null(sym_l, sym_r);
125 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);
126 } 162 }
127 163
128 return strcmp(dso_name_l, dso_name_r); 164 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
129} 165}
130 166
131static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, 167static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
132 size_t size, unsigned int width) 168 size_t size, unsigned int width)
133{ 169{
134 if (self->ms.map && self->ms.map->dso) { 170 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
135 const char *dso_name = !verbose ? self->ms.map->dso->short_name : 171}
136 self->ms.map->dso->long_name; 172
137 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);
138 } 183 }
139 184
140 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;
141} 199}
142 200
201
143struct sort_entry sort_dso = { 202struct sort_entry sort_dso = {
144 .se_header = "Shared Object", 203 .se_header = "Shared Object",
145 .se_cmp = sort__dso_cmp, 204 .se_cmp = sort__dso_cmp,
@@ -147,8 +206,14 @@ struct sort_entry sort_dso = {
147 .se_width_idx = HISTC_DSO, 206 .se_width_idx = HISTC_DSO,
148}; 207};
149 208
150/* --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}
151 215
216/* --sort symbol */
152static int64_t 217static int64_t
153sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 218sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
154{ 219{
@@ -166,31 +231,7 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
166 ip_l = left->ms.sym->start; 231 ip_l = left->ms.sym->start;
167 ip_r = right->ms.sym->start; 232 ip_r = right->ms.sym->start;
168 233
169 return (int64_t)(ip_r - ip_l); 234 return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
170}
171
172static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
173 size_t size, unsigned int width __used)
174{
175 size_t ret = 0;
176
177 if (verbose) {
178 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
179 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
180 BITS_PER_LONG / 4, self->ip, o);
181 }
182
183 if (!sort_dso.elide)
184 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
185
186 if (self->ms.sym)
187 ret += repsep_snprintf(bf + ret, size - ret, "%s",
188 self->ms.sym->name);
189 else
190 ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
191 BITS_PER_LONG / 4, self->ip);
192
193 return ret;
194} 235}
195 236
196struct sort_entry sort_sym = { 237struct sort_entry sort_sym = {
@@ -249,19 +290,155 @@ struct sort_entry sort_cpu = {
249 .se_width_idx = HISTC_CPU, 290 .se_width_idx = HISTC_CPU,
250}; 291};
251 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
252struct sort_dimension { 422struct sort_dimension {
253 const char *name; 423 const char *name;
254 struct sort_entry *entry; 424 struct sort_entry *entry;
255 int taken; 425 int taken;
256}; 426};
257 427
428#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
429
258static struct sort_dimension sort_dimensions[] = { 430static struct sort_dimension sort_dimensions[] = {
259 { .name = "pid", .entry = &sort_thread, }, 431 DIM(SORT_PID, "pid", sort_thread),
260 { .name = "comm", .entry = &sort_comm, }, 432 DIM(SORT_COMM, "comm", sort_comm),
261 { .name = "dso", .entry = &sort_dso, }, 433 DIM(SORT_DSO, "dso", sort_dso),
262 { .name = "symbol", .entry = &sort_sym, }, 434 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
263 { .name = "parent", .entry = &sort_parent, }, 435 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
264 { .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),
265}; 442};
266 443
267int sort_dimension__add(const char *tok) 444int sort_dimension__add(const char *tok)
@@ -273,7 +450,6 @@ int sort_dimension__add(const char *tok)
273 450
274 if (strncasecmp(tok, sd->name, strlen(tok))) 451 if (strncasecmp(tok, sd->name, strlen(tok)))
275 continue; 452 continue;
276
277 if (sd->entry == &sort_parent) { 453 if (sd->entry == &sort_parent) {
278 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 454 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
279 if (ret) { 455 if (ret) {
@@ -305,6 +481,16 @@ int sort_dimension__add(const char *tok)
305 sort__first_dimension = SORT_PARENT; 481 sort__first_dimension = SORT_PARENT;
306 else if (!strcmp(sd->name, "cpu")) 482 else if (!strcmp(sd->name, "cpu"))
307 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;
308 } 494 }
309 495
310 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 496 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
@@ -312,7 +498,6 @@ int sort_dimension__add(const char *tok)
312 498
313 return 0; 499 return 0;
314 } 500 }
315
316 return -ESRCH; 501 return -ESRCH;
317} 502}
318 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/symbol.c b/tools/perf/util/symbol.c
index 0975438c3e72..5dd83c3e2c0c 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,4 +1,3 @@
1#include <ctype.h>
2#include <dirent.h> 1#include <dirent.h>
3#include <errno.h> 2#include <errno.h>
4#include <libgen.h> 3#include <libgen.h>
@@ -12,6 +11,7 @@
12#include <unistd.h> 11#include <unistd.h>
13#include <inttypes.h> 12#include <inttypes.h>
14#include "build-id.h" 13#include "build-id.h"
14#include "util.h"
15#include "debug.h" 15#include "debug.h"
16#include "symbol.h" 16#include "symbol.h"
17#include "strlist.h" 17#include "strlist.h"
@@ -263,6 +263,28 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
263 sym->name); 263 sym->name);
264} 264}
265 265
266size_t symbol__fprintf_symname_offs(const struct symbol *sym,
267 const struct addr_location *al, FILE *fp)
268{
269 unsigned long offset;
270 size_t length;
271
272 if (sym && sym->name) {
273 length = fprintf(fp, "%s", sym->name);
274 if (al) {
275 offset = al->addr - sym->start;
276 length += fprintf(fp, "+0x%lx", offset);
277 }
278 return length;
279 } else
280 return fprintf(fp, "[unknown]");
281}
282
283size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
284{
285 return symbol__fprintf_symname_offs(sym, NULL, fp);
286}
287
266void dso__set_long_name(struct dso *dso, char *name) 288void dso__set_long_name(struct dso *dso, char *name)
267{ 289{
268 if (name == NULL) 290 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 f2eab81435ae..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,7 @@ 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;
37 bool exclude_guest_missing; 38 bool exclude_guest_missing;
38 bool dump_symtab; 39 bool dump_symtab;
39 const char *cpu_list; 40 const char *cpu_list;
@@ -46,6 +47,7 @@ struct perf_top {
46 int realtime_prio; 47 int realtime_prio;
47 int sym_pcnt_filter; 48 int sym_pcnt_filter;
48 const char *sym_filter; 49 const char *sym_filter;
50 const char *uid_str;
49}; 51};
50 52
51size_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..a4088ced1e64 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"
@@ -1424,6 +1423,11 @@ static long long arg_num_eval(struct print_arg *arg)
1424 die("unknown op '%s'", arg->op.op); 1423 die("unknown op '%s'", arg->op.op);
1425 } 1424 }
1426 break; 1425 break;
1426 case '+':
1427 left = arg_num_eval(arg->op.left);
1428 right = arg_num_eval(arg->op.right);
1429 val = left + right;
1430 break;
1427 default: 1431 default:
1428 die("unknown op '%s'", arg->op.op); 1432 die("unknown op '%s'", arg->op.op);
1429 } 1433 }
@@ -1484,6 +1488,13 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1484 1488
1485 free_token(token); 1489 free_token(token);
1486 type = process_arg(event, arg, &token); 1490 type = process_arg(event, arg, &token);
1491
1492 if (type == EVENT_OP)
1493 type = process_op(event, arg, &token);
1494
1495 if (type == EVENT_ERROR)
1496 goto out_free;
1497
1487 if (test_type_token(type, token, EVENT_DELIM, ",")) 1498 if (test_type_token(type, token, EVENT_DELIM, ","))
1488 goto out_free; 1499 goto out_free;
1489 1500
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/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 bb9197c9c4a4..fa530fcc764a 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -805,8 +805,11 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
805 self->hists = hists; 805 self->hists = hists;
806 self->b.refresh = hist_browser__refresh; 806 self->b.refresh = hist_browser__refresh;
807 self->b.seek = ui_browser__hists_seek; 807 self->b.seek = ui_browser__hists_seek;
808 self->b.use_navkeypressed = true, 808 self->b.use_navkeypressed = true;
809 self->has_symbols = sort_sym.list.next != NULL; 809 if (sort__branch_mode == 1)
810 self->has_symbols = sort_sym_from.list.next != NULL;
811 else
812 self->has_symbols = sort_sym.list.next != NULL;
810 } 813 }
811 814
812 return self; 815 return self;
@@ -839,6 +842,9 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
839 nr_events = convert_unit(nr_events, &unit); 842 nr_events = convert_unit(nr_events, &unit);
840 printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name); 843 printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
841 844
845 if (self->uid_filter_str)
846 printed += snprintf(bf + printed, size - printed,
847 ", UID: %s", self->uid_filter_str);
842 if (thread) 848 if (thread)
843 printed += scnprintf(bf + printed, size - printed, 849 printed += scnprintf(bf + printed, size - printed,
844 ", Thread: %s(%d)", 850 ", Thread: %s(%d)",
@@ -850,6 +856,16 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
850 return printed; 856 return printed;
851} 857}
852 858
859static inline void free_popup_options(char **options, int n)
860{
861 int i;
862
863 for (i = 0; i < n; ++i) {
864 free(options[i]);
865 options[i] = NULL;
866 }
867}
868
853static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 869static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
854 const char *helpline, const char *ev_name, 870 const char *helpline, const char *ev_name,
855 bool left_exits, 871 bool left_exits,
@@ -858,7 +874,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
858{ 874{
859 struct hists *self = &evsel->hists; 875 struct hists *self = &evsel->hists;
860 struct hist_browser *browser = hist_browser__new(self); 876 struct hist_browser *browser = hist_browser__new(self);
877 struct branch_info *bi;
861 struct pstack *fstack; 878 struct pstack *fstack;
879 char *options[16];
880 int nr_options = 0;
862 int key = -1; 881 int key = -1;
863 882
864 if (browser == NULL) 883 if (browser == NULL)
@@ -870,13 +889,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
870 889
871 ui_helpline__push(helpline); 890 ui_helpline__push(helpline);
872 891
892 memset(options, 0, sizeof(options));
893
873 while (1) { 894 while (1) {
874 const struct thread *thread = NULL; 895 const struct thread *thread = NULL;
875 const struct dso *dso = NULL; 896 const struct dso *dso = NULL;
876 char *options[16]; 897 int choice = 0,
877 int nr_options = 0, choice = 0, i,
878 annotate = -2, zoom_dso = -2, zoom_thread = -2, 898 annotate = -2, zoom_dso = -2, zoom_thread = -2,
879 browse_map = -2; 899 annotate_f = -2, annotate_t = -2, browse_map = -2;
900
901 nr_options = 0;
880 902
881 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs); 903 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
882 904
@@ -884,7 +906,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
884 thread = hist_browser__selected_thread(browser); 906 thread = hist_browser__selected_thread(browser);
885 dso = browser->selection->map ? browser->selection->map->dso : NULL; 907 dso = browser->selection->map ? browser->selection->map->dso : NULL;
886 } 908 }
887
888 switch (key) { 909 switch (key) {
889 case K_TAB: 910 case K_TAB:
890 case K_UNTAB: 911 case K_UNTAB:
@@ -899,7 +920,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
899 if (!browser->has_symbols) { 920 if (!browser->has_symbols) {
900 ui_browser__warning(&browser->b, delay_secs * 2, 921 ui_browser__warning(&browser->b, delay_secs * 2,
901 "Annotation is only available for symbolic views, " 922 "Annotation is only available for symbolic views, "
902 "include \"sym\" in --sort to use it."); 923 "include \"sym*\" in --sort to use it.");
903 continue; 924 continue;
904 } 925 }
905 926
@@ -969,12 +990,34 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
969 if (!browser->has_symbols) 990 if (!browser->has_symbols)
970 goto add_exit_option; 991 goto add_exit_option;
971 992
972 if (browser->selection != NULL && 993 if (sort__branch_mode == 1) {
973 browser->selection->sym != NULL && 994 bi = browser->he_selection->branch_info;
974 !browser->selection->map->dso->annotate_warned && 995 if (browser->selection != NULL &&
975 asprintf(&options[nr_options], "Annotate %s", 996 bi &&
976 browser->selection->sym->name) > 0) 997 bi->from.sym != NULL &&
977 annotate = nr_options++; 998 !bi->from.map->dso->annotate_warned &&
999 asprintf(&options[nr_options], "Annotate %s",
1000 bi->from.sym->name) > 0)
1001 annotate_f = nr_options++;
1002
1003 if (browser->selection != NULL &&
1004 bi &&
1005 bi->to.sym != NULL &&
1006 !bi->to.map->dso->annotate_warned &&
1007 (bi->to.sym != bi->from.sym ||
1008 bi->to.map->dso != bi->from.map->dso) &&
1009 asprintf(&options[nr_options], "Annotate %s",
1010 bi->to.sym->name) > 0)
1011 annotate_t = nr_options++;
1012 } else {
1013
1014 if (browser->selection != NULL &&
1015 browser->selection->sym != NULL &&
1016 !browser->selection->map->dso->annotate_warned &&
1017 asprintf(&options[nr_options], "Annotate %s",
1018 browser->selection->sym->name) > 0)
1019 annotate = nr_options++;
1020 }
978 1021
979 if (thread != NULL && 1022 if (thread != NULL &&
980 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1023 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
@@ -995,25 +1038,39 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
995 browse_map = nr_options++; 1038 browse_map = nr_options++;
996add_exit_option: 1039add_exit_option:
997 options[nr_options++] = (char *)"Exit"; 1040 options[nr_options++] = (char *)"Exit";
998 1041retry_popup_menu:
999 choice = ui__popup_menu(nr_options, options); 1042 choice = ui__popup_menu(nr_options, options);
1000 1043
1001 for (i = 0; i < nr_options - 1; ++i)
1002 free(options[i]);
1003
1004 if (choice == nr_options - 1) 1044 if (choice == nr_options - 1)
1005 break; 1045 break;
1006 1046
1007 if (choice == -1) 1047 if (choice == -1) {
1048 free_popup_options(options, nr_options - 1);
1008 continue; 1049 continue;
1050 }
1009 1051
1010 if (choice == annotate) { 1052 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
1011 struct hist_entry *he; 1053 struct hist_entry *he;
1012 int err; 1054 int err;
1013do_annotate: 1055do_annotate:
1014 he = hist_browser__selected_entry(browser); 1056 he = hist_browser__selected_entry(browser);
1015 if (he == NULL) 1057 if (he == NULL)
1016 continue; 1058 continue;
1059
1060 /*
1061 * we stash the branch_info symbol + map into the
1062 * the ms so we don't have to rewrite all the annotation
1063 * code to use branch_info.
1064 * in branch mode, the ms struct is not used
1065 */
1066 if (choice == annotate_f) {
1067 he->ms.sym = he->branch_info->from.sym;
1068 he->ms.map = he->branch_info->from.map;
1069 } else if (choice == annotate_t) {
1070 he->ms.sym = he->branch_info->to.sym;
1071 he->ms.map = he->branch_info->to.map;
1072 }
1073
1017 /* 1074 /*
1018 * Don't let this be freed, say, by hists__decay_entry. 1075 * Don't let this be freed, say, by hists__decay_entry.
1019 */ 1076 */
@@ -1021,9 +1078,18 @@ do_annotate:
1021 err = hist_entry__tui_annotate(he, evsel->idx, 1078 err = hist_entry__tui_annotate(he, evsel->idx,
1022 timer, arg, delay_secs); 1079 timer, arg, delay_secs);
1023 he->used = false; 1080 he->used = false;
1081 /*
1082 * offer option to annotate the other branch source or target
1083 * (if they exists) when returning from annotate
1084 */
1085 if ((err == 'q' || err == CTRL('c'))
1086 && annotate_t != -2 && annotate_f != -2)
1087 goto retry_popup_menu;
1088
1024 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1089 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1025 if (err) 1090 if (err)
1026 ui_browser__handle_resize(&browser->b); 1091 ui_browser__handle_resize(&browser->b);
1092
1027 } else if (choice == browse_map) 1093 } else if (choice == browse_map)
1028 map__browse(browser->selection->map); 1094 map__browse(browser->selection->map);
1029 else if (choice == zoom_dso) { 1095 else if (choice == zoom_dso) {
@@ -1069,6 +1135,7 @@ out_free_stack:
1069 pstack__delete(fstack); 1135 pstack__delete(fstack);
1070out: 1136out:
1071 hist_browser__delete(browser); 1137 hist_browser__delete(browser);
1138 free_popup_options(options, nr_options - 1);
1072 return key; 1139 return key;
1073} 1140}
1074 1141
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/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 fb25d1329218..8109a907841e 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -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